deployinator 0.0.0 → 0.0.1

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.
@@ -1,17 +1,75 @@
1
- namespace :config do
2
- set :stage, :staging
3
- desc 'Write deploy_example.rb and <stage>_example.rb files'
4
- task :write_examples do
5
- run_locally do
6
- execute "mkdir -p ./config/deploy"
1
+ namespace :deployinator do
2
+
3
+ # desc 'Ensure all deployinator specific settings are set, and warn and raise if not.'
4
+ # task :check_settings do
5
+ # run_locally do
6
+ # deploy_rb = File.expand_path("./config/deploy.rb")
7
+ # deploy_dir = File.expand_path("./config/deploy")
8
+ # {
9
+ # "Do not \"set :bundle_binstubs, ....\", deployinator will overwrite it and you'll be confused." =>
10
+ # system("grep -R -q -E '^set\ :bundle_binstubs' #{deploy_rb} #{deploy_dir}"),
11
+ # "Do not \"set :bundle_gemfile, ....\", deployinator will overwrite it and you'll be confused." =>
12
+ # system("grep -R -q -E '^set\ :bundle_gemfile' #{deploy_rb} #{deploy_dir}"),
13
+ # "You need \"set :domain, 'your.domain.com'\" in your config/deploy/#{fetch(:stage)}.rb file." =>
14
+ # fetch(:domain).nil?,
15
+ # "You need \"set :nginx_container_name, 'your_nginx_container_name'\" in your config/deploy/#{fetch(:stage)}.rb file." =>
16
+ # fetch(:nginx_container_name).nil?,
17
+ # "You need \"set :external_socket_path, 'your_external_socket_path'\" in your config/deploy/#{fetch(:stage)}.rb file." =>
18
+ # fetch(:external_socket_path).nil?,
19
+ # "You need \"set :postgres_container_name, 'your_postgres_container_name'\" in your config/deploy/#{fetch(:stage)}.rb file." =>
20
+ # fetch(:postgres_container_name).nil?,
21
+ # "You need \"set :postgres_port, 'your_postgres_port_number'\" in your config/deploy/#{fetch(:stage)}.rb file." =>
22
+ # fetch(:postgres_port).nil?,
23
+ # "You need \"set :ruby_image_name, 'your_ruby_image_name'\" in your config/deploy/#{fetch(:stage)}.rb file." =>
24
+ # fetch(:ruby_image_name).nil?,
25
+ # "You need \"set :ruby_container_name, 'your_ruby_container_name'\" in your config/deploy/#{fetch(:stage)}.rb file." =>
26
+ # fetch(:ruby_container_name).nil?,
27
+ # "You need \"set :ruby_container_max_mem_mb, 'your_ruby_container_max_mem_mb'\" in your config/deploy/#{fetch(:stage)}.rb file." =>
28
+ # fetch(:ruby_container_max_mem_mb).nil?
29
+ # }.each do |message, true_false|
30
+ # fatal(message) and raise if true_false
31
+ # end
32
+ # end
33
+ # end
34
+ # before 'deploy:starting', 'deployinator:check_settings'
7
35
 
8
- # example deploy.rb
9
- config = "set :application, 'example-app'"
10
- File.open('./config/deploy_example.rb', 'w') { |f| f.write(config) }
36
+ # TODO make this better
37
+ task :check_templates do
38
+ run_locally do
39
+ keys_template = File.expand_path("./templates/deploy/deployer_authorized_keys.erb")
40
+ bluepill_template = File.expand_path("./templates/deploy/#{fetch(:application)}_bluepill.rb.erb")
41
+ unicorn_template = File.expand_path("./templates/deploy/#{fetch(:application)}_unicorn.rb.erb")
42
+ {
43
+ "You need a templates/deploy/deployer_authorized_keys.erb file." => keys_template,
44
+ "You need a templates/deploy/#{fetch(:application)}_bluepill.rb.erb file." => bluepill_template,
45
+ "You need a templates/deploy/#{fetch(:application)}_unicorn.rb.erb file." => unicorn_template,
46
+ }.each do |message, file|
47
+ fatal(message) and raise unless File.exists? file
48
+ end
49
+ end
50
+ end
51
+ before 'deploy:starting', 'deployinator:check_templates'
11
52
 
12
- # example <stage>.rb
13
- config = "set :example_attr, true"
14
- File.open('./config/deploy/stage_example.rb', 'w') { |f| f.write(config) }
53
+ desc 'Write example config files'
54
+ task :install do
55
+ run_locally do
56
+ execute "mkdir -p config/deploy templates/deploy"
57
+ {
58
+ "examples/Capfile" => "Capfile_example",
59
+ "examples/config/deploy.rb" => "config/deploy_example.rb",
60
+ "examples/config/deploy_deployinator.rb" => "config/deploy_deployinator_example.rb",
61
+ "examples/config/deploy/staging.rb" => "config/deploy/staging_example.rb",
62
+ "examples/config/deploy/staging_deployinator.rb" => "config/deploy/staging_deployinator_example.rb",
63
+ "examples/Dockerfile" => "templates/deploy/Dockerfile_example",
64
+ "examples/deployer_authorized_keys.erb" => "templates/deploy/deployer_authorized_keys_example.erb",
65
+ "examples/application_unicorn.rb.erb" => "templates/deploy/#{fetch(:application, "my_app")}_unicorn_example.rb.erb",
66
+ "examples/application_bluepill.rb.erb" => "templates/deploy/#{fetch(:application, "my_app")}_bluepill_example.rb.erb"
67
+ }.each do |source, destination|
68
+ config = File.read(File.dirname(__FILE__) + "/#{source}")
69
+ File.open("./#{destination}", 'w') { |f| f.write(config) }
70
+ info "Wrote '#{destination}'"
71
+ end
72
+ info "Now remove the '_example' portion of their names or diff with existing files and add the needed lines."
15
73
  end
