メインコンテンツまでスキップ

Laravel Envoy

はじめに

Laravel Envoy は、リモートサーバーで実行する一般的なタスクを実行するためのツールです。Blade スタイルの構文を使用して、デプロイメントやArtisanコマンドなどのタスクを簡単に設定できます。現在、EnvoyはMacとLinuxオペレーティングシステムのみをサポートしています。ただし、WSL2 を使用することでWindowsのサポートも可能です。

インストール

まず、Composerパッケージマネージャーを使用してプロジェクトにEnvoyをインストールします:

composer require laravel/envoy --dev

Envoyをインストールしたら、Envoyバイナリはアプリケーションの vendor/bin ディレクトリで利用できるようになります:

php vendor/bin/envoy

タスクの記述

タスクの定義

タスクはEnvoyの基本的な構成要素です。タスクは、タスクが呼び出されたときにリモートサーバーで実行すべきシェルコマンドを定義します。たとえば、アプリケーションのキューワーカーサーバー全体で php artisan queue:restart コマンドを実行するタスクを定義するかもしれません。

Envoyのすべてのタスクは、アプリケーションのルートにある Envoy.blade.php ファイルに定義する必要があります。以下は、始めるための例です:

@servers(['web' => ['user@192.168.1.1'], 'workers' => ['user@192.168.1.2']])

@task('restart-queues', ['on' => 'workers'])
cd /home/user/example.com
php artisan queue:restart
@endtask

ご覧の通り、ファイルの先頭に @servers の配列が定義されており、これらのサーバーをタスク宣言の on オプションで参照できます。@servers の宣言は常に1行に配置する必要があります。@task の宣言内では、タスクが呼び出されたときにサーバーで実行すべきシェルコマンドを配置する必要があります。

ローカルタスク

サーバーのIPアドレスを 127.0.0.1 として指定することで、スクリプトをローカルコンピューターで実行することができます:

@servers(['localhost' => '127.0.0.1'])

Envoyタスクのインポート

@import ディレクティブを使用すると、他のEnvoyファイルをインポートして、そのストーリーやタスクを自分のものに追加することができます。ファイルをインポートした後は、それらが含むタスクを自分のEnvoyファイルで定義されているかのように実行することができます:

@import('vendor/package/Envoy.blade.php')

複数のサーバー

Envoyを使用すると、簡単に複数のサーバーでタスクを実行できます。まず、@servers 宣言に追加のサーバーを追加します。各サーバーには一意の名前を割り当てる必要があります。追加のサーバーを定義したら、タスクの on 配列に各サーバーをリストアップできます:

@servers(['web-1' => '192.168.1.1', 'web-2' => '192.168.1.2'])

@task('deploy', ['on' => ['web-1', 'web-2']])
cd /home/user/example.com
git pull origin {{ $branch }}
php artisan migrate --force
@endtask

並列実行

デフォルトでは、タスクは各サーバーで直列に実行されます。つまり、タスクは最初のサーバーで実行が完了するまで、次のサーバーで実行されません。複数のサーバーでタスクを並列に実行したい場合は、タスク宣言に parallel オプションを追加してください:

@servers(['web-1' => '192.168.1.1', 'web-2' => '192.168.1.2'])

@task('deploy', ['on' => ['web-1', 'web-2'], 'parallel' => true])
cd /home/user/example.com
git pull origin {{ $branch }}
php artisan migrate --force
@endtask

セットアップ

時々、Envoyタスクを実行する前に任意のPHPコードを実行する必要がある場合があります。タスクの前に実行するべきPHPコードブロックを定義するために、@setup ディレクティブを使用できます:

@setup
$now = new DateTime;
@endsetup

タスクを実行する前に他のPHPファイルを要求する必要がある場合は、Envoy.blade.php ファイルの先頭に @include ディレクティブを使用できます:

@include('vendor/autoload.php')

@task('restart-queues')
# ...
@endtask

変数

必要に応じて、Envoyタスクに引数を渡すことができます。Envoyを呼び出す際にコマンドラインでそれらを指定することができます:

php vendor/bin/envoy run deploy --branch=master

Bladeの "echo" 構文を使用して、タスク内でオプションにアクセスできます。また、タスク内でBladeの if 文やループを定義することもできます。例えば、git pull コマンドを実行する前に $branch 変数の存在を確認しましょう:

@servers(['web' => ['user@192.168.1.1']])

@task('deploy', ['on' => 'web'])
cd /home/user/example.com

@if ($branch)
git pull origin {{ $branch }}
@endif

php artisan migrate --force
@endtask

ストーリー

ストーリーは、便利な名前の下に一連のタスクをグループ化します。たとえば、deploy ストーリーは、update-codeinstall-dependencies タスクをその定義内でタスク名をリストアップすることで実行できます:

@servers(['web' => ['user@192.168.1.1']])

@story('deploy')
update-code
install-dependencies
@endstory

@task('update-code')
cd /home/user/example.com
git pull origin master
@endtask

@task('install-dependencies')
cd /home/user/example.com
composer install
@endtask

