はじめに
DeployerはPHP製のデプロイツールです。汎用性のあるツールですが、Laravelはかなり手早くデプロイできるので、実際にデプロイし、レシピをカスタマイズする方法を紹介します。
Deployerの導入
前提条件
サーバ側
- Gitインストール済み
- nginx, php-fpmインストール済み
- mysqlセットアップ済み
ローカル側
- Laravelのプロジェクトを作成済み
- Gitリポジトリにプッシュ可能
インストール
composerでDeployerをインストールします。
1 | $ composer require deployer/deployer --dev |
インストールが完了したら、Deployerの初期設定を行います。
1 | $ php vendor/bin/dep init |
まず、プロジェクトの種類を選択します。今回はLaravelなので
1
とします。
1 2 3 4 5 6 7 8 9 10 11 12 13 | Please select your project type [Common]: [0 ] Common [1 ] Laravel [2 ] Symfony [3 ] Yii [4 ] Yii2 Basic App [5 ] Yii2 Advanced App [6 ] Zend Framework [7 ] CakePHP [8 ] CodeIgniter [9 ] Drupal [10] TYPO3 > 1 |
次に、Gitリポジトリのリモートを入力します。デプロイしたいプロジェクトのリモートのURLを指定してください。
1 2 | Repository []: > git@github.com:your/repository.git |
最後に、Deployer開発チームにデータを送信するかどうか聞かれます。これはどちらでも構いません。今回は
yes
にします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | Contribute to the Deployer Development In order to help development and improve the features in Deployer, Deployer has a setting for usage data collection. This function collects anonymous usage data and sends it to Deployer. The data is used in Deployer development to get reliable statistics on which features are used (or not used). The information is not traceable to any individual or organization. Participation is voluntary, and you can change your mind at any time. ・・・ Do you confirm? (yes/no) [yes]: > yes |
これで完了です。
デプロイの設定
デプロイスクリプト
デプロイスクリプトはプロジェクトのルートにある
deploy.php
で行います。Laravelテンプレートを選択したため、 基本的なことをほぼテンプレートのままできてしまいます。これに少し手を加えたので、その辺りも含めて説明します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | <?php namespace Deployer; require 'recipe/laravel.php'; // プロジェクト名 set('application', 'laravel-deployer'); // Gitリモートリポジトリ set('repository', 'git@github.com:your/repository.git'); // [任意] git cloneコマンドにttyを割り当てる。(デフォルトはfalse) set('git_tty', true); // デプロイ間で共有されるファイルとディレクトリ add('shared_files', []); add('shared_dirs', ['vendor']); // ウェブサーバから書き込み可能なディレクトリ add('writable_dirs', ['bootstrap/cache', 'storage']); // Hosts host('project.com') ->stage('production') ->identityFile('~/.ssh/your-key.pem') ->user('admin') ->set('deploy_path', '/var/www/{{application}}'); // Tasks (テンプレートに含まれていますが、サンプルなので不要) // task('build', function () { // run('cd {{release_path}} && build'); // }); // [任意] デプロイ失敗時に自動的にアンロックする after('deploy:failed', 'deploy:unlock'); // Migrate database before symlink new release. before('deploy:symlink', 'artisan:migrate'); // 本番環境用のenvファイルをコピーする before('deploy:shared','deploy:copy:env'); desc('各環境用のenvファイルをコピー'); task('deploy:copy:env', function () { run("cp {{release_path}}/.env.{{stage}} {{deploy_path}}/shared/.env"); }); |
いくつかポイントを紹介します。
-
require 'receipe/laravel.php
Laravelテンプレートを選択した時に使用されるLaravelレシピです。Laravelの様々なartisanコマンドが使えるレシピです。詳細は後述します。 -
add('shared_dirs', ['vendor']);
デプロイ時に共有するディレクトリを指定します。ここの指定したディレクトリは、実際のデプロイパス上ではシンボリックリンクに置き換えられ、実態はshared
ディレクトリの中に存在することになります。そのため、vendor
ディレクトリが毎回のデプロイで削除されずに使いまわされる、composer install
が早くなります。
また、Laravelレシピ側でデフォルトでstorage
が指定されています。これにより、デプロイ毎にstorage配下のファイルが消えずに、使用し続けることができます。 - .envファイルのコピー
Laravelレシピでは、.envファイルはshared/.env
へのシンボリックリンクが作成されるため、このパスにenvファイルをコピーします。Deployer内で使用できる変数を使用してパスとステージを特定して、適切な.envファイルを配置するようにしています。
例えばステージ名がproductionであれば、.env.production
をコピーするように実装しました。 -
run()
では、コマンド内で{{変数名}}
とすることで、変数を使用することができます。例えば、次のような変数があります。-
deploy_path
:host()->set()
で指定したデプロイディレクトリを取得できます。 -
release_path
: デプロイ中のソースが入っているディレクトリを取得することができます。今回の例では/var/www/laravel-deployer/releases/1
が取得できます。1
はリリース毎にインクリメントされます -
stage
: 今デプロイしているステージ名を取得できます。ステージ名はhost()->stage()
で設定し、デプロイコマンドで指定できます。
-
サーバサイドの設定
今回は割愛しますが、設定に合わせて次の対応を行います。
- /var/www/laravel-deployerディレクトリの作成
- gitのインストール
-
ssh-keygen
でキーを生成し、GithubにDeploy Keyとして登録する。 - nginx.confで、rootを
/var/www/laravel-deployer/current/public
にしておく。
デプロイコマンド
それでは、実際にデプロイしてみます。
1 | $ vendor/bin/dep deploy production |
deploy
は、Laravelレシピで定義されているタスク名で、ここにデプロイに最低限必要な一通りのタスクがまとまっています。
production
は、ステージ名です。
実際に実行すると、次のようになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | $ vendor/bin/dep deploy production ✈︎ Deploying master project.com ✔ Executing task deploy:prepare ✔ Executing task deploy:lock ✔ Executing task deploy:release ➤ Executing task deploy:update_code Cloning into '/var/www/laravel-deployer/releases/2'... remote: Enumerating objects: 11, done. remote: Counting objects: 100% (11/11), done. remote: Compressing objects: 100% (3/3), done. remote: Total 6 (delta 3), reused 6 (delta 3), pack-reused 0 Receiving objects: 100% (6/6), done. Resolving deltas: 100% (3/3), completed with 3 local objects. Enumerating objects: 187, done. Counting objects: 100% (187/187), done. Compressing objects: 100% (135/135), done. Writing objects: 100% (187/187), done. Total 187 (delta 34), reused 187 (delta 34) Connection to project.com closed. ✔ Ok ✔ Executing task deploy:copy:env ✔ Executing task deploy:shared ✔ Executing task deploy:vendors ✔ Executing task deploy:writable ✔ Executing task artisan:storage:link ✔ Executing task artisan:view:cache ✔ Executing task artisan:config:cache ✔ Executing task artisan:optimize ✔ Executing task artisan:migrate ✔ Executing task deploy:symlink ✔ Executing task deploy:unlock ✔ Executing task cleanup Successfully deployed! |
Deployerのディレクトリ構成
初めてデプロイが完了すると、指定したパスにディレクトリが生成されます。
- current: releases/nへのシンボリックリンク。(nは最新のデプロイ番号)
- releases: デプロイしたソースの実態
- shared: deploy.phpで指定した共有ディレクトリの格納場所 (今回の例では、vendor, storageが入っています。)
そのため、Webサーバは
current
配下を見れば最新のソースが格納されていることになります。
レシピ
requireされている
receipe/laravel.php
には他にも様々なレシピがあります。デプロイタスクに組み込むこともできますし、直接タスクを実行することもできます。
例えば、マイグレーションはデプロイタスクに組み込まず、任意のタイミングで実行したい場合は
$ vendor/bin/dep artisan:migrate production
で実行できます。
レシピをカスタマイズする方法
レシピをカスタマイズするには、deploy.phpの実装でいくつかやり方があるので、紹介します。
コンフィグの追加/上書き
レシピで
set()
で定義されているコンフィグは、追加したり上書きしたりできます。追加するには
add(キー, 値)
、上書きするには
set(キー、値)
とします。
任意のタスクを、定義済みタスクの前後に追加
deployタスクのように、一連のタスクを実行するタスクの中に、任意のタスクを追加したい場合があります。先ほどの例では次のように使用しています。
1 2 | // 本番環境用のenvファイルをコピーする before('deploy:shared','deploy:copy:env'); |
deploy:copy:env
は自前のタスクですが、これを
deploy:shared
の前に実行させています。
deploy:shared
タスクは、実際のソースをシンボリックリンクに置き換えますが、その際に
shared
内に対象ディレクトリもしくはファイルが無ければ、それぞれからの状態で生成します。
これが.envファイルで行われてしまうと、後からコピーする時に、空ファイルをいちいち削除しなければならなくなってしまうため、事前にenvファイルを
shared/.env
にコピーさせたかったからです。
参考までに実際の
deploy:shared
タスクで、shared_filesの処理は次のようになっています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | <?php /* (c) Anton Medvedev <anton@medv.io> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Deployer; use Deployer\Exception\Exception; desc('Creating symlinks for shared files and dirs'); task('deploy:shared', function () { $sharedPath = "{{deploy_path}}/shared"; // ・・・(shared_dir部分は省略)・・・ foreach (get('shared_files') as $file) { $dirname = dirname(parse($file)); // shared_filesへのパスが、sharedディレクトリに存在しない場合は、まずディレクトリを作成する。 if (!test("[ -d {$sharedPath}/{$dirname} ]")) { run("mkdir -p {$sharedPath}/{$dirname}"); } // shared_filesがsharedディレクトリに存在せず、releaseディレクトリ内に元ファイルがある場合は、 // releaseディレクトリ内の元ファイルをそのままコピーする if (!test("[ -f $sharedPath/$file ]") && test("[ -f {{release_path}}/$file ]")) { // Copy file in shared dir if not present run("cp -rv {{release_path}}/$file $sharedPath/$file"); } // releaseディレクトリ内に元ファイルがある場合は、のファイルは削除する。 run("if [ -f $(echo {{release_path}}/$file) ]; then rm -rf {{release_path}}/$file; fi"); // releaseディレクトリ内に元ファイルまでのディレクトリが存在しなければ作成する run("if [ ! -d $(echo {{release_path}}/$dirname) ]; then mkdir -p {{release_path}}/$dirname;fi"); // sharedにファイルを新規作成(touchなので、既存ファイルの中身は置き換わらない。) run("touch $sharedPath/$file"); // releaseディレクトリの対象パスに、sharedディレクトリ内ファイルへのシンボリックリンクを貼る。 run("{{bin/symlink}} $sharedPath/$file {{release_path}}/$file"); } }); |
おまけ
Github Actionsでもデプロイできるようにしてみたので、簡単に紹介します。作成したワークフローはこちらです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | name: Laravel on: push: branches: [ master ] jobs: laravel-tests: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Copy .env run: php -r "file_exists('.env') || copy('.env.production', '.env');" - name: Install Dependencies run: composer install -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist - name: Generate key run: php artisan key:generate - name: deploy run: | mkdir ~/.ssh echo "${{ secrets.SECRET_KEY }}" > ~/.ssh/your-project.pem ssh-keyscan -H "project.com" >> ~/.ssh/known_hosts chmod 600 ~/.ssh/your-project.pem vendor/bin/dep deploy production |
3つポイントがあります。
- SSHキーは、GithubのSecretsに登録しておきます。
- deploy.phpの
git_tty
はGithub Actionsでは動作しなかったので、falseにします。 - あらかじめknown_hostsに登録しておきます。
個人用のプロジェクト程度であれば、これで十分便利に使用できると思いました。
さいごに
いかがでしたか。Deployerはテンプレートやレシピが充実していて、主要なフレームワークやCMSで簡単にデプロイできることが分かりました。Laravelの公式パッケージで
envoy
と言うツールもありますが、Deployerの方がレシピが豊富なので便利だと思いました。