カテゴリー: BackEnd

Amazon ECSのタスク定義について

はじめに

前回の記事ではAmazon ECSの機能を全般的に広く浅く紹介しました。今回はAmazon ECSのタスク定義について詳しく調べてみました。

Amazon ECSのタスク定義についておさらい

Amazon ECSには大きく分けて4つの概念があります。

  • クラスター: タスクまたはサービスの論理グループ
  • サービス: タスクのスケジューラ
  • タスク: タスク定義を元に作られるアプリケーションの実行単位
  • タスク定義: DockerイメージやCPU、メモリの量などタスクの定義

クラスターの中にサービスがあり、サービスがタスクを立ち上げて維持します(サービスを介せずにタスクを直接立ち上げることもできます)。

Amazon ECSの概要については前回の記事をご覧ください。

タスク定義

タスク定義では以下のような内容を定義します。

  • タスクの各コンテナで使用するDockerイメージ
  • タスク及び各コンテナで使用するCPUやメモリの量
  • タスクの起動タイプ(Fargate、EC2など)
  • タスクのコンテナで使用するDockerネットワークモード
  • タスクで使用するロギング設定
  • タスクで使用されるIAMロール

1つのタスク定義の中に複数のコンテナを定義することができます。ただし、ECSでは1つのタスク定義だけでアプリケーションを構築するのではなく、複数のタスク定義を組み合わせてアプリケーションを構築することを推奨しています。

コンテナをどのようにタスク定義に振分けるかについては次で解説します。

アプリケーションのアーキテクチャ

タスク定義では、FargateもしくはEC2どちらかの起動タイプを選択します。

Fargate起動タイプ

公式ドキュメントによると、Fargate起動タイプは以下のワークロードに適しています。

  • 運用上で低いオーバーヘッドを必要とする大規模なワークロード
  • 時折バーストが発生する小さなワークロード
  • 小さなワークロード
  • バッチワークロード

AWS Fargateを使用する場合、複数をコンテナを単一のタスク定義に配置するか、それとも複数のタスク定義に分けて配置するか、どちらかを選択することになります。

以下のような要件がある場合は、同一のタスク定義にコンテナを配置するのが良いようです。

  • 各コンテナが同じライフサイクルを共有している(起動と終了が同時)
  • 実行基盤となるホストが同じになるようにコンテナを実行する(localhostポート上の別のコンテナを参照する)必要がある
  • コンテナがリソースを共有する必要がある
  • コンテナがデータボリュームを共有している

上記の要件が当てはまらない場合は、複数のタスク定義でコンテナを個別にデプロイするのが良いようです。別々にすることで、スケーリング、プロビジョニング、プロビジョニング解除を個別に行えるメリットがあります。

EC2起動タイプ

公式ドキュメントによると、EC2起動タイプは料金を最適化する必要があるような大規模なワークロードに適しています。他にも、GPUを使いたいケースの場合は、現状ではEC2起動タイプを選択する必要がありそうです。

タスク定義パラメータ

タスク定義は、タスクファミリ、IAMタスクロール、ネットワークモード、コンテナ定義、ボリューム、タスク配置の制約事項、起動タイプの各部分に別れています。この内、タスクファミリとコンテナの定義は必須項目ですがそれ以外の項目は省略することができます。

タスク定義はJSON形式で記述されます。ここではその内のいくつかを紹介します。

family

文字列型の必須項目です。

タスク定義を登録するときにはファミリー(複数バージョンのタスク定義の名前のようなもの)を指定する必要があります。登録したタスク定義にはリビジョン番号が与えられ、ファミリー:リビジョン番号の形式で表示されます。

taskRoleArn

文字列型の非必須項目です。

タスク定義を登録するときにIAMロールを割り当てることができ、タスクのコンテナにポリシーに指定されたAWS APIを呼び出すためのアクセス権限を付与できます。

詳しくはこちらをご覧ください。

executionRoleArn

文字列型の非必須項目です。

こちらもタスク定義を登録する際にIAMロールを割り当てるでき、Amazon ECSコンテナエージェントに権限を付与することができます。

詳しくはこちらをご覧ください。

networkMode

文字列型の非必須項目です。

タスクのコンテナで使用するDockerネットワークモードを指定することができます。有効な値としてはnonebridgeawsvpchostがあり、デフォルトはbridgeです。Fargate起動タイプを使用する場合はawsvpcを指定する必要があります。

awsvpcを指定する場合は、タスクにElastic Network Interfaceが割り当てられます。そのため、タスク定義を使用したサービスの作成時、または、タスクの実行時にNetworkConfiguration(VPCやサブネット)を指定する必要があります。

cpuとmemory