16
74
  end
17
75
  end
@@ -1,119 +1,332 @@
1
1
  # config valid only for Capistrano 3.1
2
2
  lock '3.2.1'
3
3
 
4
- # Use `from_local=true bundle exec cap <stage> deploy` to deploy your
5
- # locally changed code instead of the code in the git repo.
6
- # TODO this is not working yet
7
- if ENV['from_local']
8
- set :repo_url, 'file://.'
9
- set :scm, :none
10
- else
11
- set :repo_url, 'git@github.com:snarlysodboxer/example.git'
12
- set :scm, :git
13
- end
4
+ namespace :deploy do
14
5
 
15
- # Default branch is :master
16
- # ask :branch, proc { `git rev-parse --abbrev-ref HEAD`.chomp }.call
6
+ task :set_bundle_command_map => [:set_deployer_user_id] do
7
+ SSHKit.config.command_map[:bundle] = [
8
+ "/usr/bin/env docker run --rm --tty",
9
+ "--user", fetch(:deployer_user_id),
10
+ "-e", "GEM_HOME=#{fetch(:deploy_to)}/shared/bundle",
11
+ "-e", "GEM_PATH=#{fetch(:deploy_to)}/shared/bundle",
12
+ "-e", "PATH=#{fetch(:deploy_to)}/shared/bundle/bin:$PATH",
13
+ "--entrypoint", "#{fetch(:deploy_to)}/shared/bundle/bin/bundle",
14
+ "--volume #{fetch(:deploy_to)}:#{fetch(:deploy_to)}:rw",
15
+ fetch(:ruby_image_name)
16
+ ].join(' ')
17
+ end
18
+ before 'bundler:install', 'deploy:set_bundle_command_map'
17
19
 
18
- # Default deploy_to directory is /var/www/my_app
19
- # set :deploy_to, '/var/www/my_app'
20
+ task :set_rm_command_map do
21
+ SSHKit.config.command_map[:rm] = "/usr/bin/env sudo rm"
22
+ end
23
+ before 'deploy:started', 'deploy:set_rm_command_map'
20
24
 
21
- # Default value for :format is :pretty
22
- # set :format, :pretty
25
+ # Append dependancy to existing cleanup task
26
+ task :cleanup => :set_rm_command_map
23
27
 
24
- # Default value for :log_level is :debug
25
- #set :log_level, :debug
26
- set :log_level, :info
28
+ # Overwrite :assets:precompile to use docker
29
+ Rake::Task["deploy:assets:precompile"].clear
30
+ namespace :assets do
31
+ task :precompile do
32
+ on roles(fetch(:assets_roles)) do
33
+ execute(
34
+ "docker", "run", "--rm", "--tty",
35
+ "-w", fetch(:release_path, "#{fetch(:deploy_to)}/current"),
36
+ "--entrypoint", "#{fetch(:deploy_to)}/shared/bundle/bin/rake",
37
+ "--volume", "#{fetch(:deploy_to)}:#{fetch(:deploy_to)}:rw",
38
+ fetch(:ruby_image_name), "assets:precompile"
39
+ )
40
+ end
41
+ end
42
+ end
27
43
 
28
- # Default value for :pty is false
29
- # set :pty, true
44
+ # Overwrite :cleanup_assets to use docker
45
+ Rake::Task["deploy:cleanup_assets"].clear
46
+ desc 'Cleanup expired assets'
47
+ task :cleanup_assets => [:set_rails_env] do
48
+ on roles(fetch(:assets_roles)) do
49
+ execute(
50
+ "docker", "run", "--rm", "--tty",
51
+ "-e", "RAILS_ENV=#{fetch(:rails_env)}",
52
+ "-w", fetch(:release_path, "#{fetch(:deploy_to)}/current"),
53
+ "--entrypoint", "#{fetch(:deploy_to)}/shared/bundle/bin/bundle",
54
+ "--volume", "#{fetch(:deploy_to)}:#{fetch(:deploy_to)}:rw",
55
+ fetch(:ruby_image_name), "exec", "rake", "assets:clean"
56
+ )
57
+ end
58
+ end
30
59
 
31
- # Default value for :linked_files is []
32
- # set :linked_files, %w{config/nginx.conf}
60
+ # Overwrite :migrate to use docker
61
+ Rake::Task["deploy:migrate"].clear
62
+ desc 'Runs rake db:migrate if migrations are set'
63
+ task :migrate => [:set_rails_env, :ensure_running_postgres] do
64
+ on primary fetch(:migration_role) do
65
+ conditionally_migrate = fetch(:conditionally_migrate)
66
+ info '[deploy:migrate] Checking changes in /db/migrate' if conditionally_migrate
67
+ if conditionally_migrate && test("diff -q #{release_path}/db/migrate #{current_path}/db/migrate")
68
+ info '[deploy:migrate] Skip `deploy:migrate` (nothing changed in db/migrate)'
69
+ else
70
+ info '[deploy:migrate] Run `rake db:migrate`' if conditionally_migrate
71
+ execute(
72
+ "docker", "run", "--rm", "--tty",
73
+ "--link", "#{fetch(:postgres_container_name)}:postgres",
74
+ "--volume", "#{fetch(:deploy_to)}:#{fetch(:deploy_to)}:rw",
75
+ "-e", "RAILS_ENV=#{fetch(:rails_env)}",
76
+ "--entrypoint", "#{fetch(:deploy_to)}/shared/bundle/bin/rake",
77
+ "-w", fetch(:release_path, "#{fetch(:deploy_to)}/current"),
78
+ fetch(:ruby_image_name), "db:migrate"
79
+ )
80
+ end
81
+ end
82
+ end
33
83
 
