「ECS Fargate」をAWSマネジメントコンソールで構築すると何が起きるか

ECS Fargate

Dockerコンテナを管理してくれる君。Fargate起動タイプを選択すると、クラスタのEC2の管理が不要になる。ひゃっほーい。詳細は、公式ドキュメントを参照する。

AWSマネジメントコンソールによる構築

とりあえず、動かしてみるぐらいだったら、ポチポチしていくだけでOK。VPCなど、ECSに必要なコンポーネントはCloudFormationでついでに構築してくれる。

ECSのページへ遷移

ECSのページを開く。

「今すぐ始める」ボタンをクリック。

f:id:tmknom:20180829102659p:plain

コンテナとタスク

コンテナの定義で「nginx」を選択。タスク定義はデフォルトのまま、「次」ボタンをクリック。

f:id:tmknom:20180829102728p:plain f:id:tmknom:20180829102742p:plain

サービス

ロードバランサーの種類で「Application Load Balancer」を選択して、「次」ボタンをクリック。

f:id:tmknom:20180829102822p:plain

クラスタ

何も変更せず、「次」ボタンをクリック。

f:id:tmknom:20180829102842p:plain

設定内容の確認

内容を確認して、「次」ボタンをクリック。

f:id:tmknom:20180829102920p:plain f:id:tmknom:20180829102934p:plain

作成ステータスの確認

この画面でしばらく待つ。

f:id:tmknom:20180829103005p:plain

完了すると下記のようになるので、「サービスの表示」ボタンをクリック。

f:id:tmknom:20180829103027p:plain

作成されたリソースの確認

サービスの確認

起動タイプがFARGATEになってることを確認。

f:id:tmknom:20180829103111p:plain

「タスク」タブをクリックし、タスクのリンクをクリック。

f:id:tmknom:20180829103140p:plain

「Public IP」のIPアドレス(ここでは18.179.58.90)をコピー。

f:id:tmknom:20180829103201p:plain

nginxの確認

ブラウザで、コピーしたIPアドレスを開いて、nginxが稼働してることを確認。

f:id:tmknom:20180829103241p:plain

正直、ほとんど何もしてないが、ECS Fargateが立ち上がってしまった。

リソースの削除

ECSのページに遷移。

作成したクラスター「default」リンクをクリック。

f:id:tmknom:20180829103306p:plain

クラスターの削除」ボタンをクリック。

f:id:tmknom:20180829103322p:plain

モーダルが出てくるので、「削除」ボタンをクリック。

f:id:tmknom:20180829103356p:plain

表示がこんな感じになるので、しばらく待つ。

f:id:tmknom:20180829103412p:plain

完了した。CloudFormationで作られた、ネットワーク系のリソースなども削除される。

f:id:tmknom:20180829103424p:plain

何が起きたか?

AWS内で何が起きているかを調べてみよう。CloudTrailで発生したイベントを見てみると、大雑把に以下のような種類のイベントが発生していた。

  • ECS系のリソース作成
  • ALB系のリソース作成
  • IAM Roleの作成
  • ネットワーク系のリソース作成

それぞれ、APIのリクエスト・レスポンス部分だけ、CloudTrailから抜粋してみよう。

ECS

CreateCluster

ECSのクラスタ。リクエストパラメータにクラスタ名が指定されているだけ。

{
    "eventSource": "ecs.amazonaws.com",
    "eventName": "CreateCluster",
    "requestParameters": {
        "clusterName": "default"
    },
    "responseElements": {
        "cluster": {
            "clusterArn": "arn:aws:ecs:ap-northeast-1:123456789012:cluster/default",
            "pendingTasksCount": 0,
            "registeredContainerInstancesCount": 0,
            "status": "ACTIVE",
            "runningTasksCount": 0,
            "statistics": [],
            "clusterName": "default",
            "activeServicesCount": 0
        }
    }
}

RegisterTaskDefinition

ECSのタスク定義。Fargateの場合の、リクエストパラメータのポイントとしては

  • requiresCompatibilitiesFARGATE が指定されている
  • networkModeawsvpc が指定されている
  • cpumemory が指定されている
  • logConfiguration に CloudWatch Logs の設定が指定されている

あたりだろう。このあたりは、Fargateではない場合との差分である。

