ECS のタスク定義は、「どのイメージを、どれだけの CPU とメモリで、どんな環境変数とログ設定で動かすか」を書いた JSON で、Fargate で使う場合は family・networkMode(awsvpc)・cpu・memory・containerDefinitions の5つが土台になります。 ここに環境変数(environment)、機密情報(secrets)、ログ設定(logConfiguration)を足していくと、運用で使える形になります。

この記事では、Fargate 向けの最小の JSON から始めて、項目を1つずつ足した完成形までを、register-task-definition と describe-task-definition の出力つきで載せます。項目ごとの必須・任意と cpu・memory の組み合わせは早見表にし、describe の出力をそのまま再登録するときに削る項目、登録時に出るエラー文も扱います。

確認環境:Ubuntu 24.04 / AWS CLI 1.46.1 / jq 1.7。AWS の API をローカルで再現するツール(moto 5.2.3)で実行しています。掲載コマンドは接続先の指定を外してあり、実際の AWS でそのまま使える形です。アカウント ID は 123456789012、リージョンは ap-northeast-1 で統一しています。Fargate に固有の要件(ネットワークモード、cpu と memory の組み合わせ、ロールが必要になる条件、secrets の書式)は、AWS 公式ドキュメントの記載に沿っています。

タスク定義の項目早見表(Fargate)

タスク全体の項目

項目 Fargate での扱い 値の例 意味
family 必須 "web-app" タスク定義の名前。登録のたびにリビジョン番号が増える
containerDefinitions 必須 コンテナ定義の配列 動かすコンテナの設定
networkMode 必須(awsvpc) "awsvpc" Fargate のタスクは awsvpc を使う
cpu 必須 "256" タスク全体の CPU。文字列で書く
memory 必須 "512" タスク全体のメモリ(MiB)。文字列で書く
requiresCompatibilities 任意(書くのがおすすめ) ["FARGATE"] Fargate の要件を満たすかを登録時に確かめる指定
executionRoleArn 条件つきで必須 ロールの ARN ECR のプライベートリポジトリからの pull、awslogs、secrets を使うときに必要
taskRoleArn 任意 ロールの ARN コンテナの中のアプリが AWS の API を呼ぶときの権限
runtimePlatform 任意 {"cpuArchitecture":"X86_64","operatingSystemFamily":"LINUX"} CPU の種類と OS。省略時は X86_64 と LINUX

コンテナ定義(containerDefinitions の要素)の項目

項目 扱い 値の例 意味
name 必須 "web" コンテナの名前
image 必須 "...amazonaws.com/myapp/web:v1.2.0" イメージの URI。タグを省くと latest
essential 任意(省略時 true) true true のコンテナが止まると、タスク全体が止まる。少なくとも1つは true にする
portMappings 任意 [{"containerPort":8080}] 公開するポート。awsvpc では containerPort だけ書けばよい
environment 任意 [{"name":"APP_ENV","value":"production"}] 環境変数。値がそのまま JSON に残る
secrets 任意 [{"name":"DB_PASSWORD","valueFrom":"arn:..."}] Secrets Manager や Parameter Store の値を環境変数として渡す
logConfiguration 任意 {"logDriver":"awslogs","options":{...}} ログの送り先。Fargate で使えるのは awslogs・splunk・awsfirelens
healthCheck 任意 {"command":["CMD-SHELL","..."]} コンテナの中で実行するヘルスチェック

「必須」「任意」と値の決まりは、AWS 公式ドキュメント「Fargate の Amazon ECS タスク定義パラメータ」の記載に基づいています。

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「ECSタスク定義JSONの書き方|Fargate必須項目と環境変数secrets」

Fargate 向けの最小のタスク定義 JSON

次の JSON を taskdef-min.json として保存します。公開されている nginx のイメージを1つ動かすだけの形です。

{
  "family": "web-min",
  "networkMode": "awsvpc",
  "requiresCompatibilities": ["FARGATE"],
  "cpu": "256",
  "memory": "512",
  "containerDefinitions": [
    {
      "name": "web",
      "image": "public.ecr.aws/nginx/nginx:stable",
      "essential": true,
      "portMappings": [
        { "containerPort": 80, "protocol": "tcp" }
      ]
    }
  ]
}

登録する(register-task-definition)

