もがき系プログラマの日常

もがき系エンジニアの勉強したこと、日常のこと、気になっている技術、備忘録などを紹介するブログです。

Laravel-Deployerを使ったデプロイ

はじめに

こんにちは。

この記事は challenge-every-month全員でアウトプット芸人 Advent Calendar 8日目の記事です。

前日の記事は、激アウトプット芸人 の @kdnaktさんの記事です。

twitter.com

kdnakt.hatenablog.com

4月からGW明けまで異常に忙しく、なかなかブログや挑戦を行えていない僕です。

今回のブログも作業の備忘録的なブログでございます。

Laravelプロジェクトのデプロイをどうしようかと考えていたのですが、Deployerを試してみようと思い、Laravel-Porjectに特化したLaravel-Deployerなるものを発見したのでこちらを使用しました。

Laravel-DeployerはCapistranoと同じくシンボリックリンク型のデプロイツールで、そのデプロイ方法は大きく5つ存在するようです。

  1. Basic strategy
  2. First deploy strategy
  3. Locally-built strategy
  4. Git pull only strategy (no zero downtime)
  5. Upload strategy

全部検証しているわけではないのですが、基本的にHostサーバ側で git pullしちゃう形になってるみたいです。

また、.envstorage などは sharedに登録されるようですが、 基本的には .env は .gitignore対象になっていると思うので、 git pullしたあとだと .env が存在しません。

.env がない場合は、勝手に空の .env を作成して sheardFileに登録されます。

それによりもれなくエラーとなります。

このあたり参考サイトをみてても手動で解決しているようでした。

この流れで自分が変えたかったのは、以下です。

  • Host側でgit pullしちゃうところ(単純に時間短縮したい)
  • ファイルがない場合勝手に .env 作っちゃう(期待している .env を作ったり上書きしたりしたい)

こちらを対応するため、先ほど紹介したデプロイ方法をベースにカスタムのデプロイ方法を作りました。

本題

1. インストール

$ composer require lorisleiva/laravel-deployer
$ php artisan deploy:init

2. deploy.php修正

今回は自分が変えたかったところを対応するために、 Default deployment strategy を変更します。

# config/deploy.php

<?php

declare(strict_types=1);