{
    "eventSource": "ecs.amazonaws.com",
    "eventName": "RegisterTaskDefinition",
    "requestParameters": {
        "executionRoleArn": "arn:aws:iam::123456789012:role/ecsTaskExecutionRole",
        "networkMode": "awsvpc",
        "cpu": "256",
        "memory": "512",
        "family": "first-run-task-definition",
        "containerDefinitions": [
            {
                "logConfiguration": {
                    "logDriver": "awslogs",
                    "options": {
                        "awslogs-group": "/ecs/first-run-task-definition",
                        "awslogs-region": "ap-northeast-1",
                        "awslogs-stream-prefix": "ecs"
                    }
                },
                "entryPoint": [],
                "portMappings": [
                    {
                        "protocol": "tcp",
                        "containerPort": 80
                    }
                ],
                "command": [],
                "cpu": 256,
                "memoryReservation": 512,
                "image": "nginx:latest",
                "essential": true,
                "links": [],
                "name": "nginx"
            }
        ],
        "requiresCompatibilities": [
            "FARGATE"
        ]
    },
    "responseElements": {
        "taskDefinition": {
            "executionRoleArn": "arn:aws:iam::123456789012:role/ecsTaskExecutionRole",
            "containerDefinitions": [
                {
                    "logConfiguration": {
                        "logDriver": "awslogs",
                        "options": {
                            "awslogs-group": "/ecs/first-run-task-definition",
                            "awslogs-region": "ap-northeast-1",
                            "awslogs-stream-prefix": "ecs"
                        }
                    },
                    "entryPoint": [],
                    "portMappings": [
                        {
                            "hostPort": 80,
                            "protocol": "tcp",
                            "containerPort": 80
                        }
                    ],
                    "command": [],
                    "cpu": 256,
                    "environment": [],
                    "mountPoints": [],
                    "memoryReservation": 512,
                    "volumesFrom": [],
                    "image": "nginx:latest",
                    "essential": true,
                    "links": [],
                    "name": "nginx"
                }
            ],
            "placementConstraints": [],
            "memory": "512",
            "compatibilities": [
                "EC2",
                "FARGATE"
            ],
            "taskDefinitionArn": "arn:aws:ecs:ap-northeast-1:123456789012:task-definition/first-run-task-definition:1",
            "family": "first-run-task-definition",
            "requiresAttributes": [
                {
                    "name": "com.amazonaws.ecs.capability.docker-remote-api.1.18"
                },
                {
                    "name": "ecs.capability.task-eni"
                },
                {
                    "name": "ecs.capability.execution-role-awslogs"
                },
                {
                    "name": "com.amazonaws.ecs.capability.logging-driver.awslogs"
                },
                {
                    "name": "com.amazonaws.ecs.capability.docker-remote-api.1.21"
                },
                {
                    "name": "com.amazonaws.ecs.capability.docker-remote-api.1.19"
                }
            ],
            "requiresCompatibilities": [
                "FARGATE"
            ],
            "networkMode": "awsvpc",
            "cpu": "256",
            "revision": 1,
            "status": "ACTIVE",
            "volumes": []
        }
    }
}

CreateService

ECSのサービス。クラスタやTaskDefinition、ALBとの紐づけが行われている。また、ECSのネットワーク系の設定もココで定義される。