aws ecs register-task-definition --cli-input-json file://taskdef-min.json
{
    "taskDefinition": {
        "taskDefinitionArn": "arn:aws:ecs:ap-northeast-1:123456789012:task-definition/web-min:1",
        "containerDefinitions": [
            {
                "name": "web",
                "image": "public.ecr.aws/nginx/nginx:stable",
                "cpu": 0,
                "portMappings": [
                    {
                        "containerPort": 80,
                        "protocol": "tcp"
                    }
                ],
                "essential": true,
                "environment": [],
                "mountPoints": [],
                "volumesFrom": []
            }
        ],
        "family": "web-min",
        "networkMode": "awsvpc",
        "revision": 1,
        "volumes": [],
        "status": "ACTIVE",
        "placementConstraints": [],
        …(省略)…
        "requiresCompatibilities": [
            "FARGATE"
        ],
        "cpu": "256",
        "memory": "512"
    }
}

出力から分かることは3つあります。

  • taskDefinitionArn の末尾の :1 がリビジョン番号です。同じ family で登録するたびに 2、3 と増えます
  • 書かなかった項目(コンテナの cpu、environment、mountPoints、volumesFrom、volumes など)が、既定値で補われて返ります
  • revision、status、taskDefinitionArn は ECS が付ける項目で、入力の JSON には書きません

各項目の書き方の注意

項目 注意
cpu / memory(タスク全体) 引用符で囲んだ文字列で書く。 数値で書くと CLI の検証で止まる(後述のエラー文)
networkMode Fargate では awsvpc。タスクごとに専用のネットワークインターフェイスが付く
portMappings awsvpc では containerPort だけを書く。hostPort は省くか、containerPort と同じ値にする
image ECR のプライベートリポジトリを使うときは、executionRoleArn も必要になる

JSON ファイルを使わずにオプションで渡す形

項目が少なければ、コンテナ定義だけをファイルにして、残りをオプションで渡すこともできます。containers.json は containerDefinitions の配列部分だけを取り出したものです。

aws ecs register-task-definition \
  --family web-cli \
  --network-mode awsvpc \
  --requires-compatibilities FARGATE \
  --cpu 256 --memory 512 \
  --container-definitions file://containers.json \
  --query 'taskDefinition.[family,revision,cpu,memory]' --output text
web-cli 1   256 512

項目が増えると --cli-input-json で1つのファイルにまとめるほうが、差分を追いやすくなります。使える項目の一覧は aws ecs register-task-definition --generate-cli-skeleton で出力できます。

cpu と memory の有効な組み合わせ早見表

Fargate では、cpu と memory は決まった組み合わせの中から選びます。 AWS 公式ドキュメントの表を、タスク定義に書く値(cpu は CPU ユニット、memory は MiB)に直すと次のようになります。MiB の値は 1 GB を 1024 として換算したものです。

cpu に書く値 vCPU memory に書ける値(MiB) 公式の表記 対応 OS
"256" 0.25 "512" "1024" "2048" 512 MiB、1 GB、2 GB Linux
"512" 0.5 "1024" "2048" "3072" "4096" 1〜4 GB Linux
"1024" 1 "2048" から "8192" まで 1024 刻み 2〜8 GB Linux、Windows
"2048" 2 "4096" から "16384" まで 1024 刻み 4〜16 GB(1 GB 刻み) Linux、Windows
"4096" 4 "8192" から "30720" まで 1024 刻み 8〜30 GB(1 GB 刻み) Linux、Windows
"8192" 8 "16384" から "61440" まで 4096 刻み 16〜60 GB(4 GB 刻み) Linux
"16384" 16 "32768" から "122880" まで 8192 刻み 32〜120 GB(8 GB 刻み) Linux
"32768" 32 "61440" "122880" "249856" 60 GB、120 GB、244 GB Linux

8 vCPU 以上は、Linux のプラットフォームバージョン 1.4.0 以降が必要です。

表にない組み合わせで登録すると、公式ドキュメント「Amazon ECS のタスク定義の無効な CPU またはメモリエラーのトラブルシューティング」によれば、AWS CLI では次のメッセージが返ります。

An error occurred (ClientException) when calling the RegisterTaskDefinition operation: Invalid 'cpu' setting for task.

