🕐

AWS CDK でコマンド指定して ECS Scheduled Task を作成する

に公開

ググってもあまり情報が出てこなったので備忘録として。

要件としては以下の通り。

  • cron式で ECS Task を定期実行したい
  • タスク定義を再利用し、コマンドだけルールごとに置き換える
  • ECS Console の スケジュールされたタスク に定義したルール群を表示させたい

結論から言えば、下記のように aws-cdk-lib/aws-eventsRule props の targetsaws-cdk-lib/aws-events-targetsEcsTask を指定してやれば良い。

もし CDK 外でタスク定義を更新している場合、基本的には最新のタスク定義を使わせたいはずなので、それらに関するコードも入れる必要がある(下記の前半部分)。

// 最新のタスク定義
// taskDefinitionArn を文字生成するのがポイント(cdk によって作られたタスク定義を再利用すると、作った時点のタスク定義リビジョンで起動してしまうため)
const cronTaskDefLatest = FargateTaskDefinition.fromFargateTaskDefinitionAttributes(this, "CronTaskDefLatest", {
  taskDefinitionArn: `arn:aws:ecs:${env.region}:${env.account}:task-definition/${ecsTaskDefName}`,
  taskRole: taskRole,
  networkMode: NetworkMode.AWS_VPC,
})

// EventBridge に ECS RunTask をさせる Role
// 本当はもう少し権限絞ったほうが良さげ?
const ecsEventsRole = new Role(this, "EcsEventsRole", {
  assumedBy: new ServicePrincipal("events.amazonaws.com"),
  managedPolicies: [ManagedPolicy.fromAwsManagedPolicyName("service-role/AmazonEC2ContainerServiceEventsRole")],
})

// containerOverrides.command で実行コマンドを上書きする
const target = new EcsTask({
  cluster: ecsCluster,
  taskDefinition: cronTaskDefLatest,
  taskCount: 1,
  containerOverrides: [
    {
      containerName: "app",
      command: ["command", "args1", "args2", ...],
    },
  ],
  subnetSelection: {
    subnetType: SubnetType.PRIVATE_WITH_EGRESS,
  },
  launchType: LaunchType.FARGATE,
  platformVersion: FargatePlatformVersion.VERSION1_4,
  securityGroups: [securityGroup],
  enableExecuteCommand: true,
  propagateTags: PropagatedTagSource.TASK_DEFINITION,
  executionRole: execRole,
  taskRole: taskRole,
  role: ecsEventsRole.withoutPolicyUpdates(),
})

new Rule(this, `Rule${name}`, {
  ruleName: `run_task_test`,
  schedule: Schedule.expression('cron(1 0 ? * * *)'),
  enabled: true,
  targets: [target],
})

Discussion