{
    "eventSource": "ecs.amazonaws.com",
    "eventName": "CreateService",
    "requestParameters": {
        "clientToken": "2c72dd08-ab58-43bf-8ec7-39b83a60c6e5",
        "platformVersion": "LATEST",
        "networkConfiguration": {
            "awsvpcConfiguration": {
                "assignPublicIp": "ENABLED",
                "securityGroups": [
                    "sg-0ec7cfeccbde2584a"
                ],
                "subnets": [
                    "subnet-0d9dfd97724471b0f",
                    "subnet-0a0b4bfe37dbb0087"
                ]
            }
        },
        "cluster": "default",
        "desiredCount": 1,
        "loadBalancers": [
            {
                "containerPort": 80,
                "targetGroupArn": "arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:targetgroup/EC2Co-Defau-1MWX6NT3L0EY8/11f454217333df7e",
                "containerName": "nginx"
            }
        ],
        "serviceName": "nginx-service",
        "launchType": "FARGATE",
        "taskDefinition": "first-run-task-definition"
    },
    "responseElements": {
        "service": {
            "serviceArn": "arn:aws:ecs:ap-northeast-1:123456789012:service/nginx-service",
            "createdAt": "Aug 2, 2018 12:30:07 AM",
            "platformVersion": "LATEST",
            "pendingCount": 0,
            "deploymentConfiguration": {
                "minimumHealthyPercent": 100,
                "maximumPercent": 200
            },
            "networkConfiguration": {
                "awsvpcConfiguration": {
                    "assignPublicIp": "ENABLED",
                    "securityGroups": [
                        "sg-0ec7cfeccbde2584a"
                    ],
                    "subnets": [
                        "subnet-0a0b4bfe37dbb0087",
                        "subnet-0d9dfd97724471b0f"
                    ]
                }
            },
            "clusterArn": "arn:aws:ecs:ap-northeast-1:123456789012:cluster/default",
            "roleArn": "arn:aws:iam::123456789012:role/aws-service-role/ecs.amazonaws.com/AWSServiceRoleForECS",
            "serviceRegistries": [],
            "placementConstraints": [],
            "taskDefinition": "arn:aws:ecs:ap-northeast-1:123456789012:task-definition/first-run-task-definition:1",
            "placementStrategy": [],
            "status": "ACTIVE",
            "healthCheckGracePeriodSeconds": 0,
            "loadBalancers": [
                {
                    "containerPort": 80,
                    "targetGroupArn": "arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:targetgroup/EC2Co-Defau-1MWX6NT3L0EY8/11f454217333df7e",
                    "containerName": "nginx"
                }
            ],
            "schedulingStrategy": "REPLICA",
            "runningCount": 0,
            "launchType": "FARGATE",
            "serviceName": "nginx-service",
            "desiredCount": 1,
            "deployments": [
                {
                    "networkConfiguration": {
                        "awsvpcConfiguration": {
                            "assignPublicIp": "ENABLED",
                            "securityGroups": [
                                "sg-0ec7cfeccbde2584a"
                            ],
                            "subnets": [
                                "subnet-0a0b4bfe37dbb0087",
                                "subnet-0d9dfd97724471b0f"
                            ]
                        }
                    },
                    "id": "ecs-svc/9223370503684968389",
                    "updatedAt": "Aug 2, 2018 12:30:07 AM",
                    "runningCount": 0,
                    "pendingCount": 0,
                    "taskDefinition": "arn:aws:ecs:ap-northeast-1:123456789012:task-definition/first-run-task-definition:1",
                    "status": "PRIMARY",
                    "desiredCount": 1,
                    "createdAt": "Aug 2, 2018 12:30:07 AM",
                    "platformVersion": "1.1.0",
                    "launchType": "FARGATE"
                }
            ],
            "events": []
        }
    }
}

CreateSecurityGroup

ECSのセキュリティグループ。

{
    "eventSource": "ec2.amazonaws.com",
    "eventName": "CreateSecurityGroup",
    "requestParameters": {
        "groupName": "EC2ContainerService-default-EcsSecurityGroup-U9YCOYYH8OMC",
        "groupDescription": "ECS Allowed Ports",
        "vpcId": "vpc-05a0fd574c6765f18"
    },
    "responseElements": {
        "_return": true,
        "groupId": "sg-0ec7cfeccbde2584a"
    }
}

AuthorizeSecurityGroupIngress

ECSのセキュリティグループのIngressグローバルIPアドレスからは80番ポートを許可。ALBからの通信は全ポート許可。

{
    "eventSource": "ec2.amazonaws.com",
    "eventName": "AuthorizeSecurityGroupIngress",
    "requestParameters": {
        "groupId": "sg-0ec7cfeccbde2584a",
        "ipPermissions": {
            "items": [
                {
                    "ipProtocol": "tcp",
                    "fromPort": 1,
                    "toPort": 65535,
                    "groups": {
                        "items": [
                            {
                                "groupId": "sg-06876578f17442b2f"
                            }
                        ]
                    },
                    "ipRanges": {},
                    "ipv6Ranges": {},
                    "prefixListIds": {}
                }
            ]
        }
    },
    "responseElements": {
        "requestId": "5f6a7173-46e7-482f-96a0-e9861af8f644",
        "_return": true
    }
}
{
    "eventSource": "ec2.amazonaws.com",
    "eventName": "AuthorizeSecurityGroupIngress",
    "requestParameters": {
        "groupId": "sg-0ec7cfeccbde2584a",
        "ipPermissions": {
            "items": [
                {
                    "ipProtocol": "tcp",
                    "fromPort": 80,
                    "toPort": 80,
                    "groups": {},
                    "ipRanges": {
                        "items": [
                            {
                                "cidrIp": "0.0.0.0/0"
                            }
                        ]
                    },
                    "ipv6Ranges": {},
                    "prefixListIds": {}
                }
            ]
        }
    },
    "responseElements": {
        "requestId": "3ec9f080-7d60-4282-9d45-a237813ee745",
        "_return": true
    }
}