同じページには、Terraform を使った場合は ClientException: No Fargate configuration exists for given values. と表示されることも載っています。どちらのメッセージも、まず上の表で cpu と memory の組を確かめるのが近道です。

環境変数を足す(environment)

機密ではない設定値は environment に書きます。name と value の組を並べる形です。

"environment": [
  { "name": "APP_ENV", "value": "production" },
  { "name": "LOG_LEVEL", "value": "info" }
]
  • value は文字列です。数値や真偽値も "8080" "true" のように引用符で囲みます
  • environment の値は、タスク定義の JSON にそのまま残ります。describe-task-definition を実行できる人なら誰でも読めるので、パスワードや API キーは次の secrets に書きます

機密情報を渡す(secrets と valueFrom の書式)

secrets は、値そのものではなく「値の置き場所」を書く項目です。タスクの起動時に ECS が Secrets Manager や Systems Manager Parameter Store から値を取り出し、name に書いた名前の環境変数としてコンテナに渡します。

"secrets": [
  {
    "name": "DB_PASSWORD",
    "valueFrom": "arn:aws:secretsmanager:ap-northeast-1:123456789012:secret:prod/web/db-AbCdEf:password::"
  },
  {
    "name": "API_TOKEN",
    "valueFrom": "arn:aws:ssm:ap-northeast-1:123456789012:parameter/prod/web/api-token"
  }
]

Secrets Manager の valueFrom

AWS 公式ドキュメント「Amazon ECS 環境変数を使用して Secrets Manager シークレットを渡す」に載っている書式です。

arn:aws:secretsmanager:region:aws_account_id:secret:secret-name:json-key:version-stage:version-id

後ろの3つ(json-key、version-stage、version-id)は省略できますが、省略するときもコロンは残します。

渡したいもの valueFrom の末尾 例
シークレット全体 何も付けない ...:secret:prod/web/db-AbCdEf
JSON の中の1つのキー :キー名:: ...:secret:prod/web/db-AbCdEf:password::
特定のステージの値 ::ステージ名: ...:secret:prod/web/db-AbCdEf::AWSPREVIOUS:
特定のバージョン ID の値 :::バージョンID ...:secret:prod/web/db-AbCdEf:::9d4cb84b-ad69-40c0-a0ab-cead3EXAMPLE
  • json-key を省くと、シークレットの中身全体が1つの環境変数に入ります。JSON で保存したシークレットなら、JSON の文字列がそのまま入ります
  • version-stage と version-id は同時には指定できません。どちらも省くと、現在の値(AWSCURRENT)が使われます
  • シークレット名の後ろの -AbCdEf は、Secrets Manager が ARN に付ける6文字です。ARN は aws secretsmanager describe-secret --secret-id 名前 --query ARN で確かめられます

Parameter Store の valueFrom

AWS 公式ドキュメント「Amazon ECS 環境変数を使用して Systems Manager パラメータを渡す」によると、書き方は2通りあります。

条件 書き方 例
タスクと同じリージョンのパラメータ 完全な ARN、またはパラメータ名 arn:aws:ssm:ap-northeast-1:123456789012:parameter/prod/web/api-token
別のリージョンのパラメータ 完全な ARN arn:aws:ssm:us-east-1:123456789012:parameter/prod/web/api-token

値が渡されるタイミング

どちらのページにも、機密情報はコンテナが最初に起動するときに渡され、あとでシークレットを更新・ローテーションしても、動いているコンテナには自動では反映されないと書かれています。新しい値を使うには、新しいタスクを起動するか、サービスを「新しいデプロイの強制」つきで更新します。

environment と secrets の使い分け

観点 environment secrets
タスク定義に残るもの 値そのもの 値の置き場所(ARN)
向いている値 動作モード、ログレベル、接続先のホスト名 パスワード、API キー、トークン
必要なロール なし executionRoleArn(値を読む権限つき)
値を変えたとき タスク定義を登録し直す タスクを起動し直す

ログ設定を足す(logConfiguration と awslogs)

コンテナの標準出力と標準エラー出力を CloudWatch Logs に送る設定です。