return [
    /*
    |--------------------------------------------------------------------------
    | Default deployment strategy
    |--------------------------------------------------------------------------
    |
    | This option defines which deployment strategy to use by default on all
    | of your hosts. Laravel Deployer provides some strategies out-of-box
    | for you to choose from explained in detail in the documentation.
    |
    | Supported: 'basic', 'firstdeploy', 'local', 'pull'.
    |
    */

    'default' => 'custom',

3. recipeとなるphpファイル修正

基本ベースは upload strategy をベースにしており、host側で git pullするところを、 git pullせずrsyncを行うように変更しています。

# recipe/custom_strategy.php

<?php

declare(strict_types=1);

namespace Deployer;

set('writable_dirs', [
    'bootstrap/cache',
    'storage',
    'storage/app',
    'storage/app/public',
    'storage/app/tmp',
    'storage/framework',
    'storage/framework/cache',
    'storage/framework/sessions',
    'storage/framework/views',
    'storage/logs',
]);

desc('Custom Strategy');
task('strategy:custom', [
    'hook:start',
    'deploy:prepare',
    'deploy:lock',
    'deploy:release',
    'custom:upload',
    'deploy:shared',
    'deploy:vendors',
    'deploy:writable',
    'hook:ready',
    'deploy:symlink',
    'deploy:unlock',
    'cleanup',
    'hook:done',
]);

set('custom_upload_path', __DIR__ . '/../');
set('custom_upload_vendors', false);
set('custom_upload_options', function () {
    $options = [
        '--exclude=.git',
        '--exclude=.circleci',
        '--exclude=.env.develop',
        '--exclude=.env.local',
        '--exclude=.env.production',
        '--exclude=.env.staging',
        '--exclude=.env.testing',
        '--exclude=server.php',
        '--exclude=sg.sh',
        '--exclude=tests',
        '--exclude=recipe',
        '--exclude=.editorconfig',
        '--exclude=.gitattributes',
        '--exclude=.gitignore',
        '--exclude=.php_cs.cache',
        '--exclude=.php_cs.dist',
        '--exclude=_ide_helper.php',
        '--exclude=codecov.yml',
        '--exclude=coverage.xml',
        '--exclude=phpcs.xml',
        '--exclude=phpstan.neon.dist',
        '--exclude=phpunit.xml',
        '--exclude=readme.md',
    ];

    if (!get('custom_upload_vendors')) {
        $options[] = '--exclude=/vendor';
    }

    return compact('options');
});

desc('Upload a given folder to your hosts');
task('custom:upload', function (): void {
    $configs = array_merge_recursive(get('custom_upload_options'), [
        'options' => ['--delete'],
    ]);

    upload('{{custom_upload_path}}/', '{{release_path}}', $configs);
});

4. デプロイ実行

デプロイ自体は以下のコードで実行できます。

$ php artisan deploy

今回は CircleCIからデプロイするようにしましたので、CircleCI上で checkoutした状態のコードをデプロイします。

このデプロイフローの中で、 .env の問題も解決させています。

# .circleci/config.yml

  # デプロイ実行
  execute_deployer:
    steps:
      - run: cp ~/workspace/.env.production ./.env
      - run: echo "AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID" >> ./.env
      - run: echo "AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY" >> ./.env
      - run: echo "DB_PASSWORD=$DB_PASSWORD" >> ./.env
      - run: php artisan deploy:run deploy:unlock
      - run: php artisan deploy -vv

特に変わったことはしておらず、事前に用意している production環境用の .envファイルを .env ファイルとしてコピーしつつ、デプロイを行うという方法です。

その際に、awsのアクセスキーやシークレットキー・本番DBのパスワードなども環境変数からコピーしています。

deployコマンドを実行する前に deploy:unlock を実行しているのは、万が一デプロイ中に何かしら失敗した場合に .lockファイルが残っている可能性があり、そのファイルを消さないと次のデプロイが失敗してしまうから、必ず消すようにしています。

5. デプロイ結果

実際のデプロイ結果は以下です。

$ ls -la
合計 412
drwxr-xr-x 10 ec2-user ec2-user    207  426 21:48 .
drwxrwxr-x  7 ec2-user ec2-user     55  426 21:46 ..
-rw-r--r--  1 ec2-user ec2-user   1487  426 21:48 .env
drwxr-xr-x 10 ec2-user ec2-user    131  426 21:44 app
-rwxr-xr-x  1 ec2-user ec2-user   1686  426 21:44 artisan
drwxr-xr-x  3 ec2-user ec2-user     34  426 21:44 bootstrap
-rw-r--r--  1 ec2-user ec2-user   2882  426 21:44 composer.json
-rw-r--r--  1 ec2-user ec2-user 400814  426 21:44 composer.lock
drwxr-xr-x  2 ec2-user ec2-user   4096  426 21:44 config
drwxr-xr-x  4 ec2-user ec2-user     37  426 21:44 database
drwxr-xr-x  2 ec2-user ec2-user     40  426 21:44 public
drwxr-xr-x  3 ec2-user ec2-user     18  426 21:44 resources
drwxr-xr-x  2 ec2-user ec2-user    102  426 21:44 routes
lrwxrwxrwx  1 ec2-user ec2-user     20  426 21:46 storage -> ../../shared/storage
drwxrwxr-x 51 ec2-user ec2-user   4096  426 21:46 vendor

終わりに

今回はこのような感じです。

このあたりブログに書き留めるために作業中にまとめておきたかったのですが、とにかく忙しく思い出しながら書きました。。。

嗚呼。忙しい。

現場からは以上です。

参考サイト