ECSのタスクスケジュールで常に最新(latest)のタスク定義を使う

  • 2022年3月25日
  • 2022年8月7日
  • AWS, IT
AWS

こんにちはますのです。
ECSのタスクスケジュール機能、使っていますか??

タスクスケジュール機能を利用して1日1回、バッチを動かす処理をFargateで利用しています。
その際に直面した課題が1つ。

タスク定義を更新したら手動で最新版を設定する必要がある

今回はこちらの課題をクリアするために「EventBridge」を利用しました。

参考:【小ネタ】ECSのタスクスケジュールはEventBridgeから登録するとタスク定義の最新リビジョンから起動できる

やりたいこと

主に今回のやりたいことはこんな感じです。

  • コード管理はGithubで実施
  • タスク定義の更新は「Github Actions」を利用
  • コードが変更されたタイミングでGithubActionsが起動
  • ECSの起動はFargate環境で1日1回のみ
  • Fargate起動時に最新のタスク定義を必ず展開する

EventBridgeを設定する

手順はAWSの公式ドキュメントを参照
参考:スケジュールされたタスクを作成する

  • ターゲットタイプ:AWSのサービス
  • ターゲットを選択:ECSタスク
  • タスク定義リビジョン:最新
  • カウント:(起動する台数)

コンピューティングオプションではFargateを選択します。

  • 起動タイプ:Fargate
  • プラットフォームのバージョン:(空欄)

プラットフォームのバージョンは(空欄)にすると「LATEST」が設定されます。
– (オプション) Fargate 起動タイプが指定されている場合、Platform version(プラットフォームのバージョン)で、使用するプラットフォームのバージョンを指定します。プラットフォームのバージョンが指定されない場合、LATESTプラットフォームのバージョンが使用されます。11-dより参照:https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/scheduled_tasks.html
ネットワーク設定でサブネットやセキュリティグループもあるので、ECSに設定している設定をコピペします。
このあたり、自動で入力されれば嬉しいなぁ…。

IAMロールの作成でハマりました

わたしはIAMロールの設定に気付かず1日調査で潰しました。
自動で作成されるIAMロールの場合、リビジョンが最新のものを実行しようとするとエラーが出ます。

解決方法としては2つあります。

  • 既存のロールを使用を選択し「ecsEventsRole」を設定する
  • 自動作成のIAMロールを修正する

基本的にはecsEventsRoleを設定すればOKです!
ざっくりな理解ですが、
ECSの全リソースに対して「ecs:RunTask」の権限を持っているよ。というロールになります。ちなみに、自動作成のIAMロールは「ECSの特定リソースのみ」「ecs:RunTask」の権限を持っていロールです。
権限周りを厳密に管理したい場合は、自動作成されたIAMロールを修正する必要があります。
以降の内容でメモを残します。

自動で作成されるIAMロール(EventBridge_Invole_ECS)の中身

ここから下は私のメモになります。
理解を深めたい方向けとなるので、動かせるようになれば良いという方は「ecsEventsRole」を設定してお試しください。

自動作成されるIAMロールの中身

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ecs:RunTask"
            ],
            "Resource": [
                "arn:aws:ecs:*:123456789012:task-definition/task-py-sh:*"
            ],
            "Condition": {
                "ArnLike": {
                    "ecs:cluster": "arn:aws:ecs:*:123456789012:cluster/py-test-cluster"
                }
            }
        },
        {
            "Effect": "Allow",
            "Action": "iam:PassRole",
            "Resource": [
                "*"
            ],
            "Condition": {
                "StringLike": {
                    "iam:PassedToService": "ecs-tasks.amazonaws.com"
                }
            }
        }
    ]
}

何がエラーとなっていたか?

以下の部分の「(タスク定義名):*」にやられました。
"Resource": [
"arn:aws:ecs:*:123456789012:task-definition/task-py-sh:*"

どうやらリビジョン最新の場合は「(タスク定義名):latest」ではなく、「(タスク定義名)」のみとなります。
つまり、「:」が含まれないためアクセス権限が付与されていないのです。

CloudTrailでエラーログを確認する

しっかりbecause no identity-based policy allows the ecs:RunTask action",というのが出ていますね。
権限足りないからアクセス不可ですよってことらしい。

"eventSource": "ecs.amazonaws.com",
"eventName": "RunTask",
"awsRegion": "(リージョン名)",
"sourceIPAddress": "events.amazonaws.com",
"userAgent": "events.amazonaws.com",
"errorCode": "AccessDenied",
"errorMessage": "User: arn:aws:sts::123456789012:assumed-role/Amazon_EventBridge_Invoke_ECS_123456789/abcdefghijklmn is not authorized to perform: ecs:RunTask on resource: arn:aws:ecs:123456789012:task-definition/(タスク定義名) because no identity-based policy allows the ecs:RunTask action",

自動で作成されるIAMロール(EventBridge_Invole_ECS)を修正する

Resourceタグの「:」を削除します。
こんな感じ。
"Resource": [
"arn:aws:ecs:*:123456789012:task-definition/task-py-sh*"

こうすることでリビジョン指定が無くてもワイルドカードで一致するのでAccessDeniedを避けられます。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ecs:RunTask"
            ],
            "Resource": [
                "arn:aws:ecs:*:123456789012:task-definition/task-py-sh*"
            ],
            "Condition": {
                "ArnLike": {
                    "ecs:cluster": "arn:aws:ecs:*:123456789012:cluster/py-test-cluster"
                }
            }
        },
        {
            "Effect": "Allow",
            "Action": "iam:PassRole",
            "Resource": [
                "*"
            ],
            "Condition": {
                "StringLike": {
                    "iam:PassedToService": "ecs-tasks.amazonaws.com"
                }
            }
        }
    ]
}

設定完了後:ECSクラスター>タスクのスケジュールに追加される

EventBridgeに設定を追加後、下図のようにECSクラスター内「タスクのスケジュール」に追加されます。

タスク定義に記載されているタスク名の後ろにリビジョン「:(数字)」が消えていますね。
これで必ず最新のタスク定義が実行されるようになります。

GithubActionsで「タスクのスケジュール」を設定する方法がある?
それともCLIとかで無理やりやらんとダメ?と重い腰でした。
EventBridgeでサクサクっと出来ると知れて良かったです。しかし、簡単じゃん!と思っていたところ、思わぬところで躓きました。
AWSさん改善してくれたら嬉しいなぁと思ったので届けこの思い。

参考資料

AWS builders-flash:サーバーレスのイベントバスって何 ? Amazon EventBridge をグラレコで解説

classmethod:【小ネタ】ECSのタスクスケジュールはEventBridgeから登録するとタスク定義の最新リビジョンから起動できる

AWS Devガイド:スケジュールされたタスク

 

最新情報をチェックしよう!