stackose 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 78e1ae2368a649e93bc733155190ea791acd36ec
4
+ data.tar.gz: d3e0aec71ec3afbcce1b78b4cbe3c2412d25ae87
5
+ SHA512:
6
+ metadata.gz: 0c75721a352ae19820b45e462dbff3c93f17e5f9eba8d79db22245946c222e70728855b428023f16150de96a6e855fba4747b254e3cd824dd3f245c6fe6bd488
7
+ data.tar.gz: c6358e7705080b4e46d16aa8eea19371851a04332e5ac6576155f68b6c059eedca22d8fc50b419301e2e046b4c3641c10b9c5a4be3054683b698f7434471a0f3
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ *.gem
2
+
3
+ \.idea/
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in capistrano.gemspec
4
+ gemspec
5
+
6
+ gem "rspec"
7
+ gem "rspec-core"
8
+ gem "pry"
data/Gemfile.lock ADDED
@@ -0,0 +1,61 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ capose (0.1.0)
5
+ capistrano (>= 3.7)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ airbrussh (1.1.2)
11
+ sshkit (>= 1.6.1, != 1.7.0)
12
+ capistrano (3.7.2)
13
+ airbrussh (>= 1.0.0)
14
+ capistrano-harrow
15
+ i18n
16
+ rake (>= 10.0.0)
17
+ sshkit (>= 1.9.0)
18
+ capistrano-harrow (0.5.3)
19
+ coderay (1.1.1)
20
+ diff-lcs (1.3)
21
+ i18n (0.8.0)
22
+ method_source (0.8.2)
23
+ net-scp (1.2.1)
24
+ net-ssh (>= 2.6.5)
25
+ net-ssh (4.0.1)
26
+ pry (0.10.4)
27
+ coderay (~> 1.1.0)
28
+ method_source (~> 0.8.1)
29
+ slop (~> 3.4)
30
+ rake (12.0.0)
31
+ rspec (3.5.0)
32
+ rspec-core (~> 3.5.0)
33
+ rspec-expectations (~> 3.5.0)
34
+ rspec-mocks (~> 3.5.0)
35
+ rspec-core (3.5.4)
36
+ rspec-support (~> 3.5.0)
37
+ rspec-expectations (3.5.0)
38
+ diff-lcs (>= 1.2.0, < 2.0)
39
+ rspec-support (~> 3.5.0)
40
+ rspec-mocks (3.5.0)
41
+ diff-lcs (>= 1.2.0, < 2.0)
42
+ rspec-support (~> 3.5.0)
43
+ rspec-support (3.5.0)
44
+ slop (3.6.0)
45
+ sshkit (1.11.5)
46
+ net-scp (>= 1.1.2)
47
+ net-ssh (>= 2.8.0)
48
+
49
+ PLATFORMS
50
+ ruby
51
+
52
+ DEPENDENCIES
53
+ bundler (~> 1.4)
54
+ capose!
55
+ pry
56
+ rake
57
+ rspec
58
+ rspec-core
59
+
60
+ BUNDLED WITH
61
+ 1.12.5
data/README.md ADDED
@@ -0,0 +1,101 @@
1
+ # Stackose - A capistrano addon to use with docker stack [WIP]
2
+
3
+ This gem is a refactoring to use the [capose](https://github.com/netguru/capose) gem, but with docker stack implementation.
4
+ **The Documentation is owned from capose, and not so far complete for the docker stack, must be rewritten and cleared**
5
+
6
+ This gem is a lighter version of docker-compose strategy found in [capistrano-docker](https://github.com/netguru/capistrano-docker) gem.
7
+ The idea is to be much simplier and more custom to use.
8
+
9
+
10
+ ### Installation
11
+
12
+ 1. Ensure you already have `capistrano` gem in your project, with version at least `3.7`
13
+ 2. Add the following line to your `Gemfile`: `gem 'stackose', require: false`
14
+ 3. Add the following file to `Capfile`: `require 'stackose'`
15
+
16
+ This gem will automatically hook up to the capistrano after `deploy:updated` hook to perform the deployment via `stackose:deploy` hook
17
+
18
+ ### Changelog
19
+
20
+
21
+ ### Defaults
22
+
23
+ This gem uses couple variables which can be modified inside your deploy scripts, these are:
24
+
25
+ set :stackose_role - capistrano role for stackose, defaults to :web
26
+ set :stackose_copy - list of files/dirs to be copied from shared_path before first command (replaces :link_dirs/files), defaults to []
27
+ set :stackose_project - docker-compose project name, defaults to fetch(:application)
28
+ set :stackose_file - list of files for the docker-compose -f parameter (defauls to ["docker-compose.yml", "docker-compose-#{fetch(:stage)}.yml"]) and finaly the generated docker-compose-override
29
+ set :stackose_commands - list of commands to be run with docker-compose, defaults to []
30
+ set :stackose_docker_mount_point - mount point inside the application container, defaults to "/usr/share/www/"
31
+ set :stackose_linked_folders - list of folders to link inside de image
32
+ set :stackose_service_to_build - name of the service that contains the application to run (default: app)
33
+
34
+ ### Folders to be linked
35
+ If you need to link shared folders to the root of your application path, like capistrano standard linked_folders do,
36
+ you can setup this like:
37
+
38
+ set :capose_linked_folders, [ 'tmp/pids',
39
+ 'tmp/cache',
40
+ 'tmp/sockets',
41
+ 'public/system',
42
+ 'public/pictures',
43
+ 'public/attachments',
44
+ 'public/pages',
45
+ 'public/assets',
46
+ 'uploads']
47
+
48
+ For custom linking you can provide inside the array a hash with key->value of source->destination
49
+
50
+ set :capose_linked_folders, [
51
+ 'tmp/pids',
52
+ 'tmp/cache',
53
+ ....,
54
+ 'uploads',
55
+ "/custom_path/#{fetch(:application)}/":"#{fetch(:capose_docker_mount_point)}/log",
56
+ ]
57
+
58
+ if you need the shared_path url in the key you can set `__shared_path__` as placeholder
59
+
60
+
61
+
62
+ ### Additional files before first command
63
+ If you need to throw in to the "release" folder couple files (say secret files) before image is build, you can use `capose_copy` for that, ex:
64
+
65
+ set :capose_copy, %w(config/secrets.yml certs/google.crt certs/google.key)
66
+
67
+ This command will copy the files from shared/ path before first command is executed, such as:
68
+
69
+ cp -aR [shared_path]/config/secrets.yml [release_path]/config/secrets.yml
70
+ cp -aR [shared_path]/config/google.crt [release_path]/config/google.crt
71
+ cp -aR [shared_path]/config/google.key [release_path]/config/google.key
72
+ docker-compose -p [application] -f ... build
73
+ docker-compose ...
74
+
75
+ ### Additional commands to run
76
+ If your use-case contains more commands than `build` and `up -d`, then you can modify `capose_commands` to achieve that, ex:
77
+
78
+ set :capose_commands, ["build", "run --rm web rake db:migrate", "run --rm web rake assets:precompile", "up -d"]
79
+
80
+ This will tell capistrano to run following commands:
81
+
82
+ docker-compose -p [application] -f docker-compose-[stage].yml -f docker-compose-image-override.yml build
83
+ docker-compose -p [application] -f docker-compose-[stage].yml -f docker-compose-image-override.yml run --rm web rake db:migrate
84
+ docker-compose -p [application] -f docker-compose-[stage].yml -f docker-compose-image-override.yml run --rm web rake assets:precompile
85
+ docker-compose -p [application] -f docker-compose-[stage].yml -f docker-compose-image-override.yml up -d
86
+
87
+ ### Custom docker-compose file paths
88
+
89
+ If you want to add more compose files or change the name, then modify `capose_file` variable, ex:
90
+
91
+ set :stackose_file, ["docker-compose.yml", "docker-compose-override.yml"]
92
+
93
+ This will tell capistrano to run commands as:
94
+
95
+ docker-compose -p [application] -f docker-compose.yml -f docker-compose-override.yml -f docker-compose-image-override.yml [command]
96
+
97
+ ### Docker-compose image override
98
+
99
+ This file is generated on deploy, it will create on the "app" service configurations to make it work more correctly:
100
+ It append the image builded for the release (docker stack don't build images) and the user configuration, so the files generated
101
+ from inside of the container will have the user oth the host system.
@@ -0,0 +1,24 @@
1
+
2
+ ### Template Per Rails e Alchemy
3
+
4
+
5
+ `
6
+ set :assets_dir, %w(public/system/. uploads/. public/pages/. public/noimage/.)
7
+ set :local_assets_dir, %w(../../shared/public/system ../../shared/uploads ../../shared/public/pages ../../shared/public/noimage)
8
+
9
+ set :stackose_copy, %w(config/secrets.yml)
10
+
11
+ set :stackose_commands, ['run --rm --no-deps app rails assets:precompile', 'run --rm --no-deps app rails db:migrate']
12
+
13
+ set :stackose_linked_folders, [ 'tmp/pids',
14
+ 'tmp/cache',
15
+ 'tmp/sockets',
16
+ 'public/system',
17
+ 'public/pictures',
18
+ 'public/attachments',
19
+ 'public/pages',
20
+ 'public/assets',
21
+ 'uploads',
22
+ :"__shared_path__/db_volume"=>"/usr/share/application_storage"
23
+ ]
24
+ `
data/lib/stackose.rb ADDED
@@ -0,0 +1,257 @@
1
+ require 'json'
2
+ namespace :deploy do
3
+ after :updated, 'stackose:deploy'
4
+ after :cleanup, 'stackose:cleanup'
5
+ before :check, 'stackose:create_linked_dirs'
6
+ end
7
+
8
+ namespace :stackose do
9
+ def _project
10
+ return "" if fetch(:stackose_project).nil?
11
+ "-p #{fetch(:stackose_project)}_tmp"
12
+ end
13
+
14
+ def _files
15
+ cmd = []
16
+
17
+ Array(fetch(:stackose_file)).each {|file| cmd << ["-f #{file}"]}
18
+
19
+ cmd.join(" ")
20
+ end
21
+
22
+ def _command(command)
23
+ [_project, _files, command].join(" ")
24
+ end
25
+
26
+ def normalized_stackose_linked_folders
27
+ files = []
28
+ fetch(:stackose_linked_folders).each do |f|
29
+
30
+ if f.is_a? Hash
31
+ f.each {|k, v| files << ["#{k.to_s.gsub('__shared_path__', shared_path.to_s)}", v]}
32
+ elsif f.is_a? String
33
+ files << ["#{shared_path}/#{f}", "#{fetch(:stackose_docker_mount_point)}/#{f}"]
34
+ end
35
+
36
+ end
37
+ files.to_h
38
+ end
39
+
40
+ # task :command do
41
+ # _cmd = ENV["STACKOSE_COMMAND"]
42
+ # if _cmd.nil?
43
+ # puts "Usage: STACKOSE_COMMAND='command' bundle exec cap #{fetch(:stage)} stackose:command"
44
+ # exit 1
45
+ # end
46
+ #
47
+ # on roles(fetch(:stackose_role)) do
48
+ # within current_path do
49
+ # execute :"docker-compose", _command(ENV["STACKOSE_COMMAND"])
50
+ # end
51
+ # end
52
+ # end
53
+ #
54
+ # task :stop do
55
+ # on roles(fetch(:stackose_role)) do
56
+ # within current_path do
57
+ # execute :"docker-compose", _command("stop")
58
+ # end
59
+ # end
60
+ # end
61
+ #
62
+
63
+ desc "check linked dirs, and create this if there are not present"
64
+ task :create_linked_dirs do
65
+ on roles(fetch(:stackose_role)) do
66
+ execute :mkdir,'-p',normalized_stackose_linked_folders.keys.join(' ')
67
+ end
68
+ end
69
+
70
+ task :deploy do
71
+ on roles(fetch(:stackose_role)) do
72
+ within release_path do
73
+ fetch(:stackose_copy).each do |file|
74
+ execute :cp, " -aR #{shared_path}/#{file} #{release_path}/#{file}"
75
+ end
76
+ end
77
+ end
78
+
79
+ base_image_name = "#{fetch(:stackose_project)}:#{fetch(:stackose_image_tag)}"
80
+ compose_override = "docker-compose-image-override.yml"
81
+
82
+ ## costruiamo l'immagine
83
+ on roles(fetch(:stackose_role)) do
84
+ within release_path do
85
+ with fetch(:stackose_env) do
86
+
87
+ user_id = capture :id, '-u'
88
+ group_id = capture :id, '-g'
89
+
90
+ execute :docker, :build, ". -t #{base_image_name}"
91
+
92
+ compose_production = {
93
+ version: '3',
94
+ services: {
95
+ fetch(:stackose_service_to_build, 'app').to_sym => {
96
+ image: base_image_name,
97
+ user: "#{user_id}:#{group_id}"
98
+ }
99
+ }
100
+ }
101
+
102
+ contents = StringIO.new(JSON[compose_production.to_json].to_yaml)
103
+ upload! contents, "#{release_path}/#{compose_override}"
104
+
105
+ set :stackose_file, fetch(:stackose_file) + [compose_override]
106
+
107
+
108
+ end
109
+ end
110
+ end
111
+
112
+
113
+ on roles(fetch(:stackose_role)) do
114
+ within release_path do
115
+ with fetch(:stackose_env) do
116
+ fetch(:stackose_commands).each do |command|
117
+ execute :"docker-compose", _command(command)
118
+ end
119
+
120
+ execute :docker, :stack, :deploy, "-c #{fetch(:stackose_file).join(' -c ')} #{fetch(:stackose_project)}"
121
+
122
+ end
123
+ end
124
+ end
125
+ end
126
+
127
+
128
+ task :cleanup do
129
+ on roles(fetch(:stackose_role)) do
130
+ within release_path do
131
+ with fetch(:stackose_env) do
132
+ tags_list = capture :docker, :images, fetch(:stackose_project).to_sym, '--format "{{.Tag}}"'
133
+
134
+ list = tags_list.split
135
+ list.delete('latest')
136
+
137
+ releases = capture(:ls, "-x", releases_path).split
138
+
139
+ (list - releases).each do |r|
140
+ #delete image without release path
141
+ execute :docker, :image, :rm, "#{fetch(:stackose_project)}:#{r}"
142
+ end
143
+
144
+ end
145
+ end
146
+ end
147
+ end
148
+
149
+ desc "Create online docker-compose file, use the linked_folders parameter to generate the hash form the compose file"
150
+ task :create_online_docker_compose_file do
151
+
152
+ ask(:exposed_port, 30000)
153
+ ask(:server_name, 'example.tld')
154
+
155
+ ask(:need_redis_service, true)
156
+
157
+
158
+ compose_production = {
159
+ version: '3',
160
+ services: {
161
+ app: {
162
+ restart: 'unless-stopped',
163
+ environment: {:RAILS_ENV => fetch(:rails_env).to_s,
164
+ :RAILS_SERVE_STATIC_FILES => 'true',
165
+ :RAILS_MAX_THREADS => 5,
166
+ :WEB_CONCURRENCY => 1},
167
+ deploy: {
168
+ replicas: 1,
169
+ resources: {
170
+ limits: {
171
+ cpus: '0.50',
172
+ memory: '250M'
173
+ }
174
+ }
175
+ },
176
+ volumes:
177
+ normalized_stackose_linked_folders.collect do |k|
178
+ k.join(':')
179
+ end,
180
+ ports: ["#{fetch(:exposed_port)}:3000"]
181
+ }
182
+ }
183
+ }
184
+
185
+ if fetch(:need_redis_service)
186
+ compose_production[:services][:redis] = {
187
+ restart: 'unless-stopped',
188
+ image: 'redis',
189
+ volumes: ["./config/redis.conf:/usr/local/etc/redis/redis.conf"],
190
+ deploy: {
191
+ resources: {
192
+ limits: {
193
+ memory: '50M'
194
+ }
195
+ }
196
+ }
197
+ }
198
+
199
+ File.open("config/redis.conf", 'w') {|file| file.write("maxmemory 50mb\nmaxmemory-policy allkeys-lfu")}
200
+ end
201
+
202
+ nginx_config = "server {
203
+ listen 80;
204
+ server_name #{fetch(:server_name)};
205
+ location / {
206
+ proxy_pass http://0.0.0.0:#{fetch(:exposed_port)}/;
207
+ proxy_redirect off;
208
+
209
+ proxy_set_header Host $host;
210
+ proxy_set_header X-Real-IP $remote_addr;
211
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
212
+
213
+ client_max_body_size 10m;
214
+ client_body_buffer_size 128k;
215
+
216
+ proxy_connect_timeout 90;
217
+ proxy_send_timeout 90;
218
+ proxy_read_timeout 90;
219
+
220
+ proxy_buffer_size 4k;
221
+ proxy_buffers 4 32k;
222
+ proxy_busy_buffers_size 64k;
223
+ proxy_temp_file_write_size 64k;
224
+ }
225
+ }"
226
+
227
+ puts "Configurazione NGINX:"
228
+ puts nginx_config
229
+ puts "Ricorda di cambiare anche la configurazione del database.yml per l'env specificato"
230
+ puts "
231
+ production:
232
+ <<: *default
233
+ pool: <%= ENV.fetch(\"RAILS_MAX_THREADS\") {5} %>
234
+ database: /usr/share/application_storage/production.sqlite3
235
+ "
236
+
237
+ File.open("docker-compose-production.yml", 'w') {|file| file.write(JSON[compose_production.to_json].to_yaml)}
238
+ end
239
+
240
+ end
241
+
242
+ namespace :load do
243
+ task :defaults do
244
+ set :stackose_role, -> {:web}
245
+ set :stackose_copy, -> {[]}
246
+ set :stackose_project, -> {fetch(:application)}
247
+ set :stackose_file, -> {["docker-compose.yml", "docker-compose-#{fetch(:stage)}.yml"]}
248
+ set :stackose_env, -> {{}}
249
+ set :stackose_image_tag, -> {fetch(:release_timestamp)}
250
+ set :stackose_service_to_build, -> {'app'}
251
+
252
+ set :stackose_commands, -> {[]}
253
+
254
+ set :stackose_linked_folders, -> {[]}
255
+ set :stackose_docker_mount_point, -> {'/usr/share/www'}
256
+ end
257
+ end
data/stackose.gemspec ADDED
@@ -0,0 +1,21 @@
1
+ lib = File.expand_path('../lib', __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+
4
+ Gem::Specification.new do |spec|
5
+ spec.name = 'stackose'
6
+ spec.version = '0.1.0'
7
+ spec.authors = ["Marino Bonetti"]
8
+ spec.email = ["marinobonetti@gmail.com"]
9
+ spec.description = %q{Docker-Stack support for Capistrano 3.x}
10
+ spec.summary = %q{Docker-Stack support for Capistrano 3.x}
11
+ spec.homepage = 'https://github.com/oniram88/stackose'
12
+ spec.license = 'MIT'
13
+
14
+ spec.files = `git ls-files`.split($/)
15
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
16
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
17
+ spec.require_paths = ['lib']
18
+
19
+ spec.add_runtime_dependency 'capistrano', '~> 3.7'
20
+ spec.add_development_dependency 'bundler', '~> 1.4'
21
+ end
metadata ADDED
@@ -0,0 +1,79 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: stackose
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Marino Bonetti
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-04-24 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: capistrano
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '3.7'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '3.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.4'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.4'
41
+ description: Docker-Stack support for Capistrano 3.x
42
+ email:
43
+ - marinobonetti@gmail.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - ".gitignore"
49
+ - Gemfile
50
+ - Gemfile.lock
51
+ - README.md
52
+ - RailsSqliteTemplate.md
53
+ - lib/stackose.rb
54
+ - stackose.gemspec
55
+ homepage: https://github.com/oniram88/stackose
56
+ licenses:
57
+ - MIT
58
+ metadata: {}
59
+ post_install_message:
60
+ rdoc_options: []
61
+ require_paths:
62
+ - lib
63
+ required_ruby_version: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ required_rubygems_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: '0'
73
+ requirements: []
74
+ rubyforge_project:
75
+ rubygems_version: 2.5.2
76
+ signing_key:
77
+ specification_version: 4
78
+ summary: Docker-Stack support for Capistrano 3.x
79
+ test_files: []