34
- # Default value for linked_dirs is []
35
- # set :linked_dirs, %w{bin log tmp/pids tmp/cache tmp/sockets vendor/bundle public/system}
84
+ # TODO make this better
85
+ task :ensure_running_postgres do
86
+ on primary fetch(:migration_role) do
87
+ unless capture("nc", "127.0.0.1", fetch(:postgres_port), "<", "/dev/null", ">", "/dev/null;", "echo", "$?").strip == "0"
88
+ fatal "Port #{fetch(:postgres_port)} is not responding, cannot db:migrate!"
89
+ raise
90
+ end
91
+ end
92
+ end
93
+ # task :ensure_running_postgres do
94
+ # on primary fetch(:migration_role) do
95
+ # if test "docker", "inspect", fetch(:postgres_container_name), "&>", "/dev/null"
96
+ # if (capture "docker", "inspect",
97
+ # "--format='{{.State.Running}}'",
98
+ # fetch(:postgres_container_name)).strip == "true"
99
+ # else
100
+ # execute "docker", "start", fetch(:postgres_container_name)
101
+ # end
102
+ # else
103
+ # set :run_pg_setup, ask("'true' or 'false', - #{fetch(:postgres_container_name)} is not running, would you like to run 'rake pg:setup'?", "false")
104
+ # if fetch(:run_pg_setup) == "true"
105
+ # #load Gem.bin_path('bundler', 'bundle')
106
+ # #import 'postgresinator'
107
+ # #load './infrastructure/Rakefile'
108
+ # Rake::Task['pg:setup'].invoke
109
+ # else
110
+ # raise "#{fetch(:postgres_container_name)} is not running, can't run db:migrate!"
111
+ # end
112
+ # end
113
+ # end
114
+ # end
115
+ before 'deploy:started', :ensure_running_postgres
36
116
 
37
- # Default value for default_env is {}
38
- # set :default_env, { path: "/opt/ruby/bin:$PATH" }
117
+ before 'deploy:check', :setup_deployer_user do
118
+ on "#{ENV['USER']}@#{fetch(:domain)}" do
119
+ as :root do
120
+ unless test "id", fetch(:deploy_username)
121
+ execute "adduser", "--disabled-password", "--gecos", "\"\"", fetch(:deploy_username)
122
+ execute "usermod", "-a", "-G", "sudo", fetch(:deploy_username)
123
+ execute "usermod", "-a", "-G", "docker", fetch(:deploy_username)
124
+ end
125
+ execute "mkdir", "-p", "/home/#{fetch(:deploy_username)}/.ssh"
126
+ # not actually using ERB interpolation, no need for an instance variable.
127
+ template_path = File.expand_path("./templates/deploy/#{fetch(:deploy_username)}_authorized_keys.erb")
128
+ generated_config_file = ERB.new(File.new(template_path).read).result(binding)
129
+ # upload! does not yet honor "as" and similar scoping methods
130
+ upload! StringIO.new(generated_config_file), "/tmp/authorized_keys"
131
+ execute "mv", "-b", "/tmp/authorized_keys", "/home/#{fetch(:deploy_username)}/.ssh/authorized_keys"
132
+ execute "chown", "-R", "#{fetch(:deploy_username)}:#{fetch(:deploy_username)}", "/home/#{fetch(:deploy_username)}/.ssh"
133
+ execute "chmod", "700", "/home/#{fetch(:deploy_username)}/.ssh"
134
+ execute "chmod", "600", "/home/#{fetch(:deploy_username)}/.ssh/authorized_keys"
135
+ end
136
+ end
137
+ end
39
138
 
40
- # Default value for keep_releases is 5
41
- # set :keep_releases, 5
139
+ task :ensure_www_data_user do
140
+ on "#{ENV['USER']}@#{fetch(:domain)}" do
141
+ as :root do
142
+ unless test "id", "www-data"
143
+ execute "adduser", "--disabled-password", "--gecos", "\"\"", "www-data"
144
+ end
145
+ end
146
+ end
147
+ end
148
+ after 'deploy:started', :ensure_www_data_user
42
149
 
43
- namespace :deploy do
150
+ task :set_deployer_user_id do
151
+ on roles(:app), in: :sequence, wait: 5 do
152
+ set :deployer_user_id, capture("id", "-u", fetch(:deploy_username)).strip
153
+ end
154
+ end
44
155
 
45
- # :started is the hook before which to set/check your needed environment/settings
46
- before :started, :ensure_setup
156
+ task :set_www_data_user_id do
157
+ on roles(:app), in: :sequence, wait: 5 do
158
+ set :www_data_user_id, capture("id", "-u", "www-data").strip
159
+ end
160
+ end
47
161
 
48
- task :ensure_setup do
49
- on roles(:web), :once => true do
50
- raise "You need to use ruby 1.9 or higher where you are running this capistrano command." unless RUBY_VERSION >= "1.9"
51
- test "bash", "-l", "-c", "'docker", "ps", "&>", "/dev/null", "||", "sudo", "usermod", "-a", "-G", "docker", "$USER'"
162
+ task :chown_log_dir => :set_www_data_user_id do
163
+ on roles(:app), in: :sequence, wait: 5 do
164
+ as :root do
165
+ unless test "[", "-d", "#{fetch(:deploy_to)}/shared/log", "]"
166
+ execute("mkdir", "-p", "#{fetch(:deploy_to)}/shared/log")
167
+ end
168
+ execute "chown", "-R", "#{fetch(:www_data_user_id)}:#{fetch(:www_data_user_id)}", "#{fetch(:deploy_to)}/shared/log"
169
+ end
52
170
  end
53
171
  end
172
+ before 'deploy:check:linked_dirs', :chown_log_dir
54
173
 