CreateLogGroup

ECSのロググループ。ECSではログ出力はCloudWatch Logsで行うため、出力先のロググループを作成している。

{
    "eventSource": "logs.amazonaws.com",
    "eventName": "CreateLogGroup",
    "requestParameters": {
        "logGroupName": "/ecs/first-run-task-definition"
    },
    "responseElements": null
}

ALB

CreateLoadBalancer

ECSの手前にいるロードバランサ。

{
    "eventSource": "elasticloadbalancing.amazonaws.com",
    "eventName": "CreateLoadBalancer",
    "requestParameters": {
        "securityGroups": [
            "sg-06876578f17442b2f"
        ],
        "type": "application",
        "subnetMappings": [
            {
                "subnetId": "subnet-0a0b4bfe37dbb0087"
            },
            {
                "subnetId": "subnet-0d9dfd97724471b0f"
            }
        ],
        "name": "EC2Co-EcsEl-SOF7FSMFFR7D",
        "tags": [
            {
                "value": "Created for ECS cluster default",
                "key": "Description"
            },
            {
                "value": "ECS default - ALB",
                "key": "Name"
            }
        ],
        "scheme": "internet-facing"
    },
    "responseElements": {
        "loadBalancers": [
            {
                "type": "application",
                "loadBalancerName": "EC2Co-EcsEl-SOF7FSMFFR7D",
                "vpcId": "vpc-05a0fd574c6765f18",
                "securityGroups": [
                    "sg-06876578f17442b2f"
                ],
                "state": {
                    "code": "provisioning"
                },
                "availabilityZones": [
                    {
                        "subnetId": "subnet-0a0b4bfe37dbb0087",
                        "zoneName": "ap-northeast-1c"
                    },
                    {
                        "subnetId": "subnet-0d9dfd97724471b0f",
                        "zoneName": "ap-northeast-1d"
                    }
                ],
                "ipAddressType": "ipv4",
                "dNSName": "EC2Co-EcsEl-SOF7FSMFFR7D-330120737.ap-northeast-1.elb.amazonaws.com",
                "canonicalHostedZoneId": "Z14GRHDCWA56QT",
                "createdTime": "Aug 2, 2018 12:27:53 AM",
                "loadBalancerArn": "arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:loadbalancer/app/EC2Co-EcsEl-SOF7FSMFFR7D/702801505425bcd2",
                "scheme": "internet-facing"
            }
        ]
    }
}

CreateListener

ALBのリスナ。HTTP用のポートを空けるよう設定されている。

{
    "eventSource": "elasticloadbalancing.amazonaws.com",
    "eventName": "CreateListener",
    "requestParameters": {
        "loadBalancerArn": "arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:loadbalancer/app/EC2Co-EcsEl-SOF7FSMFFR7D/702801505425bcd2",
        "protocol": "HTTP",
        "port": 80,
        "defaultActions": [
            {
                "targetGroupArn": "arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:targetgroup/EC2Co-Defau-1MWX6NT3L0EY8/11f454217333df7e",
                "type": "forward"
            }
        ]
    },
    "responseElements": {
        "listeners": [
            {
                "protocol": "HTTP",
                "defaultActions": [
                    {
                        "targetGroupArn": "arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:targetgroup/EC2Co-Defau-1MWX6NT3L0EY8/11f454217333df7e",
                        "type": "forward"
                    }
                ],
                "listenerArn": "arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:listener/app/EC2Co-EcsEl-SOF7FSMFFR7D/702801505425bcd2/3388e6ab7dd623ce",
                "loadBalancerArn": "arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:loadbalancer/app/EC2Co-EcsEl-SOF7FSMFFR7D/702801505425bcd2",
                "port": 80
            }
        ]
    }
}

