🔰

【自分用】【備忘録】AWS Step Functions+ECSタスクのワークフロー

に公開

【備忘録】
Step functionsステートマシンでのECS(Fargate)タスク実行について
並列・直列実行ワークフロー定義を作成した。
※学習内容を備忘録として残す

■Step Functions ステートマシーン定義

直列実行定義(ECSタスク×2) 警告判定
{
  "StartAt": "ECS_TaskA",
  "States": {
    "ECS_TaskA": {
      "Type": "Task",
      "Resource": "arn:aws:states:::ecs:runTask.sync",
      "Parameters": {
        "LaunchType": "FARGATE",
        "Cluster": "",
        "TaskDefinition": "",
        "NetworkConfiguration": {
          "AwsvpcConfiguration": {
            "Subnets": [
              "subnet-020bfb42a62070fd0",
              "subnet-0f76b85fd4ec253be"
            ],
            "SecurityGroups": [
              "sg-0a952161376b08a81"
            ],
            "AssignPublicIp": "ENABLED"
          }
        }
      },
      "Catch": [
        {
          "ErrorEquals": [
            "States.ALL"
          ],
          "ResultPath": "$.error",
          "Next": "警告判定(A)"
        }
      ],
      "Next": "ECS_TaskB"
    },
    "警告判定(A)": {
      "Type": "Choice",
      "Choices": [
        {
          "Variable": "$.error.Cause",
          "StringMatches": "*\"ExitCode\":9*",
          "Next": "ECS_TaskB"
        }
      ],
      "Default": "異常終了"
    },
    "ECS_TaskB": {
      "Type": "Task",
      "Resource": "arn:aws:states:::ecs:runTask.sync",
      "Parameters": {
        "LaunchType": "FARGATE",
        "Cluster": "",
        "TaskDefinition": "",
        "NetworkConfiguration": {
          "AwsvpcConfiguration": {
            "Subnets": [
              "subnet-020bfb42a62070fd0",
              "subnet-0f76b85fd4ec253be"
            ],
            "SecurityGroups": [
              "sg-0a952161376b08a81"
            ],
            "AssignPublicIp": "ENABLED"
          }
        }
      },
      "Catch": [
        {
          "ErrorEquals": [
            "States.ALL"
          ],
          "Next": "警告判定(B)",
          "ResultPath": "$.error"
        }
      ],
      "End": true
    },
    "警告判定(B)": {
      "Type": "Choice",
      "Choices": [
        {
          "Variable": "$.error.Cause",
          "StringMatches": "*\"ExitCode\":9*",
          "Next": "警告判定(ExitCode:9)"
        }
      ],
      "Default": "異常終了"
    },
    "警告判定(ExitCode:9)": {
      "Type": "Succeed"
    },
    "異常終了": {
      "Type": "Fail",
      "Error": "UnexpectedFailure",
      "Cause": "ExitCode が 0, 9 以外の異常終了"
    }
  }
}
直列実行定義(ECSタスク×2) 警告判定 CFn
AWSTemplateFormatVersion: '2010-09-09'
Resources:
  StateMachinec7bf56b8:
    Type: AWS::StepFunctions::StateMachine
    Properties:
      Definition:
        StartAt: ECS_TaskA
        States:
          ECS_TaskA:
            Type: Task
            Resource: arn:aws:states:::ecs:runTask.sync
            Parameters:
              LaunchType: FARGATE
              Cluster: [クラスターARN]
              TaskDefinition: [タスク定義ARN]
              NetworkConfiguration:
                AwsvpcConfiguration:
                  Subnets:
                    - subnet-020bfb42a62070fd0
                    - subnet-0f76b85fd4ec253be
                  SecurityGroups:
                    - sg-0a952161376b08a81
                  AssignPublicIp: ENABLED
            Catch:
              - ErrorEquals:
                  - States.ALL
                ResultPath: $.error
                Next: 警告判定(A)
            Next: ECS_TaskB

          警告判定(A):
            Type: Choice
            Choices:
              - Variable: $.error.Cause
                StringMatches: '*"ExitCode":9*'
                Next: ECS_TaskB
            Default: 異常終了

          ECS_TaskB:
            Type: Task
            Resource: arn:aws:states:::ecs:runTask.sync
            Parameters:
              LaunchType: FARGATE
              Cluster: [クラスターARN]
              TaskDefinition: [タスク定義ARN]
              NetworkConfiguration:
                AwsvpcConfiguration:
                  Subnets:
                    - subnet-020bfb42a62070fd0
                    - subnet-0f76b85fd4ec253be
                  SecurityGroups:
                    - sg-0a952161376b08a81
                  AssignPublicIp: ENABLED
            Catch:
              - ErrorEquals:
                  - States.ALL
                ResultPath: $.error
                Next: 警告判定(B)
            End: true

          警告判定(B):
            Type: Choice
            Choices:
              - Variable: $.error.Cause
                StringMatches: '*"ExitCode":9*'
                Next: 警告判定(ExitCode:9)
            Default: 異常終了

          警告判定(ExitCode:9):
            Type: Succeed

          異常終了:
            Type: Fail
            Error: UnexpectedFailure
            Cause: ExitCode が 0, 9 以外の異常終了

      RoleArn: [IAMのARN]
      StateMachineName: StateMachinec7bf56b8
      StateMachineType: STANDARD
      EncryptionConfiguration:
        Type: AWS_OWNED_KEY