どちらも文字列型の必須項目(Fargate起動タイプの場合)です。

cpuはタスクに適用されるCPUユニットの制限で、CPUユニット数(256など)またはvCPU(.25 vCPUなど)で表します。

memoryはタスクに適用されるメモリの制限で、MiBを使用した整数(512など)またはGBを使用した文字列(0.5 GBなど)で表されます。

cpuの値ごとにとれるmemoryの値の範囲が決まっていますので注意してください。

containerDefinitions

コンテナの定義に関わるオブジェクトの配列です。

Dockerイメージ、環境変数、secrets、ポートマッピングなど様々な設定項目があります。非常に多くの項目があるため詳細は割愛します。詳しくはこちらをご覧下さい。

定義例

参考までに前回の記事で作成したタスク定義のJSONを載せます。

{
    "ipcMode": null,
    "executionRoleArn": "arn:aws:iam::XXXX:role/ecsTaskExecutionRole",
    "containerDefinitions": [
        {
            "dnsSearchDomains": null,
            "environmentFiles": null,
            "logConfiguration": {
                "logDriver": "awslogs",
                "secretOptions": null,
                "options": {
                    "awslogs-group": "/ecs/echo-sample",
                    "awslogs-region": "ap-northeast-1",
                    "awslogs-stream-prefix": "ecs"
                }
            },
            "entryPoint": [],
            "portMappings": [
                {
                    "hostPort": 80,
                    "protocol": "tcp",
                    "containerPort": 80
                }
            ],
            "command": [],
            "linuxParameters": null,
            "cpu": 0,
            "environment": [],
            "resourceRequirements": null,
            "ulimits": null,
            "dnsServers": null,
            "mountPoints": [],
            "workingDirectory": null,
            "secrets": null,
            "dockerSecurityOptions": null,
            "memory": null,
            "memoryReservation": 128,
            "volumesFrom": [],
            "stopTimeout": null,
            "image": "XXXX.dkr.ecr.ap-northeast-1.amazonaws.com/ecs-echo-sample:latest",
            "startTimeout": null,
            "firelensConfiguration": null,
            "dependsOn": null,
            "disableNetworking": null,
            "interactive": null,
            "healthCheck": null,
            "essential": true,
            "links": null,
            "hostname": null,
            "extraHosts": null,
            "pseudoTerminal": null,
            "user": null,
            "readonlyRootFilesystem": null,
            "dockerLabels": null,
            "systemControls": null,
            "privileged": null,
            "name": "echo"
        }
    ],
    "memory": "512",
    "taskRoleArn": "arn:aws:iam::XXXX:role/ecsTaskExecutionRole",
    "family": "echo-sample",
    "pidMode": null,
    "requiresCompatibilities": [
        "FARGATE"
    ],
    "networkMode": "awsvpc",
    "runtimePlatform": {
        "operatingSystemFamily": "LINUX",
        "cpuArchitecture": null
    },
    "cpu": "256",
    "inferenceAccelerators": [],
    "proxyConfiguration": null,
    "volumes": [],
    "tags": [
        {
            "key": "test key",
            "value": "test value"
        }
    ]
}

余談ですが、タスク定義のJSONを取得する方法はいくつかあります。例えば、既存のタスク定義の「新しいリビジョンの作成」画面の下部にある「JSONによる設定」を開くと表示されるもの。タスク定義の「JSON」タブに表示されているもの。aws cliで取得できるものなどです。これらはいずれも表示される項目が微妙に異なります(cliで取得できる値は特に異なる)。ここで表示しているのは「JSONによる設定」で表示されたJSONです。

ちなみに、JSONからタスク定義を作成する方法は2種類あります。1つ目は「JSONによる設定」に貼り付ける方法。2つ目はaws cliaws ecs describe-task-definitionコマンドで登録する方法です。

タスクでのデータボリュームの使用

ECSでは以下のデータボリュームをサポートしています。

  • Fargate タスクストレージ
  • Amazon EFS ボリューム
  • FSx for Windows File Server ボリューム
  • Docker ボリューム
  • バインドマウント

ただし、Fargate起動タイプを選ぶ場合は、タスクストレージ、EFS、バインドマウントのみ利用できるようです。

Fargate タスクストレージ

Fargateでホストされている各タスクは、プロビジョニングされる際にバインドマウントのためのエフェメラル (ローカル)ストレージを受け取ります。これらをマウントし、タスク定義内でvolumesmoutPointsおよびvolumesFromパラメータを使用しているコンテナ間で共有することができます。

ECSタスクはデフォルトで20GiBの(最大200GiBまで増やせる)エフェメラルストレージを受け取ります。

