ECSで実行しているコンテナに対して、実行時間タイムアウトを実装する

これはなに?

ECSで実行しているコンテナに対して、Lambdaを使って実行時間タイムアウトの仕組みを実装します。

タスク定義にタイムアウトの項目があったので、それで実行時間タイムアウト指定できるかなと思ったのですが、依存関係のタイムアウトとコンテナを終了する際のタイムアウトでやりたい事と異なっていたので作りました。
タスク定義パラメータ - Amazon Elastic Container Service

必要なリソース

必要なリソースは以下の2つです。
一つのLambdaで複数のコンテナのタイムアウトを実装できるように、パラメータをパラメータストアに外だししています。

  • Systems Manager Parameter Store #各クラスター、タスク定義に対してのタイムアウト値の設定
  • Lambda #タイムアウトスクリプトの実行

構築

1. Systems Manager Parameter Store

パラメータストアを作成します。

  • パラメータストア名: 任意 ※Lambdaのパラメータで利用するのでメモしておいてください
    • <your_cluster_name> : タイムアウトを実装したいECS クラスター名
    • <your_task_def_name> : タイムアウトを実装したいタスク定義名
    • <timeout_hour> : タイムアウト時間

JSON形式でパラメータを記入します。
クラスター名 * タスク定義名 の組み合わせでタイムアウト時間を定義できるようにしています。

{
    "<your_cluster_nameA>": [
        {
            "task_def_name": "<your_task_def_name1>",
            "timeout": "<timeout_hour>"
        },
        {
            "task_def_name": "<your_task_def_name2>",
            "timeout": "<timeout_hour>"
        }
    ],
    "<your_cluster_nameB>": [
        {
            "task_def_name": "<your_task_def_name1>",
            "timeout": "<timeout_hour>"
        }
    ]
}

<例> f:id:ykoomaru:20200729220503p:plain

2. Lambda

次にLambdaを作成します。 Runtimeは、 Python3.8 です。

コードは以下の2点を環境に合わせて置き換えてください。後はコピペでOKです。

  • <your_aws_account_name> : AWSアカウントID
  • <your_paramater_store_name> : 1で作成したパラメータストア名 (例 /ecs/timeout

boto3 の ecs_client.describe_tasks でタスクの作成時間を取得、設定したタイムアウト値を超えていた場合はタスクを停止させます。

gist.github.com

github.com

これで、必要なコンポーネントは揃いました。

テスト

ECS上でコンテナを実行した状態でLambdaを実行します。# テストなのでタイムアウトを0にして実行しています。
以下Lambdaの実行結果です。 f:id:ykoomaru:20200729223711p:plain

Stop Task List にタイムアウトで停止したタスクのARNが表示されています。
停止したタスクのログをCloudwatchlogsで確認すると、タイムアウトで停止したことが確認できます。

f:id:ykoomaru:20200729224211p:plain

以上でECSの実行タイムアウトの設定は完了です。
後はLambdaをCloudWatchEventsで定期実行するように設定してあげれば、定期的にタイムアウトのチェックが実施できるようになります。

最後に

JenkinsからECSをタスクを実行した場合は、Jenkins側で実行時間タイムアウトが設定できたので、ECSでも同じように簡単に実施できるかなと思っていたら意外と大変でした。