deployer 實戰經驗分享

開發完項目,免不了要部署上線。純手動操做,登陸、拉代碼、改配置、清緩存、各類服務重啓等等一條龍下來,人生寶貴的幾分鐘就過去了。並且手動操做十分容易出錯,遺漏部分步驟都有可能產生一些邪門問題。因此我很早就開始尋求一種能輕鬆部署 Laravel 項目的辦法。php

laravel 的官方文檔裏介紹了 Envoy,以前用過,能知足大部分場景,但仍然有一些限制。直到後來看到了 deployer,大有相見恨晚之感!前端

deployer 的優點

  1. 真正解放雙手,一條命令完成部署。
  2. 進行部署的過程當中,項目仍然可以正常訪問。部署成功完成後才切到新的版本。
  3. 能十分方便地進行回滾。
  4. 豐富任務鉤子和預置任務可靈活的組合完成各類任務,好比執行前端依賴的安裝、構建等。
  5. 其它騷姿式等你發掘……

使用 deployer 的前提條件

  • 本地機器(也就是你執行 dep 命令時所在的機器)可以 SSH 鏈接到目標機器(代碼要部署到的機器,不論是在線的雲主機仍是局域網中的虛擬機)
  • 有登陸目標機器並調整一些設置的權限,或者能讓負責人協助調整。(使用過程當中可能遇到問題須要調整一些設置,後面會提)
  • 目標主機有拉取項目倉庫的權限。(這個應該都有吧,否則玩個毛?)
  • 足夠大膽、足夠細心、足夠有耐性……

deployer 的使用

首先說明下我的實際使用場景。nginx

本人使用 win10 系統,使用 Homestead 做爲 PHP 項目的開發環境(vagrant v2.1.1, homestead v7.4.1, virtualbox v5.2.8, homestead 的 virtual box 版本爲 v5.2)。laravel

本地開發能完成絕大部分開發和測試任務,但在部署到生產機以前仍然須要先部署到開發機上進行測試。線上測試與生產使用的是青雲的雲主機,Ubuntu16 系統。git

如下的操做都是在 homestead 虛擬機裏進行操做!
  1. 安裝
cd /path/to/your/project

composer require deployer/deployer --dev
我的習慣於將其做爲項目依賴安裝,固然也能夠根據須要或我的喜愛全局安裝。
  1. 初始化 deployer 配置文件
vendor/bin/dep init

由於我用的是 laravel 輸入項目類型 1 後回車,而後會出現一個讓設置 git 倉庫的,默認是對應項目的 git 遠端倉庫,不須要修改的話確認就能夠了。github

deploy_init

完成上面的初始化後,項目要目錄下會出現一個 deploy.php 文件,deployer 的配置就靠它了。初始的配置以下,裏面顯示了一些基本的配置。web

<?php
namespace Deployer;

require 'recipe/laravel.php';

// Project name
// 項目名
set('application', 'my_project');

// Project repository
// 項目倉庫地址不解釋
set('repository', 'git@github.com:tianyong90/xxx.git');

// [Optional] Allocate tty for git clone. Default value is false.
set('git_tty', true); 

// Shared files/dirs between deploys 
// 分享文件即目錄,一般也不用改,默認包含了 storage 目錄
add('shared_files', []);
add('shared_dirs', []);

// Writable dirs by web server 
// 可寫目錄,通常不用改
add('writable_dirs', []);


// Hosts
// 目標主機配置,這是最基本的
host('project.com')
    ->set('deploy_path', '~/{{application}}');    
    
// Tasks
// 這算是個自定義任務示例
task('build', function () {
    run('cd {{release_path}} && build');
});

// [Optional] if deploy fails automatically unlock.
// 若是部署失敗,自動解除部署鎖定狀態,以避免影響下次執行
after('deploy:failed', 'deploy:unlock');

// Migrate database before symlink new release.
// 執行數據庫遷移,建議刪掉,遷移雖好,但畢竟高風險,只推薦用於開發環境。
before('deploy:symlink', 'database:migrate');
  1. 修改配置

