GithubやBitbucketなどGitリポジトリで管理されているLaravelのプロジェクトをDeployerを使ってデプロイしてみます。
Deployerとは
Deployerの公式サイトには以下のように書かれています。
A deployment tool written in PHP with support for popular frameworks out of the box.
様々なフレームワークをサポートしているデプロイツールです。
もちろんLaravelもサポートされています。
デプロイ手順
1. Deployerのインストール
composerを使ってインストールします。
$ composer require deployer/deployer --dev
これで vendor/bin/dep
でDeployerを実行できるようになります。
2. 設定ファイル作成
今回はDeployerが提供するLaravel用の設定ファイルの雛形を編集していきます。
以下を実行すると deploy.php
が作成されます。
$ vendor/bin/dep init -t Laravel // Laravel用の設定ファイルの雛形を作成
次にデプロイ先のHost情報を記載する hosts.yml
を作成します。
<hostname>
と <username>
には適切な値を設定してください。
staging:
hostname: <hostname> # デプロイ先のホスト名
stage: staging
roles:
- app
deploy_path: /var/www/html
branch: master
become: <username> # デプロイを行うユーザ
production:
hostname: <hostname> # デプロイ先のホスト名
stage: production
roles:
- app
deploy_path: /var/www/html
branch: master
become: <username> # デプロイを行うユーザ
先ほど作成した deploy.php
を編集します。
<?php
namespace Deployer;
require 'recipe/laravel.php';
// Project name
set('application', 'アプリケーション名');
// Project repository
set('repository', 'Gitリポジトリ');
// [Optional] Allocate tty for git clone. Default value is false.
set('git_tty', false);
// Shared files/dirs between deploys
add('shared_files', []);
add('shared_dirs', []);
// Writable dirs by web server
add('writable_dirs', []);
// 統計情報を送信しない
set('allow_anonymous_stats', false);
// Hosts
inventory('hosts.yml');
// [Optional] if deploy fails automatically unlock.
after('deploy:failed', 'deploy:unlock');
// shared/.envを.env.{stage}で上書きする
after('deploy:shared', 'overwrite-env');
// Migrate database before symlink new release.
before('deploy:symlink', 'artisan:migrate');
// Tasks
task('deploy', function () {
// 本番への反映は確認を挟む
if (input()->hasArgument('stage') && (input()->getArgument('stage') === 'production')) {
if (!askConfirmation('productionに反映して問題ありませんか?', true)) {
writeln('deploy was stopped');
return;
}
}
invoke('deploy:laravel');
});
desc('shared/.envを.env.{stage}で上書き');
task('overwrite-env', function () {
$stage = get('stage');
$src = ".env.${stage}";
$deployPath = get('deploy_path');
$sharedPath = "${deployPath}/shared";
run("cp -f {{release_path}}/${src} ${sharedPath}/.env");
});
/**
* Main task
*/
desc('Deploy your project');
task('deploy:laravel', [
'deploy:info',
'deploy:prepare',
'deploy:lock',
'deploy:release',
'deploy:update_code',
'deploy:shared',
'deploy:vendors',
'deploy:writable',
'artisan:storage:link',
'artisan:view:clear',
'artisan:cache:clear',
'artisan:config:cache',
'artisan:optimize',
'deploy:symlink',
'deploy:unlock',
'cleanup',
]);
.envの扱い
デフォルトの挙動では deploy:shared
タスクで {deploy_path}/shared
に .env
がなければ、空の .env
を作成して {deploy_path}/shared/.env
から {release_path}/.env
へのシンボリックリンクを貼ります。
今回は各環境の .env
を .env.{stage}
のようにしてプロジェクト内に含める運用をしたかったので、 deploy:shared
タスクの直後に {deploy_path}/shared/.env
を .env.{stage}
で上書きするようにしました。
3. デプロイ先サーバの設定
1. SSH接続するユーザがsudoできるようにする
hosts.yml
の become
で指定したユーザになるためにsudoできる必要があるため、SSH接続するユーザがsudoできるようにする。
2. デプロイ先のディレクトリをデプロイユーザが作成できるように権限を確認
Deployerは hosts.yml
の deploy_path
で指定したディレクトリを作成してくれるのでデプロイするユーザに書き込み権限があるか確認しておく。
3. 初回Gitクローン時にSSH接続の確認をしないようにする
Host github.com
StrictHostKeyChecking no
Host bitbucket.org
StrictHostKeyChecking no
4. Webサーバの設定
Webサーバのドキュメントルートを {deploy_path}/current/public
に設定する。
また、Nginx+PHP-FPM環境でOPcacheを利用する場合は以下のように SCRIPT_FILENAME
と DOCUMENT_ROOT
を設定すると良いです。
詳しくはこちらを参照。
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT $realpath_root;
4. デプロイ
$ vendor/bin/dep deploy staging // ステージング
$ vendor/bin/dep deploy production // 本番
5. おまけ
デプロイ開始時と結果をSlack通知します。
composerでレシピを追加。
$ composer require deployer/recipes --dev
・・・略・・・
require 'recipe/slack.php';
・・・略・・・
// deployタスクを上書きした場合必要。
after('deploy', 'success');
// Slack Notification
set('slack_webhook', '<Webhook URL>');
set('slack_text', '_{{user}}_ が `{{branch}}` を *{{target}}* へデプロイしています...🚀');
set('slack_success_text', '*{{target}}* へのデプロイが成功しました。🎉');
set('slack_failure_text', '*{{target}}* へのデプロイが失敗しました。😂');
before('deploy', 'slack:notify');
after('success', 'slack:notify:success');
after('deploy:failed', 'slack:notify:failure');