55
- # do this so capistrano has permissions to remove old releases
56
- before :updating, :revert_permissions do
57
- on roles(:web) do
58
- if test "[", "-d", "#{releases_path}", "]"
59
- execute "bash", "-l", "-c", "'sudo", "chown", "-R", "deployer.", "#{releases_path}'"
174
+ task :setup_deploy_to_dir => :set_deployer_user_id do
175
+ on roles(:app), in: :sequence, wait: 5 do
176
+ as :root do
177
+ [
178
+ fetch(:deploy_to),
179
+ "#{fetch(:deploy_to)}/shared",
180
+ "#{fetch(:deploy_to)}/releases"
181
+ ].each do |dir|
182
+ unless test "[", "-d", dir, "]"
183
+ execute("mkdir", "-p", dir)
184
+ end
185
+ execute "chown", "#{fetch(:deployer_user_id)}:#{fetch(:deployer_user_id)}", dir
186
+ end
60
187
  end
61
188
  end
62
189
  end
190
+ after :setup_deployer_user, :setup_deploy_to_dir
63
191
 
64
- before :restart, :ensure_permissions do
65
- on roles(:web) do
66
- execute "bash", "-l", "-c", "'sudo", "mkdir", "-p", "#{current_path}/data/cache'"
67
- execute "bash", "-l", "-c", "'sudo", "chown", "-R", "www-data.", "#{current_path}/data'"
192
+ task :install_bundler => :set_deployer_user_id do
193
+ on roles(:app), in: :sequence, wait: 5 do
194
+ as :root do
195
+ unless test "[", "-f", "#{fetch(:deploy_to)}/shared/bundle/bin/bundle", "]"
196
+ execute(
197
+ "docker", "run", "--rm", "--tty",
198
+ "-e", "GEM_HOME=#{fetch(:deploy_to)}/shared/bundle",
199
+ "-e", "GEM_PATH=#{fetch(:deploy_to)}/shared/bundle",
200
+ "-e", "PATH=#{fetch(:deploy_to)}/shared/bundle/bin:$PATH",
201
+ "--entrypoint", "/usr/local/bin/gem",
202
+ "--volume", "#{fetch(:deploy_to)}:#{fetch(:deploy_to)}:rw",
203
+ fetch(:ruby_image_name), "install",
204
+ "--install-dir", "#{fetch(:deploy_to)}/shared/bundle",
205
+ "--bindir", "#{fetch(:deploy_to)}/shared/bundle/bin",
206
+ "--no-ri", "--no-rdoc", "--quiet", "bundler", "-v'#{fetch(:bundler_version)}'"
207
+ )
208
+ end
209
+ execute "chown", "-R", "#{fetch(:deployer_user_id)}:#{fetch(:deployer_user_id)}", "#{fetch(:deploy_to)}/shared/bundle"
210
+ end
68
211
  end
69
212
  end
213
+ before 'bundler:install', 'deploy:install_bundler'
70
214
 
71
- #desc 'Install config files in current_path'
72
- before :restart, :install_config_files do
73
- on roles(:web) do |host|
74
- require 'erb'
75
- { 'config/nginx.conf.erb' => "#{current_path}/config/#{fetch(:application)}-nginx.conf",
76
- 'config/php-fpm.conf.erb' => "#{current_path}/config/#{fetch(:application)}-php-fpm.conf",
77
- 'config/php.ini.erb' => "#{current_path}/config/#{fetch(:application)}-php.ini"
78
- }.each do |template, upload_path|
79
- @worker_processes = fetch(:worker_processes)
80
- template_path = File.expand_path(template)
81
- host_config = ERB.new(File.new(template_path).read).result(binding)
82
- upload! StringIO.new(host_config), upload_path
215
+ desc 'Restart application'
216
+ task :restart => [:set_www_data_user_id, :install_config_files] do
217
+ on roles(:app), in: :sequence, wait: 5 do
218
+ if test "docker", "inspect", fetch(:ruby_container_name), "&>", "/dev/null"
219
+ if (capture "docker", "inspect",
220
+ "--format='{{.State.Restarting}}'",
221
+ fetch(:ruby_container_name)).strip == "true"
222
+ execute("docker", "stop", fetch(:ruby_container_name))
223
+ execute("docker", "wait", fetch(:ruby_container_name))
224
+ end
225
+ if (capture "docker", "inspect",
226
+ "--format='{{.State.Running}}'",
227
+ fetch(:ruby_container_name)).strip == "true"
228
+ execute(
229
+ "docker", "exec", "--tty",
230
+ fetch(:ruby_container_name),
231
+ "#{fetch(:deploy_to)}/shared/bundle/bin/bluepill",
232
+ fetch(:application), "stop"
233
+ )
234
+ sleep 5
235
+ execute("docker", "stop", fetch(:ruby_container_name))
236
+ execute("docker", "wait", fetch(:ruby_container_name))
237
+ end
238
+ sleep 2
239
+ begin
240
+ execute("docker", "rm", fetch(:ruby_container_name))
241
+ rescue
242
+ sleep 5
243
+ begin
244
+ execute("docker", "rm", fetch(:ruby_container_name))
245
+ rescue
246
+ fatal "We were not able to remove the container for some reason. Try running 'cap <stage> deploy:restart' again."
247
+ end
248
+ end
249
+ end
250
+ as :root do
251
+ [
252
+ fetch(:external_socket_path),
253
+ "#{fetch(:deploy_to)}/current/public",
254
+ "#{fetch(:deploy_to)}/shared/tmp",
255
+ "#{fetch(:deploy_to)}/shared/log/production.log"
256
+ ].each do |directory|
257
+ execute "chown", "-R", "#{fetch(:www_data_user_id)}:#{fetch(:www_data_user_id)}", directory
258
+ end
259
+ execute "chown", "-R", "#{fetch(:deployer_user_id)}:#{fetch(:deployer_user_id)}", "#{fetch(:deploy_to)}/shared/bundle"
83
260
  end
261
+ execute("docker", "run", fetch(:docker_run_bluepill_command))
84
262
  end
85
263
  end
264
+ after :publishing, :restart
86
265
 
