ECSで稼働するphp:fpm-alpine
ベースのPHP/Phalconで構築したアプリケーションイメージを流用して、ECSでバッチ処理をスケジュール実行するためのアーキ。
要件
- 運用中のアプリケーションのイメージを流用できること。
- スケジュール実行したあと、exit終了すること。
- ログはCloudWatchLogに出力すること。
PhalconでCLI実行
エントリポイントとバッチ処理を実装する。下記のコードスニペットがそのまま使えました。 【PHP Phalcon】バッチ処理の実装とcronの設定
実行
# cliモードで起動
php /path/to/CLIエントリポイント.php \
&& className(→ ClassNameTaskクラス) \
&& action_name(→ actionNameActionメソッド) \
&& param1(→ メソッドの引数1) \
&& param2(→ メソッドの引数2)
Dockerイメージのフレキシブル運用
ENTRYPOINT
にCMD
に応じて サーバー起動 or CLI実行 を切り替えるシェルスクリプトを用意して、docker run イメージ {コマンド上書き}
あるいは、ecsのコマンド上書き設定で起動モードをスイッチ出来るようにする。
Dockerfile
...
# エントリポイントスクリプトをコピー
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
# エントリポイントを設定
ENTRYPOINT ["/entrypoint.sh"]
# デフォルトでは FPM を起動
CMD ["fpm"]
#!/bin/sh
set -e # エラー時に停止
# 引数がない場合、または "fpm" の場合は PHP-FPM を起動
if [ "$1" = "fpm" ] || [ -z "$1" ]; then
echo "Starting PHP-FPM..."
exec php-fpm
fi
# "cli" の場合は、引数を `php` に渡して実行(CLIモード)
if [ "$1" = "cli" ]; then
shift # `cli` を削除
echo "Running PHP CLI..."
exec php "$@"
fi
# それ以外のコマンドは直接実行
exec "$@"
実行
# サーバー起動モード
docker run -d イメージ
#=> php-fpm
# CLI実行でワンショット起動
docker run --rm イメージ cli /path/to/cli.php arg1 arg2
#=> php /path/to/cli.php arg1 arg2
# メンテコマンドでワンショット起動
docker run --rm イメージ ls -l
#=> ls -l
ECS
初見はいろいろと問題が出るので、新しいタスクの実行でデバッグしてからスケジュールされたタスクを構築することを推奨。
- バッチ用の
タスク定義
を作成して、上記のイメージを指定する。- 起動タイプ(Fagate?EC2?)クラスタレイヤーの話なのにここで選ぶのかい?と混乱していたら、フォームを想定環境に最適化してくる親切設計であった。Amazon ECS 起動タイプ - Amazon Elastic Container Service
- デバッグ、モニタリングためCloudWatchLogは必ずオン
クラスタ > スケジュールされたタスク
では主にタスク定義
、cron
式および、コンテナの上書き > コマンドの上書き
でCMDをCLI起動用に上書きする。- スケジュール機能はEventBridgeに統合されていて、EventBridge流のcron式で記述する(例:
cron(0 0 * * ? *)
)。タイムゾーンはUTC。 cron 式と rate 式を使用して Amazon EventBridge でルールをスケジュールする - Amazon EventBridge - コマンドの上書きはカンマ区切りで指定するコマンドラインなのりでスペース区切りで指定すると、ひとつの文字列として認識され、そのようなコマンドはない的なエラーになる。
- スケジュール機能はEventBridgeに統合されていて、EventBridge流のcron式で記述する(例:
# だめ ひとつのコマンドとして認識される
# cli /path/to/cli.php className action_name
#=> /entrypoint.sh: exec: line X: cli /path/to/cli.php className action_name: not found
# OK カンマでCMD引数としてプロットしてくれる(説明どおり)
cli,/path/to/cli.php,className,action_name
#=> exec php /path/to/cli.php className action_name
つまずき
ResourceInitializationError
クラスター > タスクの状態より ResourceInitializationError: unable to pull secrets or registry auth: The task cannot pull registry auth from Amazon ECR: There is a connection issue between the task and Amazon ECR. Check your task network configuration. RequestError: send request failed caused by: Post "https://api.ecr.ap-northeast-1.amazonaws.com/": dial tcp 99.77.58.41:443: i/o timeout
イメージのpull → イメージのECRエンドポイントに接続できていない。 → タスクのサブネットがプライベートサブネットだったのでNAT/IGWの準備がなくECRに接続できない。パブリックサブネットに設置して通過。
Essential container in task exited
クラスター > タスクの状態より Essential container in task exited
プロセスが終了してexit状態なのでOK。CloudWatchLogで実行結果を確認する。