攻略 - Capistrano 部署 Laravel 專案

jltxwesley發表於2018-09-06

file
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 的。

相關文章