87
- desc 'Restart or start application'
88
- task :restart do
89
- on roles(:web) do
90
- ['php5', 'nginx'].each do |name|
91
- container = {
92
- :name => fetch("#{name}_container_name".to_sym),
93
- :run_options => fetch("#{name}_run_options".to_sym).join(' '),
94
- :image => fetch("#{name}_image_name".to_sym)
95
- }
96
- exists = "docker inspect #{container[:name]} &> /dev/null"
97
- is_running = "docker inspect --format='{{.State.Running}}' #{container[:name]} 2>&1 | grep -q true"
98
- if test(exists)
99
- if test(is_running)
100
- execute "docker", "stop", container[:name]
266
+ after :publishing, :check_nginx_running do
267
+ on primary fetch(:migration_role) do
268
+ if test "docker", "inspect", fetch(:nginx_container_name), "&>", "/dev/null"
269
+ if (capture "docker", "inspect",
270
+ "--format='{{.State.Running}}'",
271
+ fetch(:nginx_container_name)).strip == "true"
272
+ else
273
+ warn "The nginx container named #{fetch(:nginx_container_name)} exists but is not running. (You need this, start it, or re-run setup with something like nginxinator.)"
274
+ end
275
+ else
276
+ warn "No nginx container named #{fetch(:nginx_container_name)} exists! (You need this, set it up with something like nginxinator.)"
277
+ end
278
+ end
279
+ end
280
+
281
+ after :publishing, :ensure_cadvisor do
282
+ on roles(:app), in: :sequence, wait: 5 do
283
+ if fetch(:use_cadvisor, true)
284
+ if test "docker", "inspect", "cadvisor", "&>", "/dev/null"
285
+ if (capture "docker", "inspect",
286
+ "--format='{{.State.Running}}'",
287
+ "cadvisor").strip == "true"
288
+ info "cadvisor is already running."
289
+ else
290
+ info "Restarting existing cadvisor container."
291
+ execute "docker", "start", "cadvisor"
101
292
  end
102
- execute "docker", "rm", container[:name]
293
+ else
294
+ execute("docker", "run", fetch(:docker_run_cadvisor_command))
295
+ end
296
+ end
297
+ end
298
+ end
299
+
300
+ after :restart, :clear_cache do
301
+ on roles(:web), in: :groups, limit: 3, wait: 10 do
302
+ # Here we can do anything such as:
303
+ # within release_path do
304
+ # execute :rake, 'cache:clear'
305
+ # end
306
+ end
307
+ end
308
+
309
+ task :install_config_files => [:set_deployer_user_id] do
310
+ on roles(:app), in: :sequence, wait: 5 do
311
+ set :bluepill_config, -> { "#{fetch(:application)}_bluepill.rb" }
312
+ set :unicorn_config, -> { "#{fetch(:application)}_unicorn.rb" }
313
+ set :socket_path, -> { fetch(:internal_socket_path) }
314
+ as 'root' do
315
+ [fetch(:bluepill_config), fetch(:unicorn_config)].each do |config_file|
316
+ @deploy_to = fetch(:deploy_to) # needed for ERB
317
+ @internal_socket_path = fetch(:socket_path) # needed for ERB
318
+ @application = fetch(:application) # needed for ERB
319
+ template_path = File.expand_path("./templates/deploy/#{config_file}.erb")
320
+ current_path = Pathname.new("#{fetch(:deploy_to)}/current")
321
+ generated_config_file = ERB.new(File.new(template_path).read).result(binding)
322
+ set :final_path, -> { fetch(:release_path, current_path).join('config', config_file) }
323
+ upload! StringIO.new(generated_config_file), "/tmp/#{config_file}"
324
+ execute("mv", "/tmp/#{config_file}", fetch(:final_path))
325
+ execute("chown", "#{fetch(:deployer_user_id)}:#{fetch(:deployer_user_id)}", fetch(:final_path))
326
+ execute("chmod", "664", fetch(:final_path))
103
327
  end
104
- execute(
105
- "docker", "run",
106
- "--detach", "--tty",
107
- "--name", container[:name],
108
- container[:run_options],
109
- container[:image]
110
- )
111
- sleep 2
112
- error("Container #{container[:name]} did not stay running more than 2 seconds!") unless test(is_running)
113
328
  end
114
329
  end
115
330
  end
116
331
 
117
- # :publishing is the hook after which to set our service restart commands
118
- after :publishing, :restart
119
332
  end