CreateTargetGroup

ALBのターゲットグループ。特にリクエストパラメータで指定していないが、ヘルスチェックの設定はデフォルトで入るようだ。

{
    "eventSource": "elasticloadbalancing.amazonaws.com",
    "eventName": "CreateTargetGroup",
    "requestParameters": {
        "protocol": "HTTP",
        "targetType": "ip",
        "vpcId": "vpc-05a0fd574c6765f18",
        "port": 80,
        "name": "EC2Co-Defau-1MWX6NT3L0EY8"
    },
    "responseElements": {
        "targetGroups": [
            {
                "targetGroupArn": "arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:targetgroup/EC2Co-Defau-1MWX6NT3L0EY8/11f454217333df7e",
                "healthCheckPort": "traffic-port",
                "healthCheckPath": "/",
                "healthCheckTimeoutSeconds": 5,
                "protocol": "HTTP",
                "healthCheckProtocol": "HTTP",
                "unhealthyThresholdCount": 2,
                "healthCheckIntervalSeconds": 30,
                "port": 80,
                "matcher": {
                    "httpCode": "200"
                },
                "targetGroupName": "EC2Co-Defau-1MWX6NT3L0EY8",
                "vpcId": "vpc-05a0fd574c6765f18",
                "targetType": "ip",
                "healthyThresholdCount": 5
            }
        ]
    }
}

RegisterTargets

ALBのターゲット。ECSのIPアドレスが指定されている。

{
    "eventSource": "elasticloadbalancing.amazonaws.com",
    "eventName": "RegisterTargets",
    "requestParameters": {
        "targets": [
            {
                "id": "10.0.1.83",
                "port": 80,
                "availabilityZone": "ap-northeast-1d"
            }
        ],
        "targetGroupArn": "arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:targetgroup/EC2Co-Defau-1MWX6NT3L0EY8/11f454217333df7e"
    },
    "responseElements": null
}

CreateSecurityGroup

ALBのセキュリティグループ。

{
    "eventSource": "ec2.amazonaws.com",
    "eventName": "CreateSecurityGroup",
    "requestParameters": {
        "groupName": "EC2ContainerService-default-AlbSecurityGroup-ADPLW4Q1Q4UG",
        "groupDescription": "ELB Allowed Ports",
        "vpcId": "vpc-05a0fd574c6765f18"
    },
    "responseElements": {
        "_return": true,
        "groupId": "sg-06876578f17442b2f"
    }
}

AuthorizeSecurityGroupIngress

ALBのセキュリティグループのIngress。グローバルに80番ポートを許可。

{
    "eventSource": "ec2.amazonaws.com",
    "eventName": "AuthorizeSecurityGroupIngress",
    "requestParameters": {
        "groupId": "sg-06876578f17442b2f",
        "ipPermissions": {
            "items": [
                {
                    "ipProtocol": "tcp",
                    "fromPort": 80,
                    "toPort": 80,
                    "groups": {},
                    "ipRanges": {
                        "items": [
                            {
                                "cidrIp": "0.0.0.0/0"
                            }
                        ]
                    },
                    "ipv6Ranges": {},
                    "prefixListIds": {}
                }
            ]
        }
    },
    "responseElements": {
        "requestId": "2ad9adfe-af40-4940-b6b0-9d537775a8b2",
        "_return": true
    }
}

IAM

CreateRole

ECSタスクが使用するロール。ECSのタスク定義のexecutionRoleArn属性に指定される。

{
    "eventSource": "iam.amazonaws.com",
    "eventName": "CreateRole",
    "requestParameters": {
        "roleName": "ecsTaskExecutionRole",
        "assumeRolePolicyDocument": "{\n  \"Version\": \"2008-10-17\",\n  \"Statement\": [\n    {\n      \"Sid\": \"\",\n      \"Effect\": \"Allow\",\n      \"Principal\": {\n        \"Service\": \"ecs-tasks.amazonaws.com\"\n      },\n      \"Action\": \"sts:AssumeRole\"\n    }\n  ]\n}"
    },
    "responseElements": {
        "role": {
            "assumeRolePolicyDocument": "%7B%0A%20%20%22Version%22%3A%20%222008-10-17%22%2C%0A%20%20%22Statement%22%3A%20%5B%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%22Sid%22%3A%20%22%22%2C%0A%20%20%20%20%20%20%22Effect%22%3A%20%22Allow%22%2C%0A%20%20%20%20%20%20%22Principal%22%3A%20%7B%0A%20%20%20%20%20%20%20%20%22Service%22%3A%20%22ecs-tasks.amazonaws.com%22%0A%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%22Action%22%3A%20%22sts%3AAssumeRole%22%0A%20%20%20%20%7D%0A%20%20%5D%0A%7D",
            "arn": "arn:aws:iam::123456789012:role/ecsTaskExecutionRole",
            "roleId": "AROAJOXAXMWOLLBFC2CDM",
            "createDate": "Aug 2, 2018 12:27:04 AM",
            "roleName": "ecsTaskExecutionRole",
            "path": "/"
        }
    }
}

