情境
一個 Rails 專案,有三台機器,每次部屬分別要手動部屬,但其實這個可以做自動化
三台機器分別是不同的權限使用但都吃同一個專案,並非 load balance 那種情況
這邊我只用自己的電腦來做,所以這三台機器都分別要放上自己的 ssh public key
滑順遷移(Zero downtime)
為了避免線上的服務被中斷,我在遷移時會這樣做
假設線上專案名稱為 awesome_app
,以下為步驟
- 先建立一個和原本 app 同目錄層級的新資料夾,這裡我取名為
awesome_app_capistrano
- 把部屬的資料夾設定
set :deploy_to, "/home/user/awesome_app_capistrano"
(晚點在改回來) - 用
cap production deploy:check
去做資料夾的建立並同時把需要放到shared/
下的設定檔搬移 - 然後嘗試 deploy 一次,如果沒問題就繼續往下做
- 將 Nginx server 的設定
/etc/nginx/site-enable/your_app
從原本的/home/user/awesome/public
替換成/home/user/awesome/current/public
- 把當前的
awesome_app
資料夾名稱更改為awesome_app_backup
備用(請勿直接刪除,避免有東西沒搬好或突然想復原) - 把
awesome_app_capistrano
改為awesome_app
- 本機執行完整的 deploy 指令
cap production deploy
(記得部屬資料夾要改回原本的awesome_app
) - Nginx 重開
service nginx restart
- 檢查 crontab 裡面有沒有指令是跑在舊的路徑
- 檢查 logrotate 下的所有檔案,有沒有跑舊的路徑
- 將
awesome_app_backup
下的/log
搬去awesome_app/shared/log
- 完成 Capistrano 的遷移
檢查清單
參考設定
# config/deploy.rb
lock "~> 3.11.0"
set :application, "awesome_app"
set :repo_url, "ssh://awesome_app.git"
set :branch, "master"
set :whenever_roles, -> { [:db] }
set :whenever_environment, fetch(:stage)
set :deploy_to, "/home/user/awesome_app"
append :linked_files, "config/database.yml", "config/secrets.yml"
append :linked_dirs, "log", "tmp/pids", "tmp/cache", "tmp/sockets", "public/system"
set :keep_releases, 5
set :passenger_restart_with_touch, true
這裡筆記一下
有 :app
會跑 Server restart 有 :web
會跑 Asset task 有 :db
會跑 Database migrate
# config/deploy/production.rb
ADMIN = "1.2.3.4"
WEB_API = "5.6.7.8"
AGENT = "9.10.11.12"
role :app, [ADMIN, WEB_API, AGENT]
role :web, [ADMIN, WEB_API, AGENT]
role :db, [ADMIN], primary: true