"logConfiguration": {
  "logDriver": "awslogs",
  "options": {
    "awslogs-group": "/ecs/web-app",
    "awslogs-region": "ap-northeast-1",
    "awslogs-stream-prefix": "web"
  }
}
オプション 扱い 意味
awslogs-group 必須 送り先のロググループ名
awslogs-region 必須 ロググループがあるリージョン
awslogs-stream-prefix 必須 ログストリーム名の先頭に付く文字列
awslogs-create-group 任意(既定は false) "true" にするとロググループを自動で作る
mode 任意 non-blocking または blocking
max-buffer-size 任意(既定は 10m) non-blocking のときのバッファの大きさ

この表は公式ドキュメントのタスク定義パラメータのページに基づいています。options の値もすべて文字列で書きます。

awslogs を使うときは executionRoleArn が必要です。ロググループを先に作っておく場合は、次のコマンドを使います。

aws logs create-log-group --log-group-name /ecs/web-app

2つのロール:executionRoleArn と taskRoleArn

名前が似ていますが、使う場面が違います。

項目 誰が使うか 何のために使うか 必要になるとき
executionRoleArn(タスク実行ロール) ECS と Fargate のエージェント イメージの pull、ログの送信、secrets の取得 ECR のプライベートリポジトリ、awslogs、secrets のどれかを使うとき
taskRoleArn(タスクロール) コンテナの中のアプリ アプリが AWS の API(S3 や DynamoDB など)を呼ぶ アプリが AWS のサービスを使うとき

タスク実行ロールを作る

信頼ポリシーを ecs-tasks-trust-policy.json として保存します。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": { "Service": "ecs-tasks.amazonaws.com" },
      "Action": "sts:AssumeRole"
    }
  ]
}
aws iam create-role \
  --role-name ecsTaskExecutionRole \
  --assume-role-policy-document file://ecs-tasks-trust-policy.json \
  --query Role.Arn
"arn:aws:iam::123456789012:role/ecsTaskExecutionRole"

AWS 公式ドキュメント「Amazon ECS タスク実行 IAM ロール」では、続けて管理ポリシー AmazonECSTaskExecutionRolePolicy を付ける手順が載っています。

aws iam attach-role-policy \
  --role-name ecsTaskExecutionRole \
  --policy-arn arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy

secrets を使うときに足す権限

secrets を使う場合は、タスク実行ロールに「値を読む権限」を足します。次の JSON を secrets-access.json として保存し、インラインポリシーとして付けます。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "secretsmanager:GetSecretValue",
        "ssm:GetParameters"
      ],
      "Resource": [
        "arn:aws:secretsmanager:ap-northeast-1:123456789012:secret:prod/web/db-AbCdEf",
        "arn:aws:ssm:ap-northeast-1:123456789012:parameter/prod/web/api-token"
      ]
    }
  ]
}
aws iam put-role-policy \
  --role-name ecsTaskExecutionRole \
  --policy-name secrets-access \
  --policy-document file://secrets-access.json

Resource には、valueFrom に書いたシークレットやパラメータだけを並べると、読める範囲を必要な分に絞れます。公式ドキュメントの例には、この2つのアクションに加えて kms:Decrypt と鍵の ARN も含まれています。

完成形のタスク定義 JSON

ここまでの項目をまとめた形です。taskdef-full.json として保存します。

{
  "family": "web-app",
  "networkMode": "awsvpc",
  "requiresCompatibilities": ["FARGATE"],
  "cpu": "512",
  "memory": "1024",
  "executionRoleArn": "arn:aws:iam::123456789012:role/ecsTaskExecutionRole",
  "taskRoleArn": "arn:aws:iam::123456789012:role/web-app-task-role",
  "runtimePlatform": {
    "cpuArchitecture": "X86_64",
    "operatingSystemFamily": "LINUX"
  },
  "containerDefinitions": [
    {
      "name": "web",
      "image": "123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/myapp/web:v1.2.0",
      "essential": true,
      "portMappings": [
        { "containerPort": 8080, "protocol": "tcp" }
      ],
      "environment": [
        { "name": "APP_ENV", "value": "production" },
        { "name": "LOG_LEVEL", "value": "info" }
      ],
      "secrets": [
        {
          "name": "DB_PASSWORD",
          "valueFrom": "arn:aws:secretsmanager:ap-northeast-1:123456789012:secret:prod/web/db-AbCdEf:password::"
        },
        {
          "name": "API_TOKEN",
          "valueFrom": "arn:aws:ssm:ap-northeast-1:123456789012:parameter/prod/web/api-token"
        }
      ],
      "logConfiguration": {
        "logDriver": "awslogs",
        "options": {
          "awslogs-group": "/ecs/web-app",
          "awslogs-region": "ap-northeast-1",
          "awslogs-stream-prefix": "web"
        }
      },
      "healthCheck": {
        "command": ["CMD-SHELL", "curl -f http://localhost:8080/health || exit 1"],
        "interval": 30,
        "timeout": 5,
        "retries": 3,
        "startPeriod": 10
      }
    }
  ]
}