AttachRolePolicy

ecsTaskExecutionRoleへAmazonECSTaskExecutionRolePolicyがアタッチされる。

{
    "eventSource": "iam.amazonaws.com",
    "eventName": "AttachRolePolicy",
    "requestParameters": {
        "roleName": "ecsTaskExecutionRole",
        "policyArn": "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"
    },
    "responseElements": null
}

ネットワーク

VPCやサブネット、ルートテーブルなどが作成される。あまり見るべきトコロがなかったので割愛。

IAM Roleに関するよもやま話

前述のとおりECSタスクで使用するecsTaskExecutionRoleというロールが自動作成される。しかし、実はCloudTrailの記録には残っていないが、ServiceLinkedRoleというリソースが二つ自動作成される。一つはAWSServiceRoleForECS、もう一つはAWSServiceRoleForElasticLoadBalancingだ。

ecsTaskExecutionRole

ECSタスクが使用するロール。デフォルトでは、AmazonECSTaskExecutionRolePolicyがアタッチされており、ECRへのアクセスとCloudWatch Logsへの書き込みが許可されている。Dockerコンテナが他のAWS APIを叩く場合は、このロールに権限を付与する。

$ aws iam get-role --role-name ecsTaskExecutionRole
{
    "Role": {
        "AssumeRolePolicyDocument": {
            "Version": "2008-10-17",
            "Statement": [
                {
                    "Action": "sts:AssumeRole",
                    "Principal": {
                        "Service": "ecs-tasks.amazonaws.com"
                    },
                    "Effect": "Allow",
                    "Sid": ""
                }
            ]
        },
        "MaxSessionDuration": 3600,
        "RoleId": "AROAJOXAXMWOLLBFC2CDM",
        "CreateDate": "2018-08-02T00:27:04Z",
        "RoleName": "ecsTaskExecutionRole",
        "Path": "/",
        "Arn": "arn:aws:iam::123456789012:role/ecsTaskExecutionRole"
    }
}

$ aws iam list-attached-role-policies --role-name ecsTaskExecutionRole
{
    "AttachedPolicies": [
        {
            "PolicyName": "AmazonECSTaskExecutionRolePolicy",
            "PolicyArn": "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"
        }
    ]
}

$ aws iam get-policy --policy-arn arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy
{
    "Policy": {
        "PolicyName": "AmazonECSTaskExecutionRolePolicy",
        "Description": "Provides access to other AWS service resources that are required to run Amazon ECS tasks",
        "CreateDate": "2017-11-16T18:48:22Z",
        "AttachmentCount": 1,
        "IsAttachable": true,
        "PolicyId": "ANPAJG4T4G4PV56DE72PY",
        "DefaultVersionId": "v1",
        "Path": "/service-role/",
        "Arn": "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy",
        "UpdateDate": "2017-11-16T18:48:22Z"
    }
}

$ aws iam get-policy-version --policy-arn arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy --version-id v1
{
    "PolicyVersion": {
        "CreateDate": "2017-11-16T18:48:22Z",
        "VersionId": "v1",
        "Document": {
            "Version": "2012-10-17",
            "Statement": [
                {
                    "Action": [
                        "ecr:GetAuthorizationToken",
                        "ecr:BatchCheckLayerAvailability",
                        "ecr:GetDownloadUrlForLayer",
                        "ecr:BatchGetImage",
                        "logs:CreateLogStream",
                        "logs:PutLogEvents"
                    ],
                    "Resource": "*",
                    "Effect": "Allow"
                }
            ]
        },
        "IsDefaultVersion": true
    }
}