直列実行警告(ECSタスク×2) CFn定義詳細
プロパティ名 項目説明 設定根拠・意味
StateMachineName ステートマシンの名前 コンソールやCLI上で識別する名前として使用されます。
StateMachineType ステートマシンの種別(STANDARD or EXPRESS) STANDARD は長時間実行・高信頼、EXPRESS は高頻度/短時間向け。今回は標準型。
RoleArn ステートマシンが AWS サービスを操作するための IAM ロール ECS タスクの実行、ログ出力などを許可するために必要です。
EncryptionConfiguration.Type 実行履歴の暗号化方式 AWS_OWNED_KEY は AWS が自動管理するキーで暗号化します(デフォルト)。

♦︎定義内の各ステート(状態)

プロパティ名 項目説明 設定根拠・意味
StartAt ステートマシンの最初のステート名 実行が ECS_TaskA から始まることを指定します。
ECS_TaskA.Type / ECS_TaskB.Type タスク実行の型 Task 型で ECS タスクを同期実行(runTask.sync)します。
Resource 実行リソースのARN arn:aws:states:::ecs:runTask.sync は Step Functions から ECS タスクを同期実行するリソース指定です。
Parameters.LaunchType 実行タイプ FARGATE を指定することで、Fargateでの実行になります。
Parameters.Cluster 実行する ECS クラスターの ARN ECS タスクがどのクラスターで動くかを指定します。
Parameters.TaskDefinition 実行する ECS タスク定義 実行されるアプリケーション(Dockerコンテナ構成)を定義したリソースです。
NetworkConfiguration.AwsvpcConfiguration ネットワーク設定(VPC) 実行環境のサブネットやセキュリティグループを指定します。
Catch エラー発生時の処理先ステート States.ALL によりすべての例外をキャッチし、次の判断(Choice)に進めます。
警告判定(A/B).Type 条件分岐ステート エラー内容に "ExitCode":9 が含まれているかを判定します。
警告判定(ExitCode:9).Type 警告とみなして正常終了扱いにするステート Succeed を返して全体の処理を成功として終了させます。
異常終了.Type 異常終了を明示するステート Fail 型は明示的に失敗とするため、モニタリングや通知に活用できます。

<注記>
・StringMatches: '"ExitCode":9' の書き方は文字列として "ExitCode":9 が含まれているかを見るパターンマッチです。

・ResultPath: $.error によりエラー情報が $.error に格納され、Choice ステートで参照されます。