ストーリーを書いたら、タスクを呼び出す際には、タスクを呼び出すのと同じ方法で呼び出すことができます:

php vendor/bin/envoy run deploy

フック

タスクとストーリーが実行されると、いくつかのフックが実行されます。Envoy がサポートするフックの種類は @before@after@error@success@finished です。これらのフック内のすべてのコードは PHP として解釈され、タスクが対話するリモートサーバーではなくローカルで実行されます。

これらのフックをそれぞれ好きなだけ定義することができます。Envoy スクリプト内に現れる順序で実行されます。

@before

各タスクの実行前に、Envoy スクリプトに登録されたすべての @before フックが実行されます。@before フックは実行されるタスクの名前を受け取ります:

@before
if ($task === 'deploy') {
// ...
}
@endbefore

@after

各タスクの実行後に、Envoy スクリプトに登録されたすべての @after フックが実行されます。@after フックは実行されたタスクの名前を受け取ります:

@after
if ($task === 'deploy') {
// ...
}
@endafter

@error

すべてのタスクが失敗した後(ステータスコードが 0 より大きい値で終了した場合)、Envoy スクリプトに登録されたすべての @error フックが実行されます。@error フックは実行されたタスクの名前を受け取ります:

@error
if ($task === 'deploy') {
// ...
}
@enderror

@success

すべてのタスクがエラーなく実行された場合、Envoy スクリプトに登録されたすべての @success フックが実行されます:

@success
// ...
@endsuccess

@finished

すべてのタスクが実行された後(終了ステータスに関係なく)、すべての @finished フックが実行されます。@finished フックは完了したタスクのステータスコードを受け取ります。これは null または 0 以上の整数値です:

@finished
if ($exitCode > 0) {
// There were errors in one of the tasks...
}
@endfinished

タスクの実行

アプリケーションの Envoy.blade.php ファイルで定義されたタスクやストーリーを実行するには、Envoy の run コマンドを実行し、実行したいタスクやストーリーの名前を渡します。Envoy はタスクを実行し、リモートサーバーからの出力を表示します:

php vendor/bin/envoy run deploy

タスクの実行の確認

サーバーで特定のタスクを実行する前に確認を求めたい場合は、タスクの宣言に confirm ディレクティブを追加する必要があります。このオプションは破壊的な操作に特に便利です:

@task('deploy', ['on' => 'web', 'confirm' => true])
cd /home/user/example.com
git pull origin {{ $branch }}
php artisan migrate
@endtask

通知

Slack

Envoy は各タスクの実行後に Slack に通知を送信する機能をサポートしています。@slack ディレクティブは Slack フック URL とチャンネル / ユーザー名を受け入れます。Slack コントロールパネルで "Incoming WebHooks" 統合を作成してウェブフック URL を取得できます。

@slack ディレクティブに与えられる最初の引数としてウェブフック URL 全体を渡すべきです。@slack ディレクティブに与えられる2番目の引数は、チャンネル名 (#channel) またはユーザー名 (@user) であるべきです:

@finished
@slack('webhook-url', '#bots')
@endfinished

デフォルトでは、Envoy の通知は実行されたタスクを説明する通知チャンネルにメッセージを送信します。ただし、@slack ディレクティブに3番目の引数を渡すことで、独自のカスタムメッセージでこのメッセージを上書きすることができます:

@finished
@slack('webhook-url', '#bots', 'Hello, Slack.')
@endfinished

Discord

Envoy は各タスクの実行後に Discord に通知を送信する機能もサポートしています。@discord ディレクティブは Discord フック URL とメッセージを受け入れます。サーバー設定で "Webhook" を作成し、Webhook が投稿するチャンネルを選択して Webhook URL を取得できます。@discord ディレクティブには Webhook URL 全体を渡す必要があります:

@finished
@discord('discord-webhook-url')
@endfinished

テレグラム

Envoyは、各タスクの実行後にTelegramに通知を送信する機能もサポートしています。@telegramディレクティブは、TelegramボットIDとチャットIDを受け入れます。Bot IDは、BotFatherを使用して新しいボットを作成することで取得できます。有効なチャットIDは、@username_to_id_botを使用して取得できます。@telegramディレクティブに完全なBot IDとChat IDを渡す必要があります:

@finished
@telegram('bot-id','chat-id')
@endfinished

マイクロソフト チーム

Envoyは、各タスクの実行後にMicrosoft Teamsに通知を送信する機能もサポートしています。@microsoftTeamsディレクティブは、Teams Webhook(必須)、メッセージ、テーマカラー(success、info、warning、error)、およびオプションの配列を受け入れます。Teams Webhookは、新しいincoming webhookを作成することで取得できます。Teams APIには、タイトル、サマリー、セクションなどのメッセージボックスをカスタマイズするための他の多くの属性があります。詳細はMicrosoft Teams documentationで確認できます。@microsoftTeamsディレクティブに完全なWebhook URLを渡す必要があります:

@finished
@microsoftTeams('webhook-url')
@endfinished