AWSServiceRoleForECS

ECSクラスタをはじめて構築するときに、自動的に作成されるServiceLinkedRole。

$ aws iam get-role --role-name AWSServiceRoleForECS
{
    "Role": {
        "Description": "Role to enable Amazon ECS to manage your cluster.",
        "AssumeRolePolicyDocument": {
            "Version": "2012-10-17",
            "Statement": [
                {
                    "Action": "sts:AssumeRole",
                    "Effect": "Allow",
                    "Principal": {
                        "Service": "ecs.amazonaws.com"
                    }
                }
            ]
        },
        "MaxSessionDuration": 3600,
        "RoleId": "AROAJLAXPZR6O4INQMVBW",
        "CreateDate": "2018-08-02T00:27:03Z",
        "RoleName": "AWSServiceRoleForECS",
        "Path": "/aws-service-role/ecs.amazonaws.com/",
        "Arn": "arn:aws:iam::123456789012:role/aws-service-role/ecs.amazonaws.com/AWSServiceRoleForECS"
    }
}

$ aws iam list-attached-role-policies  --role-name AWSServiceRoleForECS
{
    "AttachedPolicies": [
        {
            "PolicyName": "AmazonECSServiceRolePolicy",
            "PolicyArn": "arn:aws:iam::aws:policy/aws-service-role/AmazonECSServiceRolePolicy"
        }
    ]
}

$ aws iam get-policy --policy-arn arn:aws:iam::aws:policy/aws-service-role/AmazonECSServiceRolePolicy
{
    "Policy": {
        "PolicyName": "AmazonECSServiceRolePolicy",
        "Description": "Policy to enable Amazon ECS to manage your cluster.",
        "CreateDate": "2017-10-14T01:18:58Z",
        "AttachmentCount": 1,
        "IsAttachable": true,
        "PolicyId": "ANPAIVUWKCAI7URU4WUEI",
        "DefaultVersionId": "v4",
        "Path": "/aws-service-role/",
        "Arn": "arn:aws:iam::aws:policy/aws-service-role/AmazonECSServiceRolePolicy",
        "UpdateDate": "2018-03-22T01:20:59Z"
    }
}

$ aws iam get-policy-version --policy-arn arn:aws:iam::aws:policy/aws-service-role/AmazonECSServiceRolePolicy --version-id v4
{
    "PolicyVersion": {
        "CreateDate": "2018-03-22T01:20:59Z",
        "VersionId": "v4",
        "Document": {
            "Version": "2012-10-17",
            "Statement": [
                {
                    "Action": [
                        "ec2:AttachNetworkInterface",
                        "ec2:CreateNetworkInterface",
                        "ec2:CreateNetworkInterfacePermission",
                        "ec2:DeleteNetworkInterface",
                        "ec2:DeleteNetworkInterfacePermission",
                        "ec2:Describe*",
                        "ec2:DetachNetworkInterface",
                        "elasticloadbalancing:DeregisterInstancesFromLoadBalancer",
                        "elasticloadbalancing:DeregisterTargets",
                        "elasticloadbalancing:Describe*",
                        "elasticloadbalancing:RegisterInstancesWithLoadBalancer",
                        "elasticloadbalancing:RegisterTargets",
                        "route53:ChangeResourceRecordSets",
                        "route53:CreateHealthCheck",
                        "route53:DeleteHealthCheck",
                        "route53:Get*",
                        "route53:List*",
                        "route53:UpdateHealthCheck",
                        "servicediscovery:DeregisterInstance",
                        "servicediscovery:Get*",
                        "servicediscovery:List*",
                        "servicediscovery:RegisterInstance",
                        "servicediscovery:UpdateInstanceCustomHealthStatus"
                    ],
                    "Resource": "*",
                    "Effect": "Allow"
                }
            ]
        },
        "IsDefaultVersion": true
    }
}

AWSServiceRoleForElasticLoadBalancing

ALBをはじめて構築するときに、自動的に作成されるServiceLinkedRole。

