Capistrano 部署的原理和 Deployer 是一樣的,@overtrue 大神寫了一篇關於 delopyer 攻略,裡面講的操作原理,伺服器端使用者配置,允許訪問 git 倉庫和免密碼登入的基本知識可以先了解下。
這篇文章主要詳細介紹下 capistrano 的具體用法:
結構
Capistrano 部署成功後的程式碼檔案結構是像這樣的:
├── current -> /var/www/app_name/releases/20180120114500/
├── releases
│ |----- 20180080072500
│ |----- 20180090083000
│ |----- 20180100093500
│ |----- 20180110104000
│ |----- 20180120114500
├── repo
│ |----- <VCS related data>
├── revisions.log
└── shared
|----- <linked_files and linked_dirs>
current, releases,shared 的含義和 deployer 的是一樣的,版本是按時間排序的,repo 裡包含了 VCS 的資訊,比如 git 或者 svn,revisions.log 日誌記載了每一次部署和 rollback 的詳細資訊。
流程
deploy:starting - 開始部署 確認一切就緒
deploy:started - started hook (自定義任務)
deploy:updating - 更新伺服器
deploy:updated - updated hook
deploy:publishing - 釋出新的部署
deploy:published - published hook
deploy:finishing - 結束部署
deploy:finished - finished hook
安裝
推薦使用 RVM 去安裝 ruby,最大的好處在於你可以安裝不同的版本,而且能夠在版本中隨意切換。
\curl -sSL https://get.rvm.io | bash -s stable(安裝 rvm)
安裝完後,可以執行 source ~/.rvm/scripts/rvm 或者重開 shell window 啟用 rvm。
rvm list known(檢視版本)
rvm install 2.5(安裝 ruby 2.5)
gem install capistrano(安裝 capistrano,gem 類似於 composer)
配置
我一般會在專案的根目錄下新建一個 deployment 資料夾,然後執行 cap install
,這個命令會建立以下的配置檔案:
├── Capfile
├── config
│ ├── deploy
│ │ ├── production.rb
│ │ └── staging.rb
│ └── deploy.rb
└── lib
└── capistrano
└── tasks
首先,看一下 Capfile,預設的配置即可,不需做太大修改。因為本文例子中 tasks 會定義在 deploy.rb 中,所以 lib 資料夾用不到,可以忽略。
# 載入 DSL 和設定 stages
require "capistrano/setup"
# 載入預設的部署任務
require "capistrano/deploy"
# 載入 SCM git 外掛:
require "capistrano/scm/git"
install_plugin Capistrano::SCM::Git
# 載入自定義任務 `lib/capistrano/tasks`
# Dir.glob("lib/capistrano/tasks/*.rake").each { |r| import r }
其次,deploy.rb 中的基本配置如下,每個配置我做了簡單的註釋:
# 設定 capistrano 版本
lock "~> 3.11.0"
# 設定專案名稱
set :application, 'app_name'
# 設定伺服器上的部署路徑
set :deploy_to, '/var/www/app_name'
# 設定 git 倉庫的 url
set :repo_url, 'git@github.com:username/app_name.git'
# 設定部署版本保持的個數
set :keep_releases, 5
# 設定日誌 level
set :log_level, :debug
# 設定樣式,美化 Capistrano 在命令列的輸出
set :format, :airbrussh
# 設定 ssh 使用的 key,免密碼登入
set :ssh_options, {
keys: %w(~/.ssh/id_rsa)
}
如果你需要在伺服器上編譯資源,可以設定環境變數,比如載入 nodejs 的路徑:
set :default_env, {
path: "/home/deployer/.nvm/versions/node/v10.9.0/bin:$PATH"
}
順便提一下,無論在 MAC 還是伺服器上,可以使用 NVM 安裝 nodejs,這個和 ruby 的 RVM 是一樣的,讓你安裝不同的 nodejs 和 npm 的版本,而且很容易切換。
下面就是比較重要的 shared 的檔案和資料夾,用來儲存版本之間共享的檔案:
set :linked_files, %w{.env}
set :linked_dirs, %w{
vendor
storage
storage/app/public
storage/framework/cache
storage/framework/sessions
storage/framework/testing
storage/framework/views
storage/logs
}
然後,定義一些常用的任務,比如:
namespace :app do
task :up do
on roles(:app), in: :sequence, wait: 5 do
within release_path do
execute :php, :artisan, "up"
end
end
end
task :down do
on roles(:app), in: :sequence, wait: 5 do
within release_path do
execute :php, :artisan, "down"
end
end
end
......
end
定義這些任務後,就可以本地執行 php artisan
命令,例如 cap staging app:down
就可以把伺服器上的網站設定為維護模式。再以快取為例子,在 namespace cache 下可以定義以下任務:
namespace :cache do
task :clear do
on roles(:app), in: :sequence, wait: 5 do
within release_path do
execute :php, :artisan, "cache:clear"
execute :php, :artisan, "view:clear"
execute :php, :artisan, "route:clear"
execute :php, :artisan, "config:clear"
end
end
end
task :route do
on roles(:app), in: :sequence, wait: 5 do
within release_path do
execute :php, :artisan, "route:cache"
end
end
end
task :config do
on roles(:app), in: :sequence, wait: 5 do
within release_path do
execute :php, :artisan, "config:cache"
end
end
end
task :refresh do
invoke('cache:clear')
invoke('cache:route')
invoke('cache:config')
end
end
所有的 php artisan 命令你都可以歸類寫成 task,放在 lib/capistrano/tasks
下,我們就簡單放在 deploy.rb 裡了。
接著 deploy 的配置:
namespace :deploy do
desc "Run Composer Install"
task :composer_install do
on roles(:app), in: :sequence, wait: 5 do
within release_path do
execute :composer, "install --prefer-dist --no-dev --optimize-autoloader"
end
end
end
desc "Run Migration"
task :migrate do
on roles(:app), in: :sequence, wait: 5 do
within release_path do
execute :php, "artisan migrate --no-interaction --force"
end
end
end
desc "Run NPM Scripts"
task :npm_scripts do
on roles(:app), in: :sequence, wait: 5 do
within release_path do
execute :npm, "install"
execute :npm, "run production"
end
end
end
desc "Restart PHP FPM"
task :restart_php_fpm do
on roles(:app), in: :sequence, wait: 5 do
within release_path do
execute :sudo, :service, "php7.2-fpm restart"
end
end
end
after :updated, "deploy:composer_install"
after :updated, "deploy:migrate"
after :updated, "deploy:npm_scripts"
after :published, "deploy:restart_php_fpm"
end
這裡需要注意的是,部署不需要重啟 apache 或者 nginx,不過需要重啟 php-fpm,這就需要給伺服器使用者 deployer 重啟 php-fpm 的許可權,安全起見,請僅給予重啟 php-fpm 的許可權:sudo visudo
deployer ALL=(ALL:ALL) NOPASSWD:/usr/sbin/service php7.2-fpm restart
。
最後,deploy/staging.rb 中的配置如下:
set :stage, :staging
set :branch, 'develop'
server '{server_ip_address}', user: 'deployer', roles: %w{app}
set :app_env, 'staging'
這樣每次部署到測試伺服器時,只需要本地執行 cap staging deploy
就可以,production 的配置類似。部署是需要一段時間的,不過只有最終成功的時候,伺服器上才會更新 symlink,指向最新的版本,所以基本上是沒有 downtime 的。
本作品採用《CC 協議》,轉載必須註明作者和本文連結