直列実行定義
{
  "Comment": "ECSタスク実行結果に基づいて異常終了原因を明示する構成 (ExitCode をエラー判断に活用)",
  "StartAt": "【先行】ECS RunTask ①",
  "States": {
    "【先行】ECS RunTask ①": {
      "Type": "Task",
      "Comment": "最初のECSタスク(正常系)を同期実行する",
      "Resource": "arn:aws:states:::ecs:runTask.sync",
      "Parameters": {
        "LaunchType": "FARGATE",
        "Cluster": "arn:aws:ecs:ap-northeast-1:{アカウントID}:cluster/2413882_test",
        "TaskDefinition": "arn:aws:ecs:ap-northeast-1:{アカウントID}:task-definition/2413882_Helloworld:7",
        "NetworkConfiguration": {
          "AwsvpcConfiguration": {
            "Subnets": [
              "subnet-020bfb42a62070fd0",
              "subnet-0f76b85fd4ec253be"
            ],
            "SecurityGroups": [
              "sg-0a952161376b08a81"
            ],
            "AssignPublicIp": "ENABLED"
          }
        }
      },
      "Retry": [
        {
          "ErrorEquals": [
            "States.ALL"
          ],
          "IntervalSeconds": 2,
          "MaxAttempts": 1,
          "BackoffRate": 1
        }
      ],
      "Catch": [
        {
          "ErrorEquals": [
            "States.ALL"
          ],
          "ResultPath": "$.error",
          "Next": "異常終了"
        }
      ],
      "Next": "【先行】ECS RunTask ②"
    },
    "【先行】ECS RunTask ②": {
      "Type": "Task",
      "Comment": "2つ目のECSタスク(正常/異常含む)を同期実行する",
      "Resource": "arn:aws:states:::ecs:runTask.sync",
      "Parameters": {
        "LaunchType": "FARGATE",
        "Cluster": "arn:aws:ecs:ap-northeast-1:{アカウントID}:cluster/2413882_test",
        "TaskDefinition": "arn:aws:ecs:ap-northeast-1:{アカウントID}:task-definition/2413882_Helloworld:6",
        "NetworkConfiguration": {
          "AwsvpcConfiguration": {
            "Subnets": [
              "subnet-020bfb42a62070fd0",
              "subnet-0f76b85fd4ec253be"
            ],
            "SecurityGroups": [
              "sg-0a952161376b08a81"
            ],
            "AssignPublicIp": "ENABLED"
          }
        }
      },
      "Retry": [
        {
          "ErrorEquals": [
            "States.ALL"
          ],
          "IntervalSeconds": 2,
          "MaxAttempts": 1,
          "BackoffRate": 1
        }
      ],
      "Catch": [
        {
          "ErrorEquals": [
            "States.ALL"
          ],
          "ResultPath": "$.error",
          "Next": "異常終了"
        }
      ],
      "Next": "成功"
    },
    "成功": {
      "Type": "Succeed",
      "Comment": "すべての処理が正常に終了した"
    },
    "異常終了": {
      "Type": "Fail",
      "Comment": "いずれかのECSタスクが異常終了した",
      "Cause": "ECSタスクが異常終了しました",
      "Error": "ECS.Fargate.ExitCode"
    }
  }
}
Overridesを用いてECSタスクにデータを渡す
{
  "StartAt": "【先行】ECS RunTask ①",
  "States": {
    "【後行】ECS RunTask ①": {
      "Type": "Task",
      "Resource": "arn:aws:states:::ecs:runTask.sync",
      "Parameters": {
        "LaunchType": "FARGATE",
        "Cluster": "[クラスターARN]",
        "TaskDefinition": "[タスク定義ARN]",
        "NetworkConfiguration": {
          "AwsvpcConfiguration": {
            "Subnets": [
              "subnet-020bfb42a62070fd0",
              "subnet-0f76b85fd4ec253be"
            ],
            "SecurityGroups": [
              "sg-0a952161376b08a81"
            ],
            "AssignPublicIp": "ENABLED"
          }
        },
        "Overrides": {
          "ContainerOverrides": [
            {
              "Name": "[コンテナ名]",
              "Command": [
                "sh",
                "-c",
                "echo Hello-world; exit 100"
              ]
            }
          ]
        }
      },
      "End": true
    }
  }
}
並列実行定義=Prallelが失敗したら、失敗とみなす
{
"Comment": "並列ECSジョブ + 条件分岐",
"StartAt": "並列ジョブ開始",
"States": {
"並列ジョブ開始": {
"Type": "Parallel",
"Branches": [
{
"StartAt": "ECS RunTask (Helloworld)",
"States": {
"ECS RunTask (Helloworld)": {
"Type": "Task",
"Resource": "arn:aws:states:::ecs:runTask.sync",
"Parameters": {
"LaunchType": "FARGATE",
"Cluster": "arn:aws:ecs:ap-northeast-1:{アカウントID}:cluster/2413882_test",
"TaskDefinition": "arn:aws:ecs:ap-northeast-1:{アカウントID}:task-definition/2413882_Helloworld:7",
"NetworkConfiguration": {
"AwsvpcConfiguration": {
"Subnets": [
"subnet-020bfb42a62070fd0",
"subnet-0f76b85fd4ec253be"
],
"SecurityGroups": [
"sg-0a952161376b08a81"
],
"AssignPublicIp": "ENABLED"
}
}
},
"End": true
}
}
},
{
"StartAt": "Run Task (Helloworld:202)",
"States": {
"Run Task (Helloworld:202)": {
"Type": "Task",
"Resource": "arn:aws:states:::ecs:runTask.sync",
"Parameters": {
"LaunchType": "FARGATE",
"Cluster": "arn:aws:ecs:ap-northeast-1:{アカウントID}:cluster/2413882_test",
"TaskDefinition": "arn:aws:ecs:ap-northeast-1:{アカウントID}:task-definition/2413882_Helloworld:8",
"NetworkConfiguration": {
"AwsvpcConfiguration": {
"Subnets": [
"subnet-020bfb42a62070fd0",
"subnet-0f76b85fd4ec253be"
],
"SecurityGroups": [
"sg-0a952161376b08a81"
],
"AssignPublicIp": "ENABLED"
}
}
},
"Retry": [
{
"ErrorEquals": [
"States.ALL"
],
"IntervalSeconds": 2,
"MaxAttempts": 1,
"BackoffRate": 1
}
],
"End": true
}
}
}
],
"Next": "Check If Success"
},
"Check If Success": {
"Type": "Choice",
"Choices": [
{
"Variable": "$[1].Containers[0].ExitCode",
"NumericEquals": 0,
"Next": "Final ECS RunTask"
}
],
"Default": "異常終了"
},
"Final ECS RunTask": {
"Type": "Task",
"Resource": "arn:aws:states:::ecs:runTask.sync",
"Parameters": {
"LaunchType": "FARGATE",
"Cluster": "arn:aws:ecs:ap-northeast-1:{アカウントID}:cluster/2413882_test",
"TaskDefinition": "arn:aws:ecs:ap-northeast-1:{アカウントID}:task-definition/2413882_Helloworld:7",
"NetworkConfiguration": {
"AwsvpcConfiguration": {
"Subnets": [
"subnet-020bfb42a62070fd0",
"subnet-0f76b85fd4ec253be"
],
"SecurityGroups": [
"sg-0a952161376b08a81"
],
"AssignPublicIp": "ENABLED"
}
}
},
"Next": "成功"
},
"成功": {
"Type": "Succeed"
},
"異常終了": {
"Type": "Fail",
"Error": "TaskFailed",
"Cause": "One or more parallel jobs failed"
}
}
}
並列実行定義=条件分岐(片方失敗しても、Prallel突破) ※後行ジョブは実行しない
{
"Comment": "並列ECSジョブ + 条件分岐",
"StartAt": "並列ジョブ開始",
"States": {
"並列ジョブ開始": {
"Type": "Parallel",
"Branches": [
{
"StartAt": "ECS RunTask (Helloworld①)",
"States": {
"ECS RunTask (Helloworld①)": {
"Type": "Task",
"Resource": "arn:aws:states:::ecs:runTask.sync",
"Parameters": {
"LaunchType": "FARGATE",
"Cluster": "arn:aws:ecs:ap-northeast-1:{アカウントID}:cluster/2413882_test",
"TaskDefinition": "arn:aws:ecs:ap-northeast-1:{アカウントID}:task-definition/2413882_Helloworld:7",
"NetworkConfiguration": {
"AwsvpcConfiguration": {
"Subnets": [
"subnet-020bfb42a62070fd0",
"subnet-0f76b85fd4ec253be"
],
"SecurityGroups": [
"sg-0a952161376b08a81"
],
"AssignPublicIp": "ENABLED"
}
}
},
"Catch": [
{
"ErrorEquals": [
"States.ALL"
],
"ResultPath": "$.error",
"Next": "SetExitCode①"
}
],
"End": true
},
"SetExitCode①": {
"Type": "Pass",
"Result": {
"ExitCode": "エラー"
},
"ResultPath": "$.Containers[0]",
"End": true
}
}
},
{
"StartAt": "Run Task (Helloworld②)",
"States": {
"Run Task (Helloworld②)": {
"Type": "Task",
"Resource": "arn:aws:states:::ecs:runTask.sync",
"Parameters": {
"LaunchType": "FARGATE",
"Cluster": "arn:aws:ecs:ap-northeast-1:{アカウントID}:cluster/2413882_test",
"TaskDefinition": "arn:aws:ecs:ap-northeast-1:{アカウントID}:task-definition/2413882_Helloworld:9",
"NetworkConfiguration": {
"AwsvpcConfiguration": {
"Subnets": [
"subnet-020bfb42a62070fd0",
"subnet-0f76b85fd4ec253be"
],
"SecurityGroups": [
"sg-0a952161376b08a81"
],
"AssignPublicIp": "ENABLED"
}
}
},
"Catch": [
{
"ErrorEquals": [
"States.ALL"
],
"ResultPath": "$.error",
"Next": "SetExitCode②"
}
],
"End": true
},
"SetExitCode②": {
"Type": "Pass",
"Result": {
"ExitCode": "エラー"
},
"ResultPath": "$.Containers[0]",
"End": true
}
}
}
],
"Next": "Check If Success"
},
"Check If Success": {
"Type": "Choice",
"Choices": [
{
"Variable": "$[0].Containers[0].ExitCode",
"NumericEquals": 0,
"Next": "Check Branch 2"
}
],
"Default": "異常終了"
},
"Check Branch 2": {
"Type": "Choice",
"Choices": [
{
"Variable": "$[1].Containers[0].ExitCode",
"NumericEquals": 0,
"Next": "Final ECS RunTask"
}
],
"Default": "異常終了"
},
"Final ECS RunTask": {
"Type": "Task",
"Resource": "arn:aws:states:::ecs:runTask.sync",
"Parameters": {
"LaunchType": "FARGATE",
"Cluster": "arn:aws:ecs:ap-northeast-1:{アカウントID}:cluster/2413882_test",
"TaskDefinition": "arn:aws:ecs:ap-northeast-1:{アカウントID}:task-definition/2413882_Helloworld:7",
"NetworkConfiguration": {
"AwsvpcConfiguration": {
"Subnets": [
"subnet-020bfb42a62070fd0",
"subnet-0f76b85fd4ec253be"
],
"SecurityGroups": [
"sg-0a952161376b08a81"
],
"AssignPublicIp": "ENABLED"
}
}
},
"Next": "成功"
},
"成功": {
"Type": "Succeed"
},
"異常終了": {
"Type": "Fail",
"Error": "TaskFailed",
"Cause": "One or more parallel jobs failed"
}
}
}
並列実行定義=条件分岐(片方失敗しても、Prallel突破、※後行ジョブも実行
{
  "Comment": "並列ECSジョブ + 条件分岐(OR 条件)",
  "StartAt": "並列ジョブ開始",
  "States": {
    "並列ジョブ開始": {
      "Type": "Parallel",
      "Branches": [
        {
          "StartAt": "【先行】ECS RunTask ①",
          "States": {
            "【先行】ECS RunTask ①": {
              "Type": "Task",
              "Resource": "arn:aws:states:::ecs:runTask.sync",
              "Parameters": {
                "LaunchType": "FARGATE",
                "Cluster": "arn:aws:ecs:ap-northeast-1:{アカウントID}:cluster/2413882_test",
                "TaskDefinition": "arn:aws:ecs:ap-northeast-1:{アカウントID}:task-definition/2413882_Helloworld:8",
                "NetworkConfiguration": {
                  "AwsvpcConfiguration": {
                    "Subnets": [
                      "subnet-020bfb42a62070fd0",
                      "subnet-0f76b85fd4ec253be"
                    ],
                    "SecurityGroups": [
                      "sg-0a952161376b08a81"
                    ],
                    "AssignPublicIp": "ENABLED"
                  }
                }
              },
              "Catch": [
                {
                  "ErrorEquals": [
                    "States.ALL"
                  ],
                  "ResultPath": "$.error",
                  "Next": "①エラーコードをChoiceへ渡す"
                }
              ],
              "End": true
            },
            "①エラーコードをChoiceへ渡す": {
              "Type": "Pass",
              "Result": {
                "ExitCode": 999
              },
              "ResultPath": "$.Containers[0]",
              "End": true
            }
          }
        },
        {
          "StartAt": "【先行】ECS RunTask ②",
          "States": {
            "【先行】ECS RunTask ②": {
              "Type": "Task",
              "Resource": "arn:aws:states:::ecs:runTask.sync",
              "Parameters": {
                "LaunchType": "FARGATE",
                "Cluster": "arn:aws:ecs:ap-northeast-1:{アカウントID}:cluster/2413882_test",
                "TaskDefinition": "arn:aws:ecs:ap-northeast-1:{アカウントID}task-definition/2413882_Helloworld:7",
                "NetworkConfiguration": {
                  "AwsvpcConfiguration": {
                    "Subnets": [
                      "subnet-020bfb42a62070fd0",
                      "subnet-0f76b85fd4ec253be"
                    ],
                    "SecurityGroups": [
                      "sg-0a952161376b08a81"
                    ],
                    "AssignPublicIp": "ENABLED"
                  }
                }
              },
              "Catch": [
                {
                  "ErrorEquals": [
                    "States.ALL"
                  ],
                  "ResultPath": "$.error",
                  "Next": "②エラーコードをChoiceへ渡す"
                }
              ],
              "End": true
            },
            "②エラーコードをChoiceへ渡す": {
              "Type": "Pass",
              "Result": {
                "ExitCode": 999
              },
              "ResultPath": "$.Containers[0]",
              "End": true
            }
          }
        }
      ],
      "Next": "判定"
    },
    "判定": {
      "Type": "Choice",
      "Choices": [
        {
          "Or": [
            {
              "Variable": "$[0].Containers[0].ExitCode",
              "NumericEquals": 0
            },
            {
              "Variable": "$[1].Containers[0].ExitCode",
              "NumericEquals": 0
            }
          ],
          "Next": "【後行】ECS RunTask③"
        }
      ],
      "Default": "異常終了"
    },
    "【後行】ECS RunTask③": {
      "Type": "Task",
      "Resource": "arn:aws:states:::ecs:runTask.sync",
      "Parameters": {
        "LaunchType": "FARGATE",
        "Cluster": "arn:aws:ecs:ap-northeast-1:{アカウントID}:cluster/2413882_test",
        "TaskDefinition": "arn:aws:ecs:ap-northeast-1:{アカウントID}:task-definition/2413882_Helloworld:8",
        "NetworkConfiguration": {
          "AwsvpcConfiguration": {
            "Subnets": [
              "subnet-020bfb42a62070fd0",
              "subnet-0f76b85fd4ec253be"
            ],
            "SecurityGroups": [
              "sg-0a952161376b08a81"
            ],
            "AssignPublicIp": "ENABLED"
          }
        }
      },
      "Next": "成功",
      "Catch": [
        {
          "ErrorEquals": [
            "States.ALL"
          ],
          "Comment": "エラーキャッチ",
          "Next": "異常終了"
        }
      ]
    },
    "成功": {
      "Type": "Succeed"
    },
    "異常終了": {
      "Type": "Fail",
      "Cause": "ECSタスクが異常終了しました"
    }
  }
}
並列実行定義=条件分岐(片方失敗しても、Prallel突破、※後行ジョブも実行するが、各ジョブどれかエラーの場合は、ステートマシーンは失敗
{
"Comment": "並列ジョブ → 最終ジョブは常に実行 → 成否で分岐",
"StartAt": "並列ジョブ開始",
"States": {
"並列ジョブ開始": {
"Type": "Parallel",
"Branches": [
{
"StartAt": "ECS RunTask (Helloworld1)",
"States": {
"ECS RunTask (Helloworld1)": {
"Type": "Task",
"Resource": "arn:aws:states:::ecs:runTask.sync",
"Parameters": {
"LaunchType": "FARGATE",
"Cluster": "arn:aws:ecs:ap-northeast-1:{アカウントID}:cluster/2413882_test",
"TaskDefinition": "arn:aws:ecs:ap-northeast-1:{アカウントID}:task-definition/2413882_Helloworld:7",
"NetworkConfiguration": {
"AwsvpcConfiguration": {
"Subnets": [
"subnet-020bfb42a62070fd0",
"subnet-0f76b85fd4ec253be"
],
"SecurityGroups": [
"sg-0a952161376b08a81"
],
"AssignPublicIp": "ENABLED"
}
}
},
"Catch": [
{
"ErrorEquals": [
"States.ALL"
],
"ResultPath": "$.Containers[0]",
"Next": "SetError1"
}
],
"End": true
},
"SetError1": {
"Type": "Pass",
"Result": {
"ExitCode": 999
},
"ResultPath": "$.Containers[0]",
"End": true
}
}
},
{
"StartAt": "ECS RunTask (Helloworld2)",
"States": {
"ECS RunTask (Helloworld2)": {
"Type": "Task",
"Resource": "arn:aws:states:::ecs:runTask.sync",
"Parameters": {
"LaunchType": "FARGATE",
"Cluster": "arn:aws:ecs:ap-northeast-1:{アカウントID}:cluster/2413882_test",
"TaskDefinition": "arn:aws:ecs:ap-northeast-1:{アカウントID}4:task-definition/2413882_Helloworld:9",
"NetworkConfiguration": {
"AwsvpcConfiguration": {
"Subnets": [
"subnet-020bfb42a62070fd0",
"subnet-0f76b85fd4ec253be"
],
"SecurityGroups": [
"sg-0a952161376b08a81"
],
"AssignPublicIp": "ENABLED"
}
}
},
"Catch": [
{
"ErrorEquals": [
"States.ALL"
],
"ResultPath": "$.Containers[0]",
"Next": "SetError2"
}
],
"End": true
},
"SetError2": {
"Type": "Pass",
"Result": {
"ExitCode": 999
},
"ResultPath": "$.Containers[0]",
"End": true
}
}
}
],
"Next": "後行ジョブ"
},
"後行ジョブ": {
"Type": "Task",
"Resource": "arn:aws:states:::ecs:runTask.sync",
"Parameters": {
"LaunchType": "FARGATE",
"Cluster": "arn:aws:ecs:ap-northeast-1:{アカウントID}:cluster/2413882_test",
"TaskDefinition": "arn:aws:ecs:ap-northeast-1:{アカウントID}:task-definition/2413882_Helloworld:7",
"NetworkConfiguration": {
"AwsvpcConfiguration": {
"Subnets": [
"subnet-020bfb42a62070fd0",
"subnet-0f76b85fd4ec253be"
],
"SecurityGroups": [
"sg-0a952161376b08a81"
],
"AssignPublicIp": "ENABLED"
}
}
},
"Next": "判定"
},
"判定": {
"Type": "Choice",
"Choices": [
{
"Or": [
{
"Variable": "$[0].Containers[0].ExitCode",
"NumericEquals": 999
},
{
"Variable": "$[1].Containers[0].ExitCode",
"NumericEquals": 999
}
],
"Next": "異常終了"
}
],
"Default": "成功"
},
"成功": {
"Type": "Succeed"
},
"異常終了": {
"Type": "Fail",
"Cause": "1つ以上の並列ジョブが異常終了しました",
"Error": "ParallelJobFailed"
}
}
}

■直列・並列定義詳細を表で整理

直列実行定義詳細
項目 定義 詳細 設定根拠
処理構成 StartAt "StartAt": "[対象ECSタスク]"
最初に実行されるステートを定義
ステートマシンの開始地点を明示的に指定する必要があるため
ECSタスクの同期実行 Resource "Resource": "arn:aws:states:::ecs:runTask.sync"
ECSタスクの同期型起動
タスクの完了を待ち、終了コードに基づく次の処理を制御するため
Fargate実行設定 Parameters LaunchType, Cluster, TaskDefinition, NetworkConfiguration 等を定義 ECSタスクの実行環境(クラスタ、定義、NW設定)を指定するため
AwsvpcConfiguration Subnets, SecurityGroups, AssignPublicIp を指定 タスクのENI生成に必要であるため
再試行 Retry ErrorEquals: States.ALL
IntervalSeconds: 2
MaxAttempts: 1
BackoffRate: 1
一時的な失敗に対して自動再試行することで、ワークフローの耐久性を高めるため
エラーハンドリング Catch ErrorEquals: States.ALL
ResultPath: "$.error"
タスクが失敗した際、異常終了に制御を移すため
正常終了定義 成功状態 "Type": "Succeed" 成功時のステートマシン終了状態を明示するため
異常終了定義 異常終了状態 "Type": "Fail"
"Cause": "ECSタスクが異常終了しました"
"Error": "ECS.Exit"
失敗時のステートマシン終了状態を明示するため
並列実行定義詳細
大項目 中項目 詳細 設定根拠
処理構成 StartAt "StartAt": "[対象ECSタスク]"
最初に実行されるステートを定義
ステートマシンの開始地点を明示的に指定する必要があるため
ECSタスクの同期実行 Resource "Resource": "arn:aws:states:::ecs:runTask.sync"
ECSタスクの同期型起動
タスクの完了を待ち、終了コードに基づく次の処理を制御するため
Fargate実行設定 Parameters LaunchType, Cluster, TaskDefinition, NetworkConfiguration 等を定義 ECSタスクの実行環境(クラスタ、定義、NW設定)を指定するため
AwsvpcConfiguration Subnets, SecurityGroups, AssignPublicIp を指定 タスクのENI(Elastic Network Interface)生成に必要であるため
再試行 Retry ErrorEquals: States.ALL
IntervalSeconds: 2
MaxAttempts: 1
BackoffRate: 1
一時的な失敗に対して自動再試行することで、ワークフローの耐久性を高めるため
エラーハンドリング Catch ErrorEquals: States.ALL
ResultPath: "$.error"
タスクが失敗した際、”Pass”へ遷移させるため
エラーコードを"Choice"へ渡す Pass "Pass""ExitCode: 999"を Containers[0] に格納し、Choiceに使用できるようにする
Resultで固定値 "ExitCode: 999" を生成
ResultPathで出力データ構造を他と統一する
並列ジョブいずれか一方が失敗しても、後行ジョブを実行させるため
判定(正常 or 異常) Choice "Choice"
下記条件を設定することで、後行ジョブが実行する
※並列ジョブ両方失敗は、後行ジョブ実行しない
"Variable": "$[0].Containers[0].ExitCode" 並列ジョブ両方成功
"Variable":"$[1].Containers[0].ExitCode" 並列ジョブいずれか一方が失敗
後行ジョブ実行後、ステートマシーン全体が正常 or 異常と判定させるため
正常終了定義 成功状態 "Type": "Succeed" 成功時のステートマシン終了状態を明示するため
異常終了定義 異常終了状態 "Type": "Fail"
"Cause": "失敗したジョブがあります"
"Error": "ParallelJobFailed"
終了時のステートマシン終了状態を明示するため

■親,子ステートマシン CloudFormation(yml)で作成

親,子ステートマシンCFn
AWSTemplateFormatVersion: '2010-09-09'
Resources:

  Child1StateMachine:
    Type: AWS::StepFunctions::StateMachine
    Properties:
      Definition:
        StartAt: 子1ECSタスク
        States:
          子1ECSタスク:
            Type: Task
            Resource: arn:aws:states:::ecs:runTask.sync
            Parameters:
              LaunchType: FARGATE
              Cluster: !ImportValue MyECSClusterArn
              TaskDefinition: !ImportValue MyTaskDefinitionArn
              NetworkConfiguration:
                AwsvpcConfiguration:
                  Subnets:
                    - !ImportValue MySubnet1Id
                    - !ImportValue MySubnet2Id
                  SecurityGroups:
                    - !ImportValue MySecurityGroupId
                  AssignPublicIp: ENABLED
              Overrides:
                ContainerOverrides:
                  - Name: my-container-name
                    Command:
                      - sh
                      - '-c'
                      - echo Hello-world; exit 0
            End: true
      RoleArn: !ImportValue MyStepFunctionsRoleArn
      StateMachineName: Child1
      StateMachineType: STANDARD
      EncryptionConfiguration:
        Type: AWS_OWNED_KEY
      LoggingConfiguration:
        Level: 'OFF'
        IncludeExecutionData: false

  Child2StateMachine:
    Type: AWS::StepFunctions::StateMachine
    Properties:
      Definition:
        StartAt: 子2ECSタスク
        States:
          子2ECSタスク:
            Type: Task
            Resource: arn:aws:states:::ecs:runTask.sync
            Parameters:
              LaunchType: FARGATE
              Cluster: !ImportValue MyECSClusterArn
              TaskDefinition: !ImportValue MyTaskDefinitionArn
              NetworkConfiguration:
                AwsvpcConfiguration:
                  Subnets:
                    - !ImportValue MySubnet1Id
                    - !ImportValue MySubnet2Id
                  SecurityGroups:
                    - !ImportValue MySecurityGroupId
                  AssignPublicIp: ENABLED
              Overrides:
                ContainerOverrides:
                  - Name: my-container-name
                    Command:
                      - sh
                      - '-c'
                      - echo Hello-world; exit 0
            End: true
      RoleArn: !ImportValue MyStepFunctionsRoleArn
      StateMachineName: Child2
      StateMachineType: STANDARD
      EncryptionConfiguration:
        Type: AWS_OWNED_KEY
      LoggingConfiguration:
        Level: 'OFF'
        IncludeExecutionData: false

  PareStateMachine:
    Type: AWS::StepFunctions::StateMachine
    Properties:
      Definition:
        Comment: Parent state machine
        StartAt: '[先行]StartExecution'
        States:
          '[先行]StartExecution':
            Type: Task
            Resource: arn:aws:states:::states:startExecution.sync:2
            Parameters:
              StateMachineArn: !Ref Child1StateMachine
            Next: '[後行]StartExecution'

          '[後行]StartExecution':
            Type: Task
            Resource: arn:aws:states:::states:startExecution.sync:2
            Parameters:
              StateMachineArn: !Ref Child2StateMachine
            Next: '[先行]ECS RunTask'

          '[先行]ECS RunTask':
            Type: Task
            Resource: arn:aws:states:::ecs:runTask.sync
            Parameters:
              LaunchType: FARGATE
              Cluster: !ImportValue MyECSClusterArn
              TaskDefinition: !ImportValue MyTaskDefinitionArn
              NetworkConfiguration:
                AwsvpcConfiguration:
                  Subnets:
                    - !ImportValue MySubnet1Id
                    - !ImportValue MySubnet2Id
                  SecurityGroups:
                    - !ImportValue MySecurityGroupId
                  AssignPublicIp: ENABLED
              Overrides:
                ContainerOverrides:
                  - Name: my-container-name
                    Command:
                      - sh
                      - '-c'
                      - echo Hello-world; exit 0
            Next: '[後行]ECS RunTask'

          '[後行]ECS RunTask':
            Type: Task
            Resource: arn:aws:states:::ecs:runTask.sync
            Parameters:
              LaunchType: FARGATE
              Cluster: !ImportValue MyECSClusterArn
              TaskDefinition: !ImportValue MyTaskDefinitionArn
              NetworkConfiguration:
                AwsvpcConfiguration:
                  Subnets:
                    - !ImportValue MySubnet1Id
                    - !ImportValue MySubnet2Id
                  SecurityGroups:
                    - !ImportValue MySecurityGroupId
                  AssignPublicIp: ENABLED
              Overrides:
                ContainerOverrides:
                  - Name: my-container-name
                    Command:
                      - sh
                      - '-c'
                      - echo Hello-world; exit 0
            End: true
        QueryLanguage: JSONPath
      RoleArn: !ImportValue MyStepFunctionsRoleArn
      StateMachineName: Pare
      StateMachineType: STANDARD
      EncryptionConfiguration:
        Type: AWS_OWNED_KEY
      LoggingConfiguration:
        Level: 'OFF'
        IncludeExecutionData: false

Outputs:
  Pare:
    Description: ARN of the parent Step Functions state machine
    Value: !Ref PareStateMachine
    Export:
      Name: Pare

  Child1:
    Description: ARN of the first child Step Functions state machine
    Value: !Ref Child1StateMachine
    Export:
      Name: Child1

  Child2:
    Description: ARN of the second child Step Functions state machine
    Value: !Ref Child2StateMachine
    Export:
      Name: Child2

EventBridgeスケジュール,スケジュールグループ
AWSTemplateFormatVersion: '2010-09-09'
Resources:

  # EventBridgeスケジュールグループ作成
  MyScheduleGroup:
    Type: AWS::Scheduler::ScheduleGroup
    Properties:
      Name: my-schedule-group
      Tags:
        - Key: Name
          Value: 計画操作

  # EventBridgeスケジュール作成
  MySchedule:
    Type: AWS::Scheduler::Schedule
    Properties:
      Name: my-schedule-job
      GroupName: !Ref MyScheduleGroup
      Description: stepfunctions-test
      ScheduleExpression: 'cron(0 10 * * ? *)'
      ScheduleExpressionTimezone: Asia/Tokyo
      FlexibleTimeWindow:
        Mode: "OFF"
      Target:
        Arn: !ImportValue Pare   # ← 親ステートマシンの出力名 'Pare' を参照
        RoleArn: [IAM]
        Input: '{}'
        RetryPolicy:
          MaximumRetryAttempts: 0
          MaximumEventAgeInSeconds: 60

Outputs:
  ScheduleGroupArn:
    Description: ARN of the EventBridge schedule group
    Value: !Sub arn:aws:scheduler:${AWS::Region}:${AWS::AccountId}:schedule-group/my-schedule-group
    Export:
      Name: ScheduleGroupArn

  ScheduleArn:
    Description: ARN of the EventBridge schedule
    Value: !Sub arn:aws:scheduler:${AWS::Region}:${AWS::AccountId}:schedule/my-schedule-group/my-schedule-job
    Export:
      Name: ScheduleArn


・DLQを使いたいときだけ DeadLetterConfig を明示
・[MaximumEventAgeInSeconds: 60]について
たとえ GUI 上で「再試行ポリシー」をオフにしても、
AWS EventBridge Scheduler の裏側では イベント自体の「最大生存期間(Event Age)」として 24時間(= 86400秒) がデフォルトとして使われる

機能 明記しなかった場合のデフォルト OFFにしたいときに必要な書き方
再試行ポリシー(RetryPolicy) ON(再試行される) RetryPolicy: { MaximumRetryAttempts: 0 }
デッドレターキュー(DLQ) OFF(使用されない) DeadLetterConfig: { Arn: ... }記載しなければOFFのまま
プロパティ名 項目説明 設定根拠
Name スケジュールの一意な名前 GUIの「スケジュール名」欄に相当
GroupName 紐づくスケジュールグループの名前(上記の Name を参照) GUIで「スケジュールグループを選択」で設定
Description スケジュールの説明テキスト GUIの「説明」欄に入力される
ScheduleExpression 実行スケジュール(cron形式)
cron(0 1 * * ? *) は JSTで毎日10:00
GUIの「スケジュール(cron/rate)」に相当。UTCベースのためJST換算で 10:00実行になる
FlexibleTimeWindow.Mode 実行時間の柔軟性を許容するか
"OFF" = 固定時間に実行
GUIの「柔軟な時間ウィンドウ」をオフにした状態
Target.Arn 実行先の Step Functions の ARN GUIで「ターゲット」→ Step Functions 選択で指定
Target.RoleArn EventBridge スケジューラがターゲットを実行するための IAM ロール GUIで指定する「IAM 実行ロール」に相当
Target.Input ターゲットへ渡す入力 JSON GUIで「入力パラメータ(JSON形式)」に相当。ここでは空の {} を指定
RetryPolicy.MaximumRetryAttempts ターゲットが失敗した場合の最大再試行回数(ここでは再試行なし) GUIで「再試行ポリシー」→ オフにしたときと同様
RetryPolicy.MaximumEventAgeInSeconds 最大でイベントを保持する時間(秒)
60秒=1分以内に実行できなければ中断
GUIでは非表示だが、CLI/IaCで明示しないとデフォルト(86400秒=24時間)が適用されるため明示指定が必要

・公式ドキュメント
When retry policy is not specified, the scheduler uses a default MaximumEventAgeInSeconds of 86400 seconds (24 hours).
https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-scheduler-schedulegroup.html
https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-scheduler-schedule.html

IAMポリシー

events:PutEvents
カスタムイベントを EventBridge に送信するための権限
Step Functions が ECS タスクの終了を検知するために使う EventBridge 機能では、PutEvents は使わない

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowRunAndMonitorECSTask",
            "Effect": "Allow",
            "Action": [
                "ecs:RunTask",
                "ecs:StopTask",
                "ecs:DescribeTasks"
            ],
            "Resource": "*"
        },
        {
            "Sid": "AllowPassTaskRole",
            "Effect": "Allow",
            "Action": "iam:PassRole",
            "Resource": "arn:aws:iam::{アカウントID}:role/ecsTaskExecutionRole"
        },
        {
            "Sid": "AllowEventBridgeSyncForECS",
            "Effect": "Allow",
            "Action": [
                "events:PutTargets",
                "events:PutRule",
                "events:DescribeRule"
            ],
            "Resource": "*"
        },
        {
            "Sid": "AllowStartChildStepFunction",
            "Effect": "Allow",
            "Action": [
                "states:StartExecution",
                "states:DescribeExecution"
            ],
            "Resource": "*"
        },
        {
            "Sid": "AllowCloudWatchLogsAccess",
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogDelivery",
                "logs:GetLogDelivery",
                "logs:UpdateLogDelivery",
                "logs:DeleteLogDelivery",
                "logs:ListLogDeliveries",
                "logs:PutResourcePolicy",
                "logs:DescribeResourcePolicies",
                "logs:DescribeLogGroups"
            ],
            "Resource": "*"
        }
    ]
}

