[转]Blue-Green Deployment using Containers

Blue-Green Deployment using Containers


lb:
image: 'tutum/haproxy:latest'
restart: always
links:
- web-green
ports:
- '80:80'
roles:
- global

web-green:
image: 'borja/bluegreen:v1'
restart: always
target_num_containers: 3
deployment_strategy: high_availability

web-blue:
image: 'borja/bluegreen:v1'
restart: always
target_num_containers: 1
deployment_strategy: high_availability

Advertisements

How to Deploy a Rails App on Ubuntu with Capistrano, Nginx, and Puma

Environment

  • Ruby: 2.3.1
  • Rails: 5.0.0
  • Capistrano: 3.8.1
  • Nginx: 1.10.0
  • Puma: 3.9.1

Tutorial

https://www.digitalocean.com/community/tutorials/deploying-a-rails-app-on-ubuntu-14-04-with-capistrano-nginx-and-puma

Initial Server Setup with Ubuntu 16.04

Create deploy user.

https://www.digitalocean.com/community/tutorials/initial-server-setup-with-ubuntu-16-04

How To Install and Use PostgreSQL on Ubuntu 16.04

https://www.digitalocean.com/community/tutorials/how-to-install-and-use-postgresql-on-ubuntu-16-04


Gemfile

group :development do
gem 'capistrano', require: false
gem 'capistrano-rvm', require: false
gem 'capistrano-rails', require: false
gem 'capistrano-bundler', require: false
gem 'capistrano3-puma', require: false
gem 'capistrano3-nginx', require: false
gem 'capistrano-npm', require: false
end

Run bundle install and cap install

$ bundle install
$ cap install

Capfile

require "capistrano/setup"
require "capistrano/deploy"
require "capistrano/scm/git"
install_plugin Capistrano::SCM::Git
require "capistrano/rvm
require "capistrano/bundler"
require "capistrano/rails/assets"
require "capistrano/rails/migrations"
require 'capistrano/nginx'
require "capistrano/puma"
install_plugin Capistrano::Puma
require 'capistrano/npm'
Dir.glob("lib/capistrano/tasks/*.rake").each { |r| import r }

config/deploy.rb

# config valid only for current version of Capistrano
lock "3.8.1"

server '192.168.0.1', port: 22, roles: [:web, :app, :db], primary: true

set :application, "testapp"
set :repo_url, "git@github.com:username/testapp.git"
set :user, 'deploy'
set :puma_threads, [4, 16]
set :puma_workers, 0

set :pty, true
set :use_sudo, false
set :stage, :production
set :deploy_via, :remote_cache
set :deploy_to, "/home/#{fetch(:user)}/apps/#{fetch(:application)}"
set :puma_bind, "unix://#{shared_path}/tmp/sockets/#{fetch(:application)}-puma.sock"
set :puma_state, "#{shared_path}/tmp/pids/puma.state"
set :puma_pid, "#{shared_path}/tmp/pids/puma.pid"
set :puma_access_log, "#{release_path}/log/puma.error.log"
set :puma_error_log, "#{release_path}/log/puma.access.log"
set :ssh_options, { forward_agent: true, user: fetch(:user), keys: %w(~/.ssh/id_rsa.pub) }
set :puma_preload_app, true
set :puma_worker_timeout, nil
set :puma_init_active_record, true # Change to false when not using ActiveRecord

set :nginx_template, "/home/#{fetch(:user)}/apps/#{fetch(:application)}/current/config/nginx.conf"
set :nginx_sites_enabled_dir, "/etc/nginx/sites-enabled"

set :npm_target_path, -> { release_path.join('client') }

## Defaults:
# set :scm, :git
# set :branch, :master
# set :format, :pretty
# set :log_level, :debug
# set :keep_releases, 5

## Linked Files & Directories (Default None):
# set :linked_files, %w{config/database.yml}
# set :linked_dirs, %w{bin log tmp/pids tmp/cache tmp/sockets vendor/bundle public/system}

namespace :puma do
desc 'Create Directories for Puma Pids and Socket'
task :make_dirs do
on roles(:app) do
execute "mkdir #{shared_path}/tmp/sockets -p"
execute "mkdir #{shared_path}/tmp/pids -p"
end
end

before :start, :make_dirs
end

namespace :deploy do
desc "Make sure local git is in sync with remote."
task :check_revision do
on roles(:app) do
unless `git rev-parse HEAD` == `git rev-parse origin/master`
puts "WARNING: HEAD is not the same as origin/master"
puts "Run `git push` to sync changes."
exit
end
end
end

desc 'Initial Deploy'
task :initial do
on roles(:app) do
before 'puma:start'
invoke 'deploy'
end
end

desc 'npm install && webpack build'
task :npm_webpack do
on roles(:app) do
invoke 'npm:install'
execute "cd '#{release_path}'; npm --prefix client run webpack-build"
end
end

desc 'Nginx link'
task :nginx_link do
on roles(:app) do
execute "sudo rm -rf #{fetch(:nginx_sites_enabled_dir)}/default"
execute "sudo ln -nfs #{fetch(:nginx_template)} #{fetch(:nginx_sites_enabled_dir)}/#{fetch(:application)}"
invoke 'nginx:restart'
end
end

before :starting, :check_revision
after :finishing, :compile_assets
after :finishing, :npm_webpack
after :finishing, :nginx_link
after :finishing, :cleanup
end

config/nginx.conf

upstream puma {
server unix:///home/deploy/apps/testapp/shared/tmp/sockets/testapp-puma.sock;
}

server {
listen 80 default_server deferred;
# server_name example.com;

root /home/deploy/apps/testapp/current/public;
access_log /home/deploy/apps/testapp/current/log/nginx.access.log;
error_log /home/deploy/apps/testapp/current/log/nginx.error.log info;

location ^~ /assets/ {
gzip_static on;
expires max;
add_header Cache-Control public;
}

try_files $uri/index.html $uri @puma;
location @puma {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;

proxy_pass http://puma;
}

error_page 500 502 503 504 /500.html;
client_max_body_size 10M;
keepalive_timeout 10;
}