ECSのタスク実行をCLIからやる
すでに作成済みのタスク定義を指定して、CLIから任意のタスクを実行する環境を整えます。
IAMポリシーのセットアップ
タスク実行に必要な ecs:RunTask
の他に、タスク定義を参照するための ecs:DescribeTasks
や、 CloudWatchへのログ出力のためのポリシーが必要になります。
最終的な設定はこんな感じになった。
{ "Version": "2012-10-17", "Statement": [ { "Sid": "0", "Effect": "Allow", "Action": [ "iam:PassRole", "ecs:RunTask", "ecs:DescribeTasks" ], "Resource": [ "arn:aws:ecs:*:*:task/*", "arn:aws:ecs:*:*:task-definition/foo*", "arn:aws:iam::*:role/foo*" ] }, { "Sid": "1", "Effect": "Allow", "Action": [ "logs:CreateLogStream", "logs:DescribeLogGroups", "logs:DescribeLogStreams", "logs:FilterLogEvents", "logs:PutLogEvents" ], "Resource": "*" } ] }
一つハマったのが、タスク定義のリビジョン指定。
マネジメントコンソールからビジュアルエディタで作る場合、リソースの指定は task definition family name
と task definition revision number
に分かれていて、できあがるARNはfoo:1
とかfoo:2
のようになる。
大抵のケースではリビジョンまで絞る必要はないので、foo:*
とワイルドカードになるのだが、これが落とし穴で、
AWS CLI から Run Task API を呼び出す際に、タスク定義のリビジョンを省略すると、最新のアクティブなリビジョンを使用するようになっている。
The family and revision (family:revision ) or full ARN of the task definition to run. If a revision is not specified, the latest ACTIVE revision is used.
便利なのだが、これだと先ほどのリソース指定のワイルドカードに含まれる:
が邪魔になって、パーミッションエラーになる。
なので、直接JSONを編集してfoo*
とするとよい。これならリビジョンを指定しても省略しても動くようになる。
入力テンプレートの作成
特にコンテナのコマンドを上書きする場合など、渡すパラメータが長くなりがちなので、ファイルで定義することにする。
--generate-cli-skeleton
オプションで雛形を生成する。
yamlの方が好みなので、yaml-input
をつける。
aws ecs run-task --generate-cli-skeleton yaml-input > tmp.yml
最低限このくらい渡せば動く。
cluster: foo count: 1 launchType: FARGATE networkConfiguration: awsvpcConfiguration: subnets: - foo securityGroups: - bar assignPublicIp: ENABLED overrides: containerOverrides: - name: foo command: - echo - Hello taskDefinition: foo
実行
aws ecs run-task --cli-input-yaml file://./tmp.yml
これもハマりどころの一つだが、ローカルにあるファイルを指定する場合は、プレフィックスにfile://
を付ける必要がある。
tasks
を含む長いレスポンスが返ってきたら成功。
"tasks": [ .... ]
タスクの起動は非同期になるので、この時点ではあくまでタスク実行リクエストを受け取ったという成功に過ぎない。Fargateは起動に1分くらいかかるし、タスクが exit 0
で正常終了するかどうかまではさすがに待ってくれない。
ログの確認
Cloud Watch Logs にログを流している場合を想定している。 これもCLIからログを見てみる。
aws logs get-log-events \ --log-group-name foo \ --log-stream-name $(aws logs describe-log-streams \ --log-group-name foo \ --order-by LastEventTime \ --descending \ --max-items 1 \ | jq -r '.logStreams[] | .logStreamName') \ --query "events[].[message]" \ --output text
最新のストリーム1つだけを取得したいので、最新のイベント順に並び替えて1件だけ取得し、ストリーム名をget-log-events
APIに渡している。雑な方法だがすぐに確認したい場合であればこれで十分かなー。
以上です。