healthCheck の command はコンテナの中で実行されるので、イメージに curl が入っていることが前提です。interval は 5〜300 秒、timeout は 2〜60 秒、retries は 1〜10 回、startPeriod は 0〜300 秒の範囲で指定します(公式ドキュメントのタスク定義パラメータより)。ARM 向けのイメージを使うときは、cpuArchitecture を ARM64 にします。

登録して確かめる

aws ecs register-task-definition --cli-input-json file://taskdef-full.json \
  --query 'taskDefinition.[taskDefinitionArn,status]'
[
    "arn:aws:ecs:ap-northeast-1:123456789012:task-definition/web-app:1",
    "ACTIVE"
]

登録した内容を見る(describe-task-definition)

aws ecs describe-task-definition --task-definition web-app
{
    "taskDefinition": {
        "taskDefinitionArn": "arn:aws:ecs:ap-northeast-1:123456789012:task-definition/web-app:1",
        "containerDefinitions": [
            {
                "name": "web",
                "image": "123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/myapp/web:v1.2.0",
                "cpu": 0,
                "portMappings": [
                    {
                        "containerPort": 8080,
                        "protocol": "tcp"
                    }
                ],
                "essential": true,
                "environment": [
                    {
                        "name": "APP_ENV",
                        "value": "production"
                    },
                    {
                        "name": "LOG_LEVEL",
                        "value": "info"
                    }
                ],
                "mountPoints": [],
                "volumesFrom": [],
                "secrets": [
                    {
                        "name": "DB_PASSWORD",
                        "valueFrom": "arn:aws:secretsmanager:ap-northeast-1:123456789012:secret:prod/web/db-AbCdEf:password::"
                    },
                    {
                        "name": "API_TOKEN",
                        "valueFrom": "arn:aws:ssm:ap-northeast-1:123456789012:parameter/prod/web/api-token"
                    }
                ],
                "logConfiguration": {
                    "logDriver": "awslogs",
                    "options": {
                        "awslogs-group": "/ecs/web-app",
                        "awslogs-region": "ap-northeast-1",
                        "awslogs-stream-prefix": "web"
                    }
                },
                "healthCheck": {
                    …(省略)…
                }
            }
        ],
        "family": "web-app",
        "taskRoleArn": "arn:aws:iam::123456789012:role/web-app-task-role",
        "executionRoleArn": "arn:aws:iam::123456789012:role/ecsTaskExecutionRole",
        "networkMode": "awsvpc",
        "revision": 1,
        "volumes": [],
        "status": "ACTIVE",
        "placementConstraints": [],
        …(省略)…
        "runtimePlatform": {
            "cpuArchitecture": "X86_64",
            "operatingSystemFamily": "LINUX"
        },
        "requiresCompatibilities": [
            "FARGATE"
        ],
        "cpu": "512",
        "memory": "1024"
    }
}

secrets は valueFrom の ARN のまま返り、値そのものは出力に現れません。 environment の値はそのまま見えます。

--task-definition の指定のしかたで、取れるリビジョンが変わります。

指定 取れるもの
web-app その family の、ACTIVE な最新リビジョン
web-app:1 リビジョン 1
完全な ARN その ARN のリビジョン

一部だけ確かめたいときは --query を使います。

aws ecs describe-task-definition --task-definition web-app \
  --query 'taskDefinition.containerDefinitions[0].[name,image,logConfiguration.options."awslogs-group"]'
[
    "web",
    "123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/myapp/web:v1.2.0",
    "/ecs/web-app"
]

特定の環境変数の値だけを取り出す例です。

aws ecs describe-task-definition --task-definition web-app \
  --query 'taskDefinition.containerDefinitions[0].environment[?name==`APP_ENV`].value | [0]' \
  --output text