默認的配置確定是不行的,目標主機啥的還不知道呢。下面直接貼上本身用到的配置,並加入了少許說明。redis

<?php

namespace Deployer;

require 'recipe/laravel.php';

// Project name
set('application', 'xxx');

// Project repository
set('repository', 'git@github.com:tianyong90/xxx.git');

// [Optional] Allocate tty for git clone. Default value is false.
set('git_tty', true);

// Shared files/dirs between deploys
add('shared_files', []);
add('shared_dirs', []);

// Writable dirs by web server
add('writable_dirs', []);

// 保存最近五次部署,這樣的話回滾最多也只能回滾到前 5 個版本
set('keep_releases', 5);

// 實踐證實,這樣能減小一些沒必要要的麻煩,如出現權限相關的問題,也可將此項設置爲 true 後嘗試
set('writable_use_sudo', false);

// 生產用的主機
host('172.16.1.1')
    ->stage('production')
    ->user('root')
    ->port(22)
    ->set('branch', 'master') // 最新的主分支部署到生產機
    ->set('deploy_path', '/data/wwwroot/xxx')
    ->identityFile('/home/vagrant/.ssh/id_rsa')
    ->forwardAgent(true)
    ->multiplexing(true)
    ->set('http_user', 'www') // 這個與 nginx 裏的配置一致
    ->addSshOption('UserKnownHostsFile', '/dev/null')
    ->addSshOption('StrictHostKeyChecking', 'no');

// 測試用的主機
host('172.16.3.2')
    ->stage('debug')
    ->user('root')
    ->port(22)
    ->set('branch', 'develop') // 通常是把 develop 分支弄到測試機測試,沒問題再合併
    ->set('deploy_path', '/data/wwwroot/xxx')
    ->identityFile('/home/vagrant/.ssh/id_rsa')
    ->forwardAgent(true)
    ->multiplexing(true)
    ->set('http_user', 'www')
    ->addSshOption('UserKnownHostsFile', '/dev/null')
    ->addSshOption('StrictHostKeyChecking', 'no');

// 自定義任務:重置 opcache 緩存
task('opcache_reset', function () {
    run('{{bin/php}} -r \'opcache_reset();\'');
});

// 自定義任務:重啓 php-fpm 服務
task('php-fpm:restart', function () {
    run('systemctl restart php-fpm.service');
});

// 自定義任務:supervisor reload
task('supervisor:reload', function () {
    run('sudo supervisorctl reload');
});

// 自定義任務:部署成功了用 bearychat 發消息給大佬和本身
task('send_message', function () {
    run('{{bin/php}} {{release_path}}/artisan deployed');
});

// 自定義任務:緩存路由,recipe/laravel.php 默認的流程裏沒有這個,因此加上,息看須要
after('artisan:config:cache', 'artisan:route:cache');

// 執行自定義任務,注意時間點是 current 已經成功鏈向新部署的目錄以後
after('deploy:symlink', 'php-fpm:restart');
after('deploy:symlink', 'supervisor:reload');

// 部署成功後重置 opcache 緩存
after('deploy:symlink', 'opcache_reset');

// 部署成功後調用 laravel 命令行發送通知
after('success', 'send_message');

// [Optional] if deploy fails automatically unlock.
after('deploy:failed', 'deploy:unlock');
  1. 代碼修改完成後運行部署

修改完成後記得先提交併將代碼推送到遠端倉庫。而後執行以下命令進行部署:數據庫

vendor/bin/dep deploy debug // 部署到測試機

vendor/bin/dep deploy production // 部署到生產機

過程當中若是提示要輸入密碼,則輸入登陸目標主機的密碼。或者想辦法設置 SSH key 實現免密碼登陸。緩存

  1. 首次部署後設置 .env,並配置 nginx 站點

默認狀況下,首次部署後,.env 文件是不會自動建立的,須要本身建立並修改,同時 nginx 站點配置也須要本身動手。對於 .env 文件,存放於目標主機的 /path/to/project/shared/ 目錄下。

修改 .env 後記得從新緩存配置 php artisan config:cache