pull、compress、uncompressされたコンテナイメージはエフェメラルストレージに保存されます。つまり、コンテナイメージの容量+指定したエフェメラルストレージの容量がコンテナの総容量になります。

Amazon EFS ボリューム

EFS(Elastic File System)では、ECSタスクで使用するためのシンプルでスケーラブルなファイルストレージを提供します。このストレージ容量は伸縮性があり、ファイルの追加や削除に伴って自動的に拡大、縮小されます。

EFSを使用すると各タスクは配置されているインスタンスに関わらず、常に同じ永続ストレージにアクセスできます。

Docker ボリューム

組み込みのlocalドライバー、またはサードパーティのボリュームドライバーを使用できます。Docker ボリュームはDocker で管理され、ディレクトリはボリュームデータを含むコンテナインスタンスの/var/lib/docker/volumesに作成されます。

Docker ボリュームを使用するには、タスク定義でdockerVolumeConfigurationを指定します。

バインドマウント

ホスト(FargateまたはEC2インスタンス)上のファイルまたはディレクトリがコンテナにマウントされます。

デフォルトではバインドマウントは、それらを使用しているコンテナのライフサイクルに紐付けられています。タスクが停止するなど、バインドマウントを使用するすべてのコンテナが停止すると、データが削除されます。

環境変数の引き渡し

環境変数は以下の方法でコンテナに渡すことができます。

  • コンテナ定義パラメータのenvironmentに個別に定義する
  • コンテナ定義パラメータのenvironmentFilesにファイルを指定する

environmentに個別に定義する

以下のようにnamevalueを定義します。これはdocker run--envオプションにマッピングされます。

{
    "containerDefinitions": [
        {
            "environment": [
                {
                    "name": "env name",
                    "value": "env value"
                }
            ]
        }
    ]
}

environmentFilesにファイルを指定する

S3にホストされている.envファイルを指定します。これはdocker run--env-fileオプションにマッピングされます。

{
    "containerDefinitions": [
        {
            "environmentFiles": [
                {
                    "value": "arn:aws:s3:::s3_bucket_name/envfile_object_name.env",
                    "type": "s3"
                }
            ]
        }
    ]
}

コンテナへの機密情報の受け渡し

AWS Secret Managerのsecrets、またはAWS System Manager Parameter Storeのパラメータに機密情報を保存した上で、コンテナ定義から参照することによってコンテナに機密情報を取り込む事ができます。

以下の方法でsecretsををコンテナに公開できます。

  • containerDefinitionsのsecretsパラメータを使用して、機密情報を環境変数としてコンテナに挿入する
  • containerDefinitionsのsecretOptionsを使用して、ログ設定へ機密情報を挿入する

タスク定義でSecret Managerシークレットを参照する

コンテナ定義でSecret Managerシークレットを参照する方法を示します。

{
  "containerDefinitions": [{
    "secrets": [{
      "name": "environment_variable_name",
      "valueFrom": "arn:aws:secretsmanager:region:aws_account_id:secret:secret_name-AbCdEf"
    }]
  }]
}

ほかにも、シークレット内の特定のキーの参照や特定のバージョンシークレットを参照することもできます。詳しくはこちらをご覧下さい。

環境変数として機密情報を挿入

コンテナ定義でコンテナに設定する環境変数名と、コンテナに渡す機密情報が含まれているSystems Manager Parameter Storeのパラメータの完全なARNを使用してsecretを指定します。

{
  "containerDefinitions": [{
    "secrets": [{
      "name": "environment_variable_name",
      "valueFrom": "arn:aws:ssm:region:aws_account_id:parameter/parameter_name"
    }]
  }]
}

Secrets ManagerとParameter Storeどちらが良いか

本記事の内容から外れている為多くは語りませんが、小規模Webシステムなどパラメータへのアクセス頻度が少ない場合はParameter Storeを使い、より多くの取得リクエストがある場合はSecrets Managerを使うのが良さそう(ただし有料)です。

この2つの比較についてはこちらの記事をご覧ください。

さいごに

ECSのタスク定義について深堀りしました。次回は同じくECSのサービスについて調べみたいと思います。

おすすめ書籍

Hiroki Ono

シェア
執筆者:
Hiroki Ono
タグ: AWS

最近の投稿

フロントエンドで動画デコレーション&レンダリング

はじめに 今回は、以下のように…

2週間 前

Goのクエリビルダー goqu を使ってみる

はじめに 最近携わっているとあ…

4週間 前

【Xcode15】プライバシーマニフェスト対応に備えて

はじめに こんにちは、suzu…

2か月 前

FSMを使った状態管理をGoで実装する

はじめに 一般的なアプリケーシ…

3か月 前