production

describe の出力を再登録するときに削る項目

「今のタスク定義を取り出して、少し変えて登録し直す」はよく使う流れです。ただし、describe-task-definition の出力には ECS が付けた項目が混ざっているので、そのままでは登録できません。

aws ecs describe-task-definition --task-definition web-app \
  --query taskDefinition > described.json
aws ecs register-task-definition --cli-input-json file://described.json
Parameter validation failed:
Unknown parameter in input: "taskDefinitionArn", must be one of: family, taskRoleArn, executionRoleArn, networkMode, containerDefinitions, volumes, placementConstraints, requiresCompatibilities, cpu, memory, tags, pidMode, ipcMode, proxyConfiguration, inferenceAccelerators, ephemeralStorage, runtimePlatform, enableFaultInjection
Unknown parameter in input: "revision", must be one of: …(省略)…
Unknown parameter in input: "status", must be one of: …(省略)…
Unknown parameter in input: "compatibilities", must be one of: …(省略)…

削る項目の一覧

AWS CLI 1.46.1 が持っている API の定義で、「describe の出力(taskDefinition)にあって、register の入力にない項目」を突き合わせた結果です。

削る項目 中身
taskDefinitionArn 登録時に ECS が付ける ARN
revision リビジョン番号
status ACTIVE / INACTIVE などの状態
requiresAttributes タスクを置くために必要な属性の一覧
compatibilities このタスク定義が使える起動タイプ
registeredAt 登録日時
registeredBy 登録した人やロール
deregisteredAt 登録解除の日時
deleteRequestedAt 削除を要求した日時

出力に含まれない項目もありますが、この9つをまとめて削る形にしておくと、どのタスク定義でも同じコマンドが使えます。 なお、タグ(tags)は describe の taskDefinition には含まれないので、付け直したい場合は登録時に --tags で指定します。

jq で削って再登録する

jq 'del(.taskDefinitionArn, .revision, .status, .requiresAttributes,
        .compatibilities, .registeredAt, .registeredBy,
        .deregisteredAt, .deleteRequestedAt)' described.json > cleaned.json

aws ecs register-task-definition --cli-input-json file://cleaned.json \
  --query 'taskDefinition.[family,revision]' --output text
web-app 2

リビジョン 2 として登録できました。

イメージのタグだけ変えて新しいリビジョンを作るスクリプト

デプロイのたびに使う「イメージだけ差し替えて登録し直す」処理を、1本にまとめた例です。

#!/usr/bin/env bash
# 使い方: ./new-revision.sh ファミリー名 コンテナ名 新しいイメージURI
set -euo pipefail

FAMILY="$1"
CONTAINER="$2"
IMAGE="$3"

aws ecs describe-task-definition --task-definition "$FAMILY" \
  --query taskDefinition --output json \
| jq --arg c "$CONTAINER" --arg img "$IMAGE" '
    del(.taskDefinitionArn, .revision, .status, .requiresAttributes,
        .compatibilities, .registeredAt, .registeredBy,
        .deregisteredAt, .deleteRequestedAt)
    | (.containerDefinitions[] | select(.name == $c) | .image) = $img
  ' > next.json

aws ecs register-task-definition --cli-input-json file://next.json \
  --query 'taskDefinition.[taskDefinitionArn,containerDefinitions[0].image]' \
  --output text
$ ./new-revision.sh web-app web 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/myapp/web:v1.3.0
arn:aws:ecs:ap-northeast-1:123456789012:task-definition/web-app:3   123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/myapp/web:v1.3.0

リビジョン 3 が v1.3.0 のイメージで登録されました。リビジョン 1 は v1.2.0 のまま残っているので、戻したいときはサービスにリビジョン 1 を指定し直せます。

aws ecs describe-task-definition --task-definition web-app:1 \
  --query 'taskDefinition.containerDefinitions[0].image' --output text
123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/myapp/web:v1.2.0

リビジョンを一覧・登録解除・削除する

aws ecs list-task-definitions --family-prefix web-app
{
    "taskDefinitionArns": [
        "arn:aws:ecs:ap-northeast-1:123456789012:task-definition/web-app:1",
        "arn:aws:ecs:ap-northeast-1:123456789012:task-definition/web-app:2",
        "arn:aws:ecs:ap-northeast-1:123456789012:task-definition/web-app:3"
    ]
}

