AWSのECSを使った環境構築、↓この記事からの続きで、
uyamazak.hatenablog.com
Laravelの
php artisan schedule:run
を実行するためにタスクのスケジューリングを使ってみることに。

新規作成はコンソール上でなんなくできたものの、CircleCIからの更新方法が見つかりませんでした。
コンテナのビルドからECRへのプッシュとか、ECSのサービスの更新などはCircleCIの公式Orbがあったけど、スケジュールに関するものは見当たらない。
CircleCI Developer Hub - circleci/aws-ecs
どうやらスケジュールタスクはECSの画面にあるもののAWSの裏側ではいろいろ組み合わせて構成されてるようで、ECSのコマンドでは更新できないもよう。
shirakiya.hatenablog.com
この記事だと手で叩くことはできても、タスク定義のリビジョンは毎回異なるため、そこは別に用意する必要があった。
公式ドキュメントには新規作成だけあった。
AWS CLI を使用したスケジュールされたタスクの作成 - Amazon Elastic Container Service
個人のOrbもあったけど、ソースをみるとPython使ってたり、ちょっと無理やりな感じなので勉強も兼ねてAWS CLIでやることに。
CircleCI Developer Hub - pbrisbin/aws-ecs-scheduled-tasks
実行タイミング的には上記Orbのaws-ecs/deploy-service-updateが終わり、タスク定義が更新された後。
手で更新してみる
まずはCIでいちいちやると大変なので、自分のPCから更新が成功するか試します。AWS CLIのインストールや設定は大前提。
上記の記事のようにaws events put-targetsを使います。
基本的に指定はArnなのでECSの画面とかIAMとかで調べながら埋めていきます。
helpを見ながら叩いて、エラーで出た不足した項目を追加していったところ、最低限はこんな感じ。
aws events put-targets --rule your-rule-id --targets="[{"Id":"ターゲットのID","Arn":"クラスターのArn","RoleArn":"ロールのARN","EcsParameters":{"TaskDefinitionArn":タスク定義ののArn"`}}]"タスク定義のArnには最新でなくとも、変わっているのが分かるように、今のスケジュールタスクの指定とは違うものを指定すればよさそう。
こんな感じの結果が返ってきて、コンソールで見て変更されてればOK
{
"FailedEntryCount": 0,
"FailedEntries": []
}
最新のタスク定義1件のArnを取得する
上記のコマンドがうまくいくのがわかったら、TaskDefinitionArnの部分を動的に最新の1件を取得するようにします。
タスク定義はECSの範疇なのでaws ecs list-task-definitionsで取得し、--sortと--max-itemsを使って最新1件にしぼります
$ aws ecs list-task-definitions --family-prefix タスク定義の名前 --sort DESC --max-items 1
{
"taskDefinitionArns": [
"arn:aws:ecs:{リージョン}:{アカウントID}:task-definition/タスク定義の名前:8"
],
"NextToken": "tekitooooooooooo=="
}このままだとJSON的なものなので使いにくい・・・使えなくはないけどCIでjqとかインストールするのもださい。
ということでいろいろ調べているとAWS CLIには--queryという全体で使えるオプションがあることを知りました。
AWS CLI 出力をフィルタリングする - AWS Command Line Interface
ほしいのはtaskDefinitionArnsの1つ目なので--query "taskDefinitionArns[0]"をつけます。
$ aws ecs list-task-definitions --family-prefix タスク定義の名前 --sort DESC --max-items 1 --query "taskDefinitionArns[0]"
"arn:aws:ecs:{リージョン}:{アカウントID}:task-definition/タスク定義の名前:8"
これでタスク定義のArnだけが取得できました。
あとはシェル芸なんですが、私はあまりシェル力は高くないので一旦JSON的な部分を環境変数にして使うことにしました。
最終的にこんな感じの.circleci/config.yml。
とりあえず今回環境で変わりそうなところだけparameter化したけどもっときれいにできそう。
version: 2.1
orbs:
aws-cli: circleci/aws-cli@2.0.0
commands:
put_targets:
parameters:
target_id:
type: string
cluster:
type: string
family:
type: string
rule:
type: string
steps:
- run:
command: |
TARGETS="[{\"Id\":\"<< parameters.target_id >>\",\"Arn\":\"arn:aws:ecs:リージョン:アカウントID:cluster/<< parameters.cluster >>\",\"RoleArn\":\"arn:aws:iam::アカウントID:role/ecsEventsRole\",\"EcsParameters\":{\"TaskDefinitionArn\":`aws ecs list-task-definitions --family-prefix << parameters.family >> --sort DESC --max-items 1 --query "taskDefinitionArns[0]"`}}]"
aws events put-targets --rule << parameters.rule >> --targets=$TARGETS
jobs:
update_scheduled_task:
executor: aws-cli/default
steps:
- aws-cli/setup
- put_targets:
cluster: hogeeee
family: hoggeeee
target_id: hogeeee
rule: hogeeee
workflows:
hogeeee-workflow-name:
jobs:
- update_scheduled_task:
requires:
- deploy-service-update-queue
filters:
branches:
only:
- stage
- push_dockerimage_to_ecrこれでサービスやタスク定義の更新後に、スケジュールしたタスクの定義も更新することができました。
ただ常に最新になってしまうので、もしかしたら問題が起きるときもあるかも?(ロールバックとか)