@@ -0,0 +1,27 @@
1
+ # Load DSL and Setup Up Stages
2
+ require 'capistrano/setup'
3
+
4
+ # Includes default deployment tasks
5
+ require 'capistrano/deploy'
6
+
7
+ # Includes tasks from other gems included in your Gemfile
8
+ #
9
+ # For documentation on these, see for example:
10
+ #
11
+ # https://github.com/capistrano/rvm
12
+ # https://github.com/capistrano/rbenv
13
+ # https://github.com/capistrano/chruby
14
+ # https://github.com/capistrano/bundler
15
+ # https://github.com/capistrano/rails
16
+ #
17
+ # require 'capistrano/rvm'
18
+ # require 'capistrano/rbenv'
19
+ # require 'capistrano/chruby'
20
+ require 'capistrano/bundler'
21
+ require 'capistrano/rails/assets'
22
+ require 'capistrano/rails/migrations'
23
+
24
+ require 'deployinator'
25
+
26
+ # Loads custom tasks from `lib/capistrano/tasks' if you have any defined.
27
+ Dir.glob('lib/capistrano/tasks/*.rake').each { |r| import r }
@@ -0,0 +1,16 @@
1
+ # vi: ft=config
2
+ FROM ubuntu:12.04
3
+ MAINTAINER david amick <docker@davidamick.com>
4
+
5
+ ENV DEBIAN_FRONTEND noninteractive
6
+
7
+ RUN /bin/bash -c "apt-get update -qq && apt-get install -qy wget curl bzip2 make gcc"
8
+ RUN wget -O ruby-install-0.5.0.tar.gz https://github.com/postmodern/ruby-install/archive/v0.5.0.tar.gz
9
+ RUN tar -xzvf ruby-install-0.5.0.tar.gz
10
+ RUN cd ruby-install-0.5.0/ && make install && ruby-install --system ruby 1.9.3-p547
11
+ RUN gem install bundler --no-ri --no-rdoc
12
+
13
+ RUN /bin/bash -c "apt-get update -qq && apt-get install -qy libxml2 libxml2-dev libxslt1-dev nodejs postgresql-contrib libpq-dev"
14
+
15
+ ENTRYPOINT ["/bin/bash"]
16
+ CMD ["-l"]
@@ -0,0 +1,27 @@
1
+ def red_unicorn_exec
2
+ "<%= @deploy_to %>/shared/bundle/bin/red_unicorn --env production --pid-file <%= @internal_socket_path %>/unicorn.pid --unicorn-exec <%= @deploy_to %>/shared/bundle/bin/unicorn_rails --unicorn-config <%= @deploy_to %>/current/config/<%= @application %>_unicorn.rb"
3
+ end
4
+
5
+ Bluepill.application("<%= @application %>", :log_file => "<%= @deploy_to %>/shared/log/bluepill.log", :foreground => true) do |app|
6
+ app.process("unicorn") do |process|
7
+ process.pid_file = "<%= @internal_socket_path %>/unicorn.pid"
8
+ process.working_dir = "<%= @deploy_to %>/current"
9
+ process.environment = {"BUNDLE_GEMFILE" => "<%= @deploy_to %>/current/Gemfile"}
10
+ process.start_command = "#{red_unicorn_exec} start"
11
+ process.stop_command = "#{red_unicorn_exec} stop"
12
+ process.restart_command = "'#{red_unicorn_exec} status; if [ $? = 0 ]; then #{red_unicorn_exec} restart; else #{red_unicorn_exec} start; fi'"
13
+
14
+ process.uid = process.gid = 'www-data'
15
+
16
+ process.start_grace_time = 30.seconds
17
+ process.stop_grace_time = 30.seconds
18
+ process.restart_grace_time = 60.seconds
19
+
20
+ process.monitor_children do |child_process|
21
+ child_process.stop_command = "kill -QUIT {{PID}}"
22
+
23
+ child_process.checks :mem_usage, :every => 30.seconds, :below => 300.megabytes, :times => [3,4], :fires => :stop
24
+ child_process.checks :cpu_usage, :every => 30.seconds, :below => 50, :times => [3,4], :fires => :stop
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,40 @@
1
+ current_path = "<%= @deploy_to %>/current"
2
+ shared_path = "<%= @deploy_to %>/shared"
3
+ shared_bundler_gems_path = "<%= @deploy_to %>/shared/bundle"
4
+
5
+ worker_processes 4
6
+ working_directory current_path
7
+ listen "<%= @internal_socket_path %>/unicorn.socket", :backlog => 64
8
+ timeout 300
9
+ pid "<%= @internal_socket_path %>/unicorn.pid"
10
+
11
+ stderr_path "#{shared_path}/log/unicorn.stderr.log"
12
+ stdout_path "#{shared_path}/log/unicorn.stdout.log"
13
+
14
+ preload_app true
15
+ GC.respond_to?(:copy_on_write_friendly=) and
16
+ GC.copy_on_write_friendly = true
17
+
18
+ before_fork do |server, worker|
19
+ defined?(ActiveRecord::Base) and
20
+ ActiveRecord::Base.connection.disconnect!
21
+ end
22
+
23
+ after_fork do |server, worker|
24
+ worker.user('www-data', 'www-data') if Process.euid == 0
25
+
26
+ defined?(ActiveRecord::Base) and
27
+ ActiveRecord::Base.establish_connection
28
+ end
29
+
30
+ before_exec do |server|
31
+ # Configure bundler to use proper paths if app provides a Gemfile
32
+ if(File.exists?("#{current_path}/Gemfile"))
33
+ paths = ENV["PATH"].to_s.split(':')
34
+ paths.unshift "#{shared_bundler_gems_path}/bin"
35
+ ENV["PATH"] = paths.uniq.join(':')
36
+
37
+ ENV['GEM_HOME'] = ENV['GEM_PATH'] = shared_bundler_gems_path
38
+ ENV['BUNDLE_GEMFILE'] = "#{current_path}/Gemfile"
39
+ end
40
+ end
@@ -0,0 +1,50 @@
1
+ # Simple Role Syntax
2
+ # ==================
3
+ # Supports bulk-adding hosts to roles, the primary server in each group
4
+ # is considered to be the first unless any hosts have the primary
5
+ # property set. Don't declare `role :all`, it's a meta role.
6
+
7
+ set :domain, "my-app-staging.example.com"
8
+ set :deploy_username, "deployer"
9
+ set :user_host, "#{fetch(:deploy_username)}@#{fetch(:domain)}"
10
+
11
+ role :app, fetch(:user_host)
12
+ role :web, fetch(:user_host)
13
+ role :db, fetch(:user_host)
14
+
15
+ # Extended Server Syntax
16
+ # ======================
17
+ # This can be used to drop a more detailed server definition into the
18
+ # server list. The second argument is a, or duck-types, Hash and is
19
+ # used to set extended properties on the server.
20
+
21
+ #server 'example.com', user: 'deploy', roles: %w{web app}, my_property: :my_value
22
+
23
+
24
+ # Custom SSH Options
25
+ # ==================
26
+ # You may pass any option but keep in mind that net/ssh understands a
27
+ # limited set of options, consult[net/ssh documentation](http://net-ssh.github.io/net-ssh/classes/Net/SSH.html#method-c-start).
28
+ #
29
+ # Global options
30
+ # --------------
31
+ # set :ssh_options, {
32
+ # keys: %w(/home/rlisowski/.ssh/id_rsa),
33
+ # forward_agent: false,
34
+ # auth_methods: %w(password)
35
+ # }
36
+ #
37
+ # And/or per server (overrides global)
38
+ # ------------------------------------
39
+ # server 'example.com',
40
+ # user: 'user_name',
41
+ # roles: %w{web app},
42
+ # ssh_options: {
43
+ # user: 'user_name', # overrides user setting above
44
+ # keys: %w(/home/user_name/.ssh/id_rsa),
45
+ # forward_agent: false,
46
+ # auth_methods: %w(publickey password)
47
+ # # password: 'please use keys'
48
+ # }
49
+
50
+ require './config/deploy/staging_deployinator.rb'
@@ -0,0 +1,17 @@
1
+ set :rails_env, 'production' # If the environment differs from the stage name
2
+ set :migration_role, 'app' # Defaults to 'db'
3
+ #set :conditionally_migrate, true # Defaults to false. If true, it's skip migration if files in db/migrate not modified
4
+ set :assets_roles, [:app] # Defaults to [:web]
5
+ #set :assets_prefix, 'prepackaged-assets' # Defaults to 'assets' this should match config.assets.prefix in your rails config/application.rb
6
+
7
+ # If you are using nginxinator and postgresinator, your settings would look similar to this:
8
+ set :nginx_container_name, "my-app-staging.example.com-nginx-80-443"
9
+ set :external_socket_path, "/my-app-staging.example.com-nginx-80-443-conf/run"
10
+ set :internal_socket_path, "/var/run/unicorn"
11
+ set :postgres_container_name, "my-app-staging.example.com-postgres-5432-master"
12
+ set :postgres_port, "5432"
13
+ set :ruby_image_name, "snarlysodboxer/ruby:1.9.3-p547"
14
+ set :ruby_container_name, "my-app-staging.example.com-ruby-bluepill"
15
+ set :ruby_container_max_mem_mb, "1024"
16
+ set :bundler_version, "1.7.4"
17
+ #set :use_cadvisor, true # this is default
@@ -0,0 +1,63 @@
1
+ # config valid only for Capistrano 3.1
2
+ lock '3.2.1'
3
+
4
+ set :application, 'my_app_name'
5
+ set :repo_url, 'git@example.com:me/my_repo.git'
6
+
7
+ ## Don't ask this here, only in staging or other non-production <stage>.rb files.
8
+ # Default branch is :master
9
+ # ask :branch, proc { `git rev-parse --abbrev-ref HEAD`.chomp }.call
10
+
11
+ # Default deploy_to directory is /var/www/my_app
12
+ # set :deploy_to, '/var/www/my_app'
13
+
14
+ # Default value for :scm is :git
15
+ # set :scm, :git
16
+
17
+ # Default value for :format is :pretty
18
+ # set :format, :pretty
19
+
20
+ # Default value for :log_level is :debug
21
+ # set :log_level, :debug
22
+
23
+ # Default value for :pty is false
24
+ # set :pty, true
25
+
26
+ # Default value for :linked_files is []
27
+ # set :linked_files, %w{config/database.yml}
28
+
29
+ # Default value for linked_dirs is []
30
+ # set :linked_dirs, %w{bin log tmp/pids tmp/cache tmp/sockets vendor/bundle public/system}
31
+ set :linked_dirs, %w{log tmp}
32
+
33
+ # Default value for default_env is {}
34
+ # set :default_env, { path: "/opt/ruby/bin:$PATH" }
35
+
36
+ # Default value for keep_releases is 5
37
+ # set :keep_releases, 5
38
+
39
+ namespace :deploy do
40
+
41
+ ### No need to do anything here, deployinator defines this task.
42
+ desc 'Restart application'
43
+ task :restart do
44
+ on roles(:app), in: :sequence, wait: 5 do
45
+ # Your restart mechanism here, for example:
46
+ # execute :touch, release_path.join('tmp/restart.txt')
47
+ end
48
+ end
49
+
50
+ after :publishing, :restart
51
+
52
+ after :restart, :clear_cache do
53
+ on roles(:web), in: :groups, limit: 3, wait: 10 do
54
+ # Here we can do anything such as:
55
+ # within release_path do
56
+ # execute :rake, 'cache:clear'
57
+ # end
58
+ end
59
+ end
60
+
61
+ end
62
+
63
+ require './config/deploy_deployinator.rb'
@@ -0,0 +1,56 @@
1
+ # Use `cap <stage> deploy from_local=true` to deploy your
2
+ # locally changed code instead of the code in the git repo. You can also add --trace.
3
+ if ENV['from_local']
4
+ set :scm, :copy
5
+ else
6
+ set :scm, :git
7
+ end
8
+
9
+ # Always use the master branch in production:
10
+ set :current_stage, -> { fetch(:stage).to_s.strip }
11
+ unless fetch(:current_stage) == "production"
12
+ ask :branch, proc { `git rev-parse --abbrev-ref HEAD`.chomp }.call
13
+ end
14
+
15
+ ## The values in this file are not meant to be changed and shouldn't
16
+ ## need to be under the majority of circumstances:
17
+
18
+ #set :bundle_roles, :all # this is default
19
+ #set :bundle_servers, -> { release_roles(fetch(:bundle_roles)) } # this is default
20
+ #set :bundle_binstubs, -> { shared_path.join('bin') } # this is default
21
+ set :bundle_binstubs, -> { shared_path.join('bundle', 'bin') } # this is required for deployinator
22
+ set :bundle_gemfile, -> { release_path.join('Gemfile') } # this is required for deployinator
23
+ #set :bundle_path, -> { shared_path.join('bundle') } # this is default
24
+ #set :bundle_without, %w{development test}.join(' ') # this is default
25
+ set :bundle_without, %w{development test deployment}.join(' ')
26
+ #set :bundle_flags, '--deployment --quiet' # this is default
27
+ #set :bundle_flags, '--deployment'
28
+ #set :bundle_env_variables, {} # this is default
29
+
30
+ set :docker_run_bluepill_command, -> { [
31
+ "--tty", "--detach",
32
+ "--name", fetch(:ruby_container_name),
33
+ "-e", "GEM_HOME=#{fetch(:deploy_to)}/shared/bundle",
34
+ "-e", "GEM_PATH=#{fetch(:deploy_to)}/shared/bundle",
35
+ "-e", "BUNDLE_GEMFILE=#{fetch(:deploy_to)}/current/Gemfile",
36
+ "-e", "PATH=#{fetch(:deploy_to)}/shared/bundle/bin:$PATH",
37
+ "--link", "#{fetch(:postgres_container_name)}:postgres",
38
+ "--volume", "#{fetch(:deploy_to)}:#{fetch(:deploy_to)}:rw",
39
+ "--volume", "#{fetch(:external_socket_path)}:#{fetch(:internal_socket_path)}:rw",
40
+ "--entrypoint", "#{fetch(:deploy_to)}/shared/bundle/bin/bluepill",
41
+ "--restart", "always", "--memory", "#{fetch(:ruby_container_max_mem_mb)}m",
42
+ fetch(:ruby_image_name), "load",
43
+ "#{fetch(:deploy_to)}/current/config/#{fetch(:application)}_bluepill.rb"
44
+ ] }
45
+
46
+ set :docker_run_cadvisor_command, -> { [
47
+ "--detach",
48
+ "--name", "cadvisor",
49
+ "--volume", "/:/rootfs:ro",
50
+ "--volume", "/var/run:/var/run:rw",
51
+ "--volume", "/sys:/sys:ro",
52
+ "--volume", "/var/lib/docker/:/var/lib/docker:ro",
53
+ "--publish", "127.0.0.1:8080:8080",
54
+ "--restart", "always",
55
+ "google/cadvisor:latest"
56
+ ] }
@@ -0,0 +1 @@
1
+ # Add your keys here:
metadata CHANGED
@@ -1,18 +1,20 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: deployinator
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.0
4
+ version: 0.0.1
5
+ prerelease:
5
6
  platform: ruby