使わなくなったリビジョンは、登録解除(deregister)してから削除(delete)する、の2段階で片付けます。

aws ecs deregister-task-definition --task-definition web-app:1 \
  --query 'taskDefinition.[taskDefinitionArn,status]'
[
    "arn:aws:ecs:ap-northeast-1:123456789012:task-definition/web-app:1",
    "INACTIVE"
]

登録解除したリビジョンは既定の一覧から外れ、--status INACTIVE を付けると表示されます。

aws ecs list-task-definitions --family-prefix web-app --status INACTIVE
{
    "taskDefinitionArns": [
        "arn:aws:ecs:ap-northeast-1:123456789012:task-definition/web-app:1"
    ]
}
aws ecs delete-task-definitions --task-definitions web-app:1 \
  --query '[taskDefinitions[].[taskDefinitionArn,status],failures]'
[
    [
        [
            "arn:aws:ecs:ap-northeast-1:123456789012:task-definition/web-app:1",
            "DELETE_IN_PROGRESS"
        ]
    ],
    []
]

ACTIVE のまま削除しようとすると、コマンドは終了しますが failures に理由が入ります。

aws ecs delete-task-definitions --task-definitions web-app:2 \
  --query '[taskDefinitions[].status,failures]'
[
    [],
    [
        {
            "arn": "web-app:2",
            "reason": "The specified task definition is still in ACTIVE status. Please deregister the target and try again."
        }
    ]
]

登録時に出るエラー文と直し方

実行して確かめたメッセージ

書き方 出たメッセージ 直し方
family を書いていない Parameter validation failed: Missing required parameter in input: "family" family を足す
cpu を数値で書いた("cpu": 256) Parameter validation failed: Invalid type for parameter cpu, value: 256, type: <class 'int'>, valid types: <class 'str'> "cpu": "256" と引用符で囲む
describe の出力をそのまま渡した Unknown parameter in input: "revision", must be one of: family, taskRoleArn, ... 前の章の9項目を削る
JSON のカンマが抜けている Error parsing parameter 'cli-input-json': Invalid JSON: Expecting ',' delimiter: line 12 column 7 (char 266) メッセージの行と列を見て直す
file:// を付けずにファイル名だけ渡した Error parsing parameter 'cli-input-json': Invalid JSON: Expecting value: line 1 column 1 (char 0) と JSON received: taskdef-min.json --cli-input-json file://taskdef-min.json にする
ファイル名を間違えた Unable to load paramfile file://nofile.json: [Errno 2] No such file or directory: 'nofile.json' パスを確かめる
コンテナの image を書いていない ClientException ... Container.image should not be null or empty. image を足す
コンテナの name を書いていない ClientException ... Container.name should not be null or empty. name を足す
タスク全体にもコンテナにもメモリを書いていない ClientException ... Invalid setting for container 'web'. At least one of 'memory' or 'memoryReservation' must be specified. タスク全体の memory(Fargate では必須)を足す
無いリビジョンを describe した ClientException ... DescribeTaskDefinition operation: Unable to describe task definition. aws ecs list-task-definitions --family-prefix 名前 で番号を確かめる
deregister でリビジョンを省いた ClientException ... DeregisterTaskDefinition operation: Revision is missing. web-app:1 のように番号まで書く
11 個以上をまとめて delete した InvalidParameterException ... Size of TaskDefinition references list cannot exceed 10 10 個以下に分けて実行する

「Parameter validation failed」と「Error parsing parameter」で始まるものは、AWS に送る前に CLI が手元で止めたものです。JSON の形や型の問題なので、ファイルを見直せば解決します。「An error occurred (ClientException)」は AWS 側で内容を確かめた結果です。

JSON の文法だけを先に確かめたいときは、jq . taskdef-full.json > /dev/null を実行すると、問題があれば行と列が表示されます。

Fargate の要件に関するチェック表

Fargate に固有の要件は、公式ドキュメントの記載をもとに、登録の前に次の表で確かめます。