另外須要注意的是配置 nginx 站點時,網站根目錄應該爲 /path/to/project/current/public。若是使用 supervisor 之類的,相關的目錄在配置時也要注意了。

部署後目錄的結構及相關說明

在部署的目標目錄下執行 ls -la,能夠看到以下結果:

deploy_init

說明:

| projectname
    |--- @current -> releases/<num>
    |--- .dep
        |--- releases 一個文本文件,裏面存着各次部署的時間、次數序號(或者說版本號)信息
    |--- releases // 目錄下根據配置保存近幾回部署,更早的則會被自動清理
        |--- 1
        |--- 2
        |--- .
        |--- .
        |--- <num>
            |--- 目錄中是項目的實際代碼
            |--- 包括 .git, vendor, .env, storage ...
            |---  .env, storage 實際經過 symlink 連接到 shared 目錄下對應的文件上
    |--- shared
        |--- storage // 即 laravel 項目的 storage 文件夾
        |--- .env // 即 laravel 項目的 .env

每次部署更新,會在 releases 下新建文件夾如 num,拉取對應的最新代碼,安裝 composer 依賴完成一些其它自定義任務,並將 storage, .env 連接到 shared 文件夾下的那兩個上去,而後項目根目錄下的 current 經過 syslink 連接到這個新文件夾 num 上,這算是其動做的基本原理,網站在部署過程當中能繼續訪問也得益於此。

.env 和 storage 下的一些未加入代碼庫中的內部,部署時不會自動更新,所以有些狀況下須要手動處理。

其它平常使用技巧

正常狀況下,部署過程當中 deployer 會自動完成緩存配置、清理已編譯的緩存等任務。理論上咱們不須要本身再動手,但須要時也能夠手動執行

// 緩存路由
vendor\bin\dep artisan:route:cache production

// 緩存配置
vendor\bin\dep artisan:config:cache production

// 清視圖緩存
vendor\bin\dep artisan:view:clear production

// 執行自定義任務,如前面提到的從新載入 supervisor
vendor\bin\dep supervisor:reload production

// ssh 鏈接到主機,hostname 也能夠不輸入,而後從選項裏選
vendor\bin\dep ssh <hostname>

// 列出其它一些可用的命令
vendor\bin\dep list

可能遇到的問題

在 deploy 命令後加上 -vvv 選項能夠輸出詳細錯誤信息,方便調試。
  1. 因爲部分 php 函數被禁用而報錯

目標主機 php.ini 裏的 disabled_functions 項裏配置了一些被禁用的函數,若是 deployer 用到了這些函數就可能報錯,修改 php.ini 解除相關函數的禁用狀態就能夠了。

  1. php 執行文件位置引發的錯誤

目標主要經過 apt-get 命令或 oneinstack 一類的一鍵包安裝的 PHP,可執行文件一般在 /usr/local/php/bin/php,而 deployer 內使用 /usr/bin/env: php 形式調用,至關於 /usr/local/bin/php。這就可能出錯,通常是報 command -v 'php' failed。解決辦法很簡單,只要加個軟連接就能夠了。

ln -s /usr/local/php/bin/php /usr/local/bin/php
  1. 目錄主機不在線或者網絡鏈接問題

解決辦法固然是打開目錄主機並檢查網絡狀況

  1. 關於緩存清理

deployer 的 laravel 默認部署流程中,會執行 php artisan cache:clear 命令,若是你的項目裏使用了 redis 驅動的隊列或者一些強依賴於緩存的業務邏輯(如緩存文章閱讀數按期再入庫),則須要進行一些騷操做了。

好比,你能夠在 config/database.phpredis 項中爲隊列連接指定其它的 database。

或者修改 deploy.php 配置默認的緩存清理任務,跳過緩存清理動做。(一般並不建議這麼作,由於項目的緩存,應該是可清理的,若是部分業務確實十分依賴於緩存,則應該考慮一些緩存持久化的實現了)

// 覆蓋 recipe/laravel 裏默認的 artisan:cache:clear 任務,部署時不清緩存
task('artisan:cache:clear', function () {
    return true;
});

原文地址

相關文章
相關標籤/搜索