Sid Action一覧 Resourceの範囲 説明
AllowRunAndMonitorECSTask - ecs:RunTask
- ecs:StopTask
- ecs:DescribeTasks
*(全てのECSタスク) Step Functions から ECS タスクを起動・停止・状態確認するために必要な権限
AllowPassTaskRole - iam:PassRole arn:aws:iam::{アカウントID}:role/ecsTaskExecutionRole ECS タスクに割り当てる実行ロール(Task Execution Role)を許可。ARN指定で最小権限を遵守
AllowEventBridgeSyncForECS - events:PutTargets
- events:PutRule
- events:DescribeRule
*(イベントルール一式) runTask.sync の内部処理で必要な EventBridge の同期ルール作成と管理に必要
AllowStartChildStepFunction - states:StartExecution
- states:DescribeExecution
*(すべての Step Functions) 子ステートマシン(サブステートマシン)を起動・状態確認するための権限
AllowCloudWatchLogsAccess - logs:CreateLogDelivery
- logs:GetLogDelivery
- logs:UpdateLogDelivery
- logs:DeleteLogDelivery
- logs:ListLogDeliveries
- logs:PutResourcePolicy
- logs:DescribeResourcePolicies
- logs:DescribeLogGroups
*(CloudWatch Logs 関連リソース) ステートマシン実行ログを CloudWatch Logs に出力するために必要な一連の操作

iam:PassRole の Resource はセキュリティ観点から 明示された1つのロールに限定

events:* 系のアクションは、Step Functions から ECS を同期実行 (runTask.sync) する場合に AWS が 内部的に EventBridge ルールを作成するため必要

states:* の権限で、Step Functions の中から 子ステートマシンを起動できる

logs:* は、Step Functions の 実行ログやトレースを CloudWatch に出力するために必要

Discussion