確かめること 公式ドキュメントの記載
networkMode が awsvpc になっているか Fargate のタスクには awsvpc ネットワークモードが必要
タスク全体の cpu と memory を書いているか Fargate ではタスクレベルの cpu と memory が必要。コンテナ単位の値は任意
cpu と memory が有効な組み合わせか 早見表の組み合わせから選ぶ。合わないと Invalid 'cpu' setting for task.
executionRoleArn を書いているか ECR のプライベートリポジトリからの pull、awslogs、secrets を使うときに必要
ログドライバーが対応しているか Fargate で使えるのは awslogs・splunk・awsfirelens
Fargate で使えない項目を書いていないか disableNetworking、dnsSearchDomains、dnsServers、dockerSecurityOptions、extraHosts、gpu、ipcMode、links、placementConstraints、privileged、maxSwap、swappiness

requiresCompatibilities に FARGATE を書いておくと、登録の時点で Fargate の要件に照らして確かめてもらえます。EC2 向けに書いたタスク定義を Fargate に移すときは、最後の行の項目が残っていないかも見ておきます。

よくある質問

Q. cpu と memory は、タスク全体とコンテナのどちらに書けばよいですか? A. Fargate ではタスク全体(JSON の最上位)の cpu と memory が必須です。コンテナ定義の中の cpu・memory は任意で、1つのタスクに複数のコンテナを入れて配分を決めたいときに使います。

Q. タスク定義を「更新」するコマンドはありますか? A. 登録済みのリビジョンを書き換えるコマンドはなく、同じ family で register-task-definition を実行して新しいリビジョンを作ります。以前のリビジョンは残るので、サービスに指定するリビジョンを変えれば戻せます。

Q. secrets に書いた値は、describe-task-definition で見えますか? A. 見えるのは valueFrom の ARN だけで、値そのものは出力に含まれません。environment に書いた値はそのまま見えるので、機密情報は secrets に分けておきます。

Q. シークレットの値を変えたのに、アプリに反映されません。 A. 公式ドキュメントによると、値はコンテナの起動時に渡され、あとから変えても動いているコンテナには反映されません。新しいタスクを起動するか、サービスを新しいデプロイの強制つきで更新してください。

まとめ

  • Fargate の土台は family・networkMode(awsvpc)・cpu・memory・containerDefinitions の5つ。cpu と memory は文字列で書く
  • cpu と memory は決まった組み合わせから選ぶ。合わないときは Invalid 'cpu' setting for task. が返る
  • 機密でない値は environment、機密情報は secrets。secrets の valueFrom は、Secrets Manager なら ARN:キー名:: の形で JSON の1キーを取り出せる
  • awslogs は awslogs-group・awslogs-region・awslogs-stream-prefix の3つをそろえる
  • ECR のプライベートリポジトリ・awslogs・secrets を使うなら executionRoleArn が必要。アプリ自身の権限は taskRoleArn
  • describe の出力を再登録するときは、taskDefinitionArn・revision・status など9項目を削る
  • リビジョンは登録のたびに増える。片付けは deregister してから delete の2段階

参考・出典

  • Amazon ECS デベロッパーガイド「Fargate の Amazon ECS タスク定義パラメータ」 https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task_definition_parameters.html
  • Amazon ECS デベロッパーガイド「Fargate の Amazon ECS タスク定義の違い」 https://docs.aws.amazon.com/AmazonECS/latest/developerguide/fargate-tasks-services.html
  • Amazon ECS デベロッパーガイド「タスク定義の無効な CPU またはメモリエラーのトラブルシューティング」 https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-cpu-memory-error.html
  • Amazon ECS デベロッパーガイド「環境変数を使用して Secrets Manager シークレットを渡す」 https://docs.aws.amazon.com/AmazonECS/latest/developerguide/secrets-envvar-secrets-manager.html
  • Amazon ECS デベロッパーガイド「環境変数を使用して Systems Manager パラメータを渡す」 https://docs.aws.amazon.com/AmazonECS/latest/developerguide/secrets-envvar-ssm-paramstore.html
  • Amazon ECS デベロッパーガイド「タスク実行 IAM ロール」 https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task_execution_IAM_role.html

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「ECSタスク定義JSONの書き方|Fargate必須項目と環境変数secrets」

株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。

WE ARE HIRING

RJCで一緒に開発しながら、
成長を楽しみませんか?

RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!

  • 127日年間休日
  • 12時間平均残業時間
  • 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!

ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

RJCで一緒に開発しながら、 成長を楽しみませんか?