FargateでECSを使う

aws

ECSはAWSのコンテナオーケストレーションサービス。 クラスタはEC2上に立てることもできるが、その場合Auto Scalingグループの設定やスケールイン時のdrainなどを考慮する必要がある。 Fargateで起動するとサーバーレスで実行でき、バックエンドの管理が必要がなくなる。 料金は割り当てたvCPUとメモリによって、最低1分の1秒単位で課金される。 Lambdaと同じくリソースあたりでいうとオンデマンドのEC2と比較して高くなっているが、柔軟にリソースが指定できる分いくらか差は縮まるかもしれない。

特にバッチ処理のように常にリソースが必要ないTaskは都度インスタンスを立ち上げるのも面倒なので良いと思う。 Lambdaと比較すると、実行環境を自由に作れるのと実行時間に制限がないというところが良いが、 Taskを作るトリガーは現状cronだけなのでそれ以外のイベントで実行したい場合はLambdaと組み合わせる必要がある。

AWSにはKubernetesクラスタを立てられるEKSもあるが、こちらはまだFargateに対応していない。 もしかしたら今月末のre:Inventで何か発表されるかもしれない。

(追記: 2021-05-30): re:Invent 2019でEKSのFargate対応が発表された。

LA,ディズニーランドからre:Inventに参加しグランドキャニオンへドライブしてきた - sambaiz-net

Clusterの作成

まずはClusterを作成する。

$ aws ecs create-cluster --cluster-name test

ECSオブジェクト

Taskの登録

イメージやポートマッピング、ヘルスチェックや割り当てるリソースといったContainer definition を含むTask definitionを書く。 Fargateの場合networkModeはawsvpc固定になる。

{
    "family": "test-task", 
    "networkMode": "awsvpc", 
    "containerDefinitions": [
        {
            "name": "nginx", 
            "image": "nginx:1.15", 
            "portMappings": [
                {
                    "containerPort": 80, 
                    "hostPort": 80, 
                    "protocol": "tcp"
                }
            ], 
            "essential": true
        }
    ], 
    "requiresCompatibilities": [
        "FARGATE"
    ], 
    "cpu": "256", 
    "memory": "512"
}

Taskを登録する。

$ aws ecs register-task-definition --cli-input-json file://$(pwd)/task.json
$ aws ecs list-task-definitions
{
    "taskDefinitionArns": [
        "arn:aws:ecs:ap-northeast-1:*****:task-definition/test-task:1"
    ]
}

Taskを実行

run-taskでTaskを実行できる。 外からアクセスできるようにPublicIPを割り当てている。

{
  "cluster": "test",
  "taskDefinition": "test-task:1",
  "launchType": "FARGATE",
  "networkConfiguration": {
    "awsvpcConfiguration": {
      "subnets": [
        "subnet-*****"
      ],
      "securityGroups": [
        "sg-*****"
      ],
      "assignPublicIp": "ENABLED"
    }
  }
}
$ aws ecs run-task --cli-input-json file://$(pwd)/run-task.json

TaskのNetworkのところにPublicIPが出ていて、アクセスするとWelcome to nginx!の表示が確認できる。

TaskのNetwork

Serviceを作成

上の方法でTaskを実行することもできるが、 常時動くアプリケーションの場合、何か問題が起きてTaskが終了したら復活してほしい。 それをやるのがServiceで、K8sでいうDeploymentのようなリソース。ELBと紐づけると複数のTaskで負荷分散できる。

{
    "cluster": "test",
    "serviceName": "test-service",
    "taskDefinition": "test-task:1",
    "desiredCount": 2,
    "launchType": "FARGATE",
    "networkConfiguration": {
        "awsvpcConfiguration": {
            "subnets": [
                "subnet-*****"
            ],
            "securityGroups": [
                "sg-******"
            ],
            "assignPublicIp": "ENABLED"
        }
    }
}

Serviceを作成するとdesiredCountの分Taskが立ち上がり、Taskを消すと再びその数になるように立ち上がる。

$ aws ecs create-service --cli-input-json file://$(pwd)/service.json
$ aws ecs list-services --cluster test
{
    "serviceArns": [
        "arn:aws:ecs:ap-northeast-1:*****:service/test-service"
    ]
}

ECS FargateでSidecarのFluentdでログをS3に送る構成をCloudFormationで構築する - sambaiz-net