$ aws iam get-role --role-name AWSServiceRoleForElasticLoadBalancing
{
    "Role": {
        "Description": "Allows ELB to call AWS services on your behalf.",
        "AssumeRolePolicyDocument": {
            "Version": "2012-10-17",
            "Statement": [
                {
                    "Action": "sts:AssumeRole",
                    "Effect": "Allow",
                    "Principal": {
                        "Service": "elasticloadbalancing.amazonaws.com"
                    }
                }
            ]
        },
        "MaxSessionDuration": 3600,
        "RoleId": "AROAISK6L5ZX2E6XFVBLI",
        "CreateDate": "2018-08-02T00:27:53Z",
        "RoleName": "AWSServiceRoleForElasticLoadBalancing",
        "Path": "/aws-service-role/elasticloadbalancing.amazonaws.com/",
        "Arn": "arn:aws:iam::123456789012:role/aws-service-role/elasticloadbalancing.amazonaws.com/AWSServiceRoleForElasticLoadBalancing"
    }
}

$ aws iam list-attached-role-policies  --role-name AWSServiceRoleForElasticLoadBalancing
{
    "AttachedPolicies": [
        {
            "PolicyName": "AWSElasticLoadBalancingServiceRolePolicy",
            "PolicyArn": "arn:aws:iam::aws:policy/aws-service-role/AWSElasticLoadBalancingServiceRolePolicy"
        }
    ]
}

$ aws iam get-policy --policy-arn arn:aws:iam::aws:policy/aws-service-role/AWSElasticLoadBalancingServiceRolePolicy
{
    "Policy": {
        "PolicyName": "AWSElasticLoadBalancingServiceRolePolicy",
        "Description": "Service Linked Role Policy for AWS Elastic Load Balancing Control Plane",
        "CreateDate": "2017-09-19T22:19:04Z",
        "AttachmentCount": 1,
        "IsAttachable": true,
        "PolicyId": "ANPAIMHWGGSRHLOQUICJQ",
        "DefaultVersionId": "v2",
        "Path": "/aws-service-role/",
        "Arn": "arn:aws:iam::aws:policy/aws-service-role/AWSElasticLoadBalancingServiceRolePolicy",
        "UpdateDate": "2018-05-14T21:18:07Z"
    }
}

$ aws iam get-policy-version --policy-arn arn:aws:iam::aws:policy/aws-service-role/AWSElasticLoadBalancingServiceRolePolicy --version-id v2
{
    "PolicyVersion": {
        "CreateDate": "2018-05-14T21:18:07Z",
        "VersionId": "v2",
        "Document": {
            "Version": "2012-10-17",
            "Statement": [
                {
                    "Action": [
                        "ec2:DescribeAddresses",
                        "ec2:DescribeInstances",
                        "ec2:DescribeSubnets",
                        "ec2:DescribeSecurityGroups",
                        "ec2:DescribeVpcs",
                        "ec2:DescribeInternetGateways",
                        "ec2:DescribeAccountAttributes",
                        "ec2:DescribeClassicLinkInstances",
                        "ec2:DescribeVpcClassicLink",
                        "ec2:CreateSecurityGroup",
                        "ec2:CreateNetworkInterface",
                        "ec2:DeleteNetworkInterface",
                        "ec2:ModifyNetworkInterface",
                        "ec2:ModifyNetworkInterfaceAttribute",
                        "ec2:AuthorizeSecurityGroupIngress",
                        "ec2:AssociateAddress",
                        "ec2:DisassociateAddress",
                        "ec2:AttachNetworkInterface",
                        "ec2:DetachNetworkInterface",
                        "ec2:AssignPrivateIpAddresses",
                        "ec2:AssignIpv6Addresses",
                        "ec2:UnassignIpv6Addresses",
                        "logs:CreateLogDelivery",
                        "logs:GetLogDelivery",
                        "logs:UpdateLogDelivery",
                        "logs:DeleteLogDelivery",
                        "logs:ListLogDeliveries"
                    ],
                    "Resource": "*",
                    "Effect": "Allow"
                }
            ]
        },
        "IsDefaultVersion": true
    }
}

まとめ

ECSは関係するコンポーネントの数が多く、なかなかの初見殺しである。Dokcerの知識だけでなく、VPC・ALB・IAM Roleなど、たくさんのコンポーネントを正しく組み合わせないと動かないため、チュートリアル以外での試行錯誤が必要だろう。

また、Fargateのおかげで、ホストサーバの管理をしなくてよくなったのは本当に喜ばしいが、デバッグの難易度は実は上がっている。ホストサーバにログインできないので、トラブルシューティングしたいときに得られる情報が非常に限定的なのだ。