6
7
  authors:
7
8
  - david amick
8
9
  autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
11
- date: 2014-09-11 00:00:00.000000000 Z
12
+ date: 2014-11-10 00:00:00.000000000 Z
12
13
  dependencies:
13
14
  - !ruby/object:Gem::Dependency
14
15
  name: capistrano
15
16
  requirement: !ruby/object:Gem::Requirement
17
+ none: false
16
18
  requirements:
17
19
  - - '='
18
20
  - !ruby/object:Gem::Version
@@ -20,6 +22,7 @@ dependencies:
20
22
  type: :runtime
21
23
  prerelease: false
22
24
  version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
23
26
  requirements:
24
27
  - - '='
25
28
  - !ruby/object:Gem::Version
@@ -33,28 +36,38 @@ files:
33
36
  - lib/deployinator.rb
34
37
  - lib/deployinator/deploy.rb
35
38
  - lib/deployinator/config.rb
36
- homepage: http://rubygems.org/gems/deployinator
39
+ - lib/deployinator/examples/Capfile
40
+ - lib/deployinator/examples/config/deploy.rb
41
+ - lib/deployinator/examples/config/deploy_deployinator.rb
42
+ - lib/deployinator/examples/config/deploy/staging.rb
43
+ - lib/deployinator/examples/config/deploy/staging_deployinator.rb
44
+ - lib/deployinator/examples/Dockerfile
45
+ - lib/deployinator/examples/deployer_authorized_keys.erb
46
+ - lib/deployinator/examples/application_unicorn.rb.erb
47
+ - lib/deployinator/examples/application_bluepill.rb.erb
48
+ homepage: https://github.com/snarlysodboxer/deployinator
37
49
  licenses:
38
- - MIT
39
- metadata: {}
50
+ - GNU
40
51
  post_install_message:
41
52
  rdoc_options: []
42
53
  require_paths:
43
54
  - lib
44
55
  required_ruby_version: !ruby/object:Gem::Requirement
56
+ none: false
45
57
  requirements:
46
- - - '>='
58
+ - - ! '>='
47
59
  - !ruby/object:Gem::Version
48
60
  version: '0'
49
61
  required_rubygems_version: !ruby/object:Gem::Requirement
62
+ none: false
50
63
  requirements:
51
- - - '>='
64
+ - - ! '>='
52
65
  - !ruby/object:Gem::Version
53
66
  version: '0'
54
67
  requirements: []
55
68
  rubyforge_project:
56
- rubygems_version: 2.0.2
69
+ rubygems_version: 1.8.23.2
57
70
  signing_key:
58
- specification_version: 4
71
+ specification_version: 3
59
72
  summary: Deploy Applications
60
73
  test_files: []
checksums.yaml DELETED
@@ -1,7 +0,0 @@
1
- ---
2
- SHA1:
3
- metadata.gz: 1118ca9720569f14d4453a2d96561b65395362f8
4
- data.tar.gz: 1d9079e7d2e1a79ec2a612f2c47a0d14355a017a
5
- SHA512:
6
- metadata.gz: a6fa60095a8adaa33144331cade009a5493def8f046f0d7d49c95bab97c0ecf686fce20c85efca467f67b79372b884ea9017b9e1aeaaab5ffc38b6a2a980457c
7
- data.tar.gz: 9b8bf3e88297d083a9ef13de344a5b76455a23cf277a1d07c2a3fc961563eb148fedecd4fd9b0abc9744637fef53d7eca112424d978c51633a73b551e8c4874e