ECS-Optimized Bottlerocket AMIでECS環境を構築する

2021.08.03

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

中山(順)@リカバリー中 です。

かなり久しぶりにブログを書いております。

最近全くインプットができてなかったので、リハビリを兼ねて少し前に一般提供を開始した"ECS-Optimized" Bottlerocket AMIを利用してECS環境を構築したいと思います。

The Bottlerocket AMI for Amazon ECS is now Generally Available

Bottlerocketとは

コンテナをホストすることに特化したLinuxベースのOSです。セキュリティや保守性の面でメリットがあります。

公式の情報はこちらからどうぞ。

Bottlerocket

bottlerocket-os / bottlerocket

一般提供開始時(EKS対応時)の弊ブログ記事はこちらになります。

コンテナ実行に特化したAWS製オープンソースOS「Bottlerocket」がGAになりました!

なお、ECS-Optimized Bottlerocket AMIにはいくつかの制約がありますのでご注意ください。

Using Bottlerocket with Amazon ECS

ECS ExecやFireLens in task definitionsは早めにサポートしてくれるとうれしいなーと思いました。

やってみた

ブログリハビリも兼ねて、ECSクラスターを作成するところからやっていこうと思います。 手順はこちらのドキュメントを参考にしています。

Using a Bottlerocket AMI with Amazon ECS

なお、以下の手順はCloudShellで実行しました。

Clusterの作成

まずはECSクラスターを作成します。

$ aws ecs create-cluster \
    --cluster-name bottlerocket
{
    "cluster": {
        "clusterArn": "arn:aws:ecs:ap-northeast-1:xxxxxxxxxxxx:cluster/bottlerocket",
        "clusterName": "bottlerocket",
        "status": "ACTIVE",
        "registeredContainerInstancesCount": 0,
        "runningTasksCount": 0,
        "pendingTasksCount": 0,
        "activeServicesCount": 0,
        "statistics": [],
        "tags": [],
        "settings": [
            {
                "name": "containerInsights",
                "value": "disabled"
            }
        ],
        "capacityProviders": [],
        "defaultCapacityProviderStrategy": []
    }
}

AMI IDの確認

ECS-Optimized BottlerocketのAMI IDは、パブリックパラメーターストアで確認できます。

$ aws ssm get-parameter \
    --name "/aws/service/bottlerocket/aws-ecs-1/x86_64/latest/image_id" \
    --query Parameter.Value \
    --output text
ami-0ab6964c3c85fe239

IAM Role(Instance Profile)の作成

以下のAWS管理ポリシーをアタッチしたIAM Roleを作成します。

ROLE_NAME="bottlerocket"
TRUST_POLICY_FILE_NAME='Trust-Policy.json'

cat << EOF > ${TRUST_POLICY_FILE_NAME}
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": [
                    "ec2.amazonaws.com"
                ]
            },
            "Action": "sts:AssumeRole"
        }
    ]
}
EOF

aws iam create-role \
    --role-name ${ROLE_NAME} \
    --assume-role-policy-document file://${TRUST_POLICY_FILE_NAME}
{
    "Role": {
        "Path": "/",
        "RoleName": "bottlerocket",
        "RoleId": "AROAXS3RGICAZ3NHYSBQW",
        "Arn": "arn:aws:iam::xxxxxxxxxxxx:role/bottlerocket",
        "CreateDate": "2021-08-03T06:42:50+00:00",
        "AssumeRolePolicyDocument": {
            "Version": "2012-10-17",
            "Statement": [
                {
                    "Effect": "Allow",
                    "Principal": {
                        "Service": [
                            "ec2.amazonaws.com"
                        ]
                    },
                    "Action": "sts:AssumeRole"
                }
            ]
        }
    }
}

作成したRoleに必要な権限を付与します。

今回は、"AmazonSSMManagedInstanceCore" および "AmazonEC2ContainerServiceforEC2Role" の2つのAWS管理ポリシーをアタッチします。

aws iam attach-role-policy \
   --role-name ${ROLE_NAME} \
   --policy-arn arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
   
aws iam attach-role-policy \
   --role-name ${ROLE_NAME} \
   --policy-arn arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceforEC2Role

aws iam list-attached-role-policies \
    --role-name ${ROLE_NAME}
{
    "AttachedPolicies": [
        {
            "PolicyName": "AmazonSSMManagedInstanceCore",
            "PolicyArn": "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
        },
        {
            "PolicyName": "AmazonEC2ContainerServiceforEC2Role",
            "PolicyArn": "arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceforEC2Role"
        }
    ]
}

最後に、Instance ProfileにIAM Roleを追加します。

INSTANCE_PROFILE_NAME="bottlerocket"

aws iam create-instance-profile \
    --instance-profile-name ${INSTANCE_PROFILE_NAME}
{
    "InstanceProfile": {
        "Path": "/",
        "InstanceProfileName": "bottlerocket",
        "InstanceProfileId": "XXXXXXXXXXXXXXXXXXXXX",
        "Arn": "arn:aws:iam::xxxxxxxxxxxx:instance-profile/bottlerocket",
        "CreateDate": "2021-08-03T06:47:36+00:00",
        "Roles": []
    }
}
aws iam add-role-to-instance-profile \
    --instance-profile-name ${INSTANCE_PROFILE_NAME} \
    --role-name ${ROLE_NAME}

aws iam get-instance-profile \
    --instance-profile-name ${INSTANCE_PROFILE_NAME}
{
    "InstanceProfile": {
        "Path": "/",
        "InstanceProfileName": "bottlerocket",
        "InstanceProfileId": "XXXXXXXXXXXXXXXXXXXXX",
        "Arn": "arn:aws:iam::xxxxxxxxxxxx:instance-profile/bottlerocket",
        "CreateDate": "2021-08-03T06:47:36+00:00",
        "Roles": [
            {
                "Path": "/",
                "RoleName": "bottlerocket",
                "RoleId": "YYYYYYYYYYYYYYYYYYYYY",
                "Arn": "arn:aws:iam::xxxxxxxxxxxx:role/bottlerocket",
                "CreateDate": "2021-08-03T06:42:50+00:00",
                "AssumeRolePolicyDocument": {
                    "Version": "2012-10-17",
                    "Statement": [
                        {
                            "Effect": "Allow",
                            "Principal": {
                                "Service": "ec2.amazonaws.com"
                            },
                            "Action": "sts:AssumeRole"
                        }
                    ]
                }
            }
        ],
        "Tags": []
    }
}

インスタンスの作成

今回はデフォルトVPCにEC2インスタンスを作成します。 EC2インスタンスの作成前に、Subnet IDを確認します。

aws ec2 describe-subnets \
    --filter=Name=vpc-id,Values=vpc-0e3f6fef1f710c869 | jq '.Subnets[] | {id: .SubnetId, public: .MapPublicIpOnLaunch, az: .AvailabilityZone}'
{
  "id": "subnet-03267eb84db1ec870",
  "public": true,
  "az": "ap-northeast-1c"
}
{
  "id": "subnet-0b33c6ab5dbe1dda5",
  "public": true,
  "az": "ap-northeast-1d"
}
{
  "id": "subnet-09166ccaa28459f22",
  "public": true,
  "az": "ap-northeast-1a"
}

インスタンスをECSクラスターに登録するためのUserDataを作成します。

USERDATA_FILE_NAME="userdata.toml"

cat << EOF > ${USERDATA_FILE_NAME}
[settings.ecs]
cluster = "bottlerocket"
EOF

EC2インスタンスを作成します。

aws ec2 run-instances --key-name KEY_NAME \
    --subnet-id subnet-09166ccaa28459f22 \
    --image-id ami-0ab6964c3c85fe239 \
    --instance-type c5.large \
    --tag-specifications 'ResourceType=instance,Tags=[{Key=bottlerocket,Value=quickstart}]' \
    --user-data file://${USERDATA_FILE_NAME} \
    --iam-instance-profile Name=${INSTANCE_PROFILE_NAME}
{
    "Groups": [],
    "Instances": [
        {
            "AmiLaunchIndex": 0,
            "ImageId": "ami-0ab6964c3c85fe239",
            "InstanceId": "i-088ec897a0f2a6b69",
            "InstanceType": "c5.large",
            "KeyName": "KEY_NAME",
            "LaunchTime": "2021-08-03T06:58:11+00:00",
            "Monitoring": {
                "State": "disabled"
            },
            "Placement": {
                "AvailabilityZone": "ap-northeast-1a",
                "GroupName": "",
                "Tenancy": "default"
            },
            "PrivateDnsName": "ip-172-31-33-39.ap-northeast-1.compute.internal",
            "PrivateIpAddress": "172.31.33.39",
            "ProductCodes": [],
            "PublicDnsName": "",
            "State": {
                "Code": 0,
                "Name": "pending"
            },
            "StateTransitionReason": "",
            "SubnetId": "subnet-09166ccaa28459f22",
            "VpcId": "vpc-0e3f6fef1f710c869",
            "Architecture": "x86_64",
            "BlockDeviceMappings": [],
            "ClientToken": "35b1d3a0-3d16-4e75-a245-aa6e83d3470f",
            "EbsOptimized": false,
            "EnaSupport": true,
            "Hypervisor": "xen",
            "IamInstanceProfile": {
                "Arn": "arn:aws:iam::xxxxxxxxxxxx:instance-profile/bottlerocket",
                "Id": "XXXXXXXXXXXXXXXXXXXXX"
            },
            "NetworkInterfaces": [
                {
                    "Attachment": {
                        "AttachTime": "2021-08-03T06:58:11+00:00",
                        "AttachmentId": "eni-attach-030812e77c1b4fb0b",
                        "DeleteOnTermination": true,
                        "DeviceIndex": 0,
                        "Status": "attaching",
                        "NetworkCardIndex": 0
                    },
                    "Description": "",
                    "Groups": [
                        {
                            "GroupName": "default",
                            "GroupId": "sg-0db2403949c9bdd77"
                        }
                    ],
                    "Ipv6Addresses": [],
                    "MacAddress": "06:fd:88:65:6b:09",
                    "NetworkInterfaceId": "eni-0b91581dc6e3e018f",
                    "OwnerId": "xxxxxxxxxxxx",
                    "PrivateDnsName": "ip-172-31-33-39.ap-northeast-1.compute.internal",
                    "PrivateIpAddress": "172.31.33.39",
                    "PrivateIpAddresses": [
                        {
                            "Primary": true,
                            "PrivateDnsName": "ip-172-31-33-39.ap-northeast-1.compute.internal",
                            "PrivateIpAddress": "172.31.33.39"
                        }
                    ],
                    "SourceDestCheck": true,
                    "Status": "in-use",
                    "SubnetId": "subnet-09166ccaa28459f22",
                    "VpcId": "vpc-0e3f6fef1f710c869",
                    "InterfaceType": "interface"
                }
            ],
            "RootDeviceName": "/dev/xvda",
            "RootDeviceType": "ebs",
            "SecurityGroups": [
                {
                    "GroupName": "default",
                    "GroupId": "sg-0db2403949c9bdd77"
                }
            ],
            "SourceDestCheck": true,
            "StateReason": {
                "Code": "pending",
                "Message": "pending"
            },
            "Tags": [
                {
                    "Key": "bottlerocket",
                    "Value": "quickstart"
                }
            ],
            "VirtualizationType": "hvm",
            "CpuOptions": {
                "CoreCount": 1,
                "ThreadsPerCore": 2
            },
            "CapacityReservationSpecification": {
                "CapacityReservationPreference": "open"
            },
            "MetadataOptions": {
                "State": "pending",
                "HttpTokens": "optional",
                "HttpPutResponseHopLimit": 1,
                "HttpEndpoint": "enabled"
            },
            "EnclaveOptions": {
                "Enabled": false
            }
        }
    ],
    "OwnerId": "xxxxxxxxxxxx",
    "ReservationId": "r-05c91827dbb4c969d"
}

ECSクラスターにインスタンスが登録されたことを確認します。

aws ecs list-container-instances \
    --cluster bottlerocket
{
    "containerInstanceArns": [
        "arn:aws:ecs:ap-northeast-1:xxxxxxxxxxxx:container-instance/bottlerocket/3ffe04bcf4294918adbadfd656db927f"
    ]
}
aws ecs describe-container-instances \
    --cluster bottlerocket \
    --container-instances 3ffe04bcf4294918adbadfd656db927f
{
    "containerInstances": [
        {
            "containerInstanceArn": "arn:aws:ecs:ap-northeast-1:xxxxxxxxxxxx:container-instance/bottlerocket/3ffe04bcf4294918adbadfd656db927f",
            "ec2InstanceId": "i-088ec897a0f2a6b69",
            "version": 3,
            "versionInfo": {
                "agentVersion": "1.53.0",
                "agentHash": "225bc3a5",
                "dockerVersion": "DockerVersion: 20.10.4"
            },
            "remainingResources": [
                {
                    "name": "CPU",
                    "type": "INTEGER",
                    "doubleValue": 0.0,
                    "longValue": 0,
                    "integerValue": 2048
                },
                {
                    "name": "MEMORY",
                    "type": "INTEGER",
                    "doubleValue": 0.0,
                    "longValue": 0,
                    "integerValue": 3679
                },
                {
                    "name": "PORTS",
                    "type": "STRINGSET",
                    "doubleValue": 0.0,
                    "longValue": 0,
                    "integerValue": 0,
                    "stringSetValue": [
                        "22",
                        "2376",
                        "2375",
                        "51678",
                        "51679"
                    ]
                },
                {
                    "name": "PORTS_UDP",
                    "type": "STRINGSET",
                    "doubleValue": 0.0,
                    "longValue": 0,
                    "integerValue": 0,
                    "stringSetValue": []
                }
            ],
            "registeredResources": [
                {
                    "name": "CPU",
                    "type": "INTEGER",
                    "doubleValue": 0.0,
                    "longValue": 0,
                    "integerValue": 2048
                },
                {
                    "name": "MEMORY",
                    "type": "INTEGER",
                    "doubleValue": 0.0,
                    "longValue": 0,
                    "integerValue": 3679
                },
                {
                    "name": "PORTS",
                    "type": "STRINGSET",
                    "doubleValue": 0.0,
                    "longValue": 0,
                    "integerValue": 0,
                    "stringSetValue": [
                        "22",
                        "2376",
                        "2375",
                        "51678",
                        "51679"
                    ]
                },
                {
                    "name": "PORTS_UDP",
                    "type": "STRINGSET",
                    "doubleValue": 0.0,
                    "longValue": 0,
                    "integerValue": 0,
                    "stringSetValue": []
                }
            ],
            "status": "ACTIVE",
            "agentConnected": true,
            "runningTasksCount": 0,
            "pendingTasksCount": 0,
            "attributes": [
                {
                    "name": "ecs.capability.secrets.asm.environment-variables"
                },
                {
                    "name": "ecs.capability.branch-cni-plugin-version",
                    "value": "a21d3a41-1.2"
                },
                {
                    "name": "ecs.ami-id",
                    "value": "ami-0ab6964c3c85fe239"
                },
                {
                    "name": "ecs.capability.secrets.asm.bootstrap.log-driver"
                },
                {
                    "name": "com.amazonaws.ecs.capability.logging-driver.none"
                },
                {
                    "name": "ecs.capability.ecr-endpoint"
                },
                {
                    "name": "ecs.capability.docker-plugin.local"
                },
                {
                    "name": "ecs.capability.task-cpu-mem-limit"
                },
                {
                    "name": "ecs.capability.secrets.ssm.bootstrap.log-driver"
                },
                {
                    "name": "com.amazonaws.ecs.capability.docker-remote-api.1.30"
                },
                {
                    "name": "ecs.capability.full-sync"
                },
                {
                    "name": "com.amazonaws.ecs.capability.docker-remote-api.1.31"
                },
                {
                    "name": "com.amazonaws.ecs.capability.docker-remote-api.1.32"
                },
                {
                    "name": "ecs.availability-zone",
                    "value": "ap-northeast-1a"
                },
                {
                    "name": "com.amazonaws.ecs.capability.logging-driver.awslogs"
                },
                {
                    "name": "com.amazonaws.ecs.capability.selinux"
                },
                {
                    "name": "com.amazonaws.ecs.capability.docker-remote-api.1.24"
                },
                {
                    "name": "ecs.capability.task-eni-trunking"
                },
                {
                    "name": "com.amazonaws.ecs.capability.docker-remote-api.1.25"
                },
                {
                    "name": "com.amazonaws.ecs.capability.docker-remote-api.1.26"
                },
                {
                    "name": "com.amazonaws.ecs.capability.docker-remote-api.1.27"
                },
                {
                    "name": "com.amazonaws.ecs.capability.docker-remote-api.1.28"
                },
                {
                    "name": "com.amazonaws.ecs.capability.docker-remote-api.1.29"
                },
                {
                    "name": "ecs.cpu-architecture",
                    "value": "x86_64"
                },
                {
                    "name": "com.amazonaws.ecs.capability.ecr-auth"
                },
                {
                    "name": "com.amazonaws.ecs.capability.docker-remote-api.1.20"
                },
                {
                    "name": "ecs.os-type",
                    "value": "linux"
                },
                {
                    "name": "com.amazonaws.ecs.capability.docker-remote-api.1.21"
                },
                {
                    "name": "com.amazonaws.ecs.capability.docker-remote-api.1.22"
                },
                {
                    "name": "com.amazonaws.ecs.capability.docker-remote-api.1.23"
                },
                {
                    "name": "ecs.capability.private-registry-authentication.secretsmanager"
                },
                {
                    "name": "com.amazonaws.ecs.capability.logging-driver.json-file"
                },
                {
                    "name": "ecs.capability.execution-role-awslogs"
                },
                {
                    "name": "ecs.vpc-id",
                    "value": "vpc-0e3f6fef1f710c869"
                },
                {
                    "name": "com.amazonaws.ecs.capability.docker-remote-api.1.17"
                },
                {
                    "name": "com.amazonaws.ecs.capability.docker-remote-api.1.18"
                },
                {
                    "name": "com.amazonaws.ecs.capability.docker-remote-api.1.19"
                },
                {
                    "name": "ecs.capability.task-eni"
                },
                {
                    "name": "ecs.capability.efs"
                },
                {
                    "name": "ecs.capability.execution-role-ecr-pull"
                },
                {
                    "name": "bottlerocket.variant",
                    "value": "aws-ecs-1"
                },
                {
                    "name": "ecs.capability.task-eni.ipv6"
                },
                {
                    "name": "ecs.capability.container-health-check"
                },
                {
                    "name": "ecs.subnet-id",
                    "value": "subnet-09166ccaa28459f22"
                },
                {
                    "name": "ecs.instance-type",
                    "value": "c5.large"
                },
                {
                    "name": "com.amazonaws.ecs.capability.task-iam-role-network-host"
                },
                {
                    "name": "ecs.capability.container-ordering"
                },
                {
                    "name": "ecs.capability.cni-plugin-version",
                    "value": "55b2ae77-2020.09.0"
                },
                {
                    "name": "ecs.capability.env-files.s3"
                },
                {
                    "name": "ecs.capability.secrets.ssm.environment-variables"
                },
                {
                    "name": "ecs.capability.pid-ipc-namespace-sharing"
                },
                {
                    "name": "com.amazonaws.ecs.capability.task-iam-role"
                }
            ],
            "registeredAt": "2021-08-03T06:58:53.950000+00:00",
            "attachments": [],
            "tags": []
        }
    ],
    "failures": []
}

Session Managerで中をのぞく

タスクを実行する前に中をのぞいてみたいと思います。

なお、Bottlerocketではsshdは利用できず、管理はControll Container(必要に応じてAdmin Container)経由で行います。 Controll ContainerにSession Managerでアクセスできます。

Welcome to Bottlerocket's control container!

This container gives you access to the Bottlerocket API, which in turn lets you
inspect and configure the system.  You'll probably want to use the `apiclient`
tool for that; for example, to inspect the system:

   apiclient -u /settings

You can run `apiclient --help` for usage details, and check the main
Bottlerocket documentation for descriptions of all settings and examples of
changing them.

If you need to debug the system further, you can enable the admin container.
This enables SSH access to the system using the key you specified when you
launched the instance.  This environment has more debugging tools installed,
and allows you to get root access to the host.

To enable the admin container, run:

   enable-admin-container

[ssm-user@ip-172-31-33-39 /]$

設定の確認や変更方法はヘルプで確認しましょう。

$ apiclient --help
Usage: apiclient [SUBCOMMAND] [OPTION]...

Global options:
    -s, --socket-path PATH     Override the server socket path.  Default: /run/api.sock
    --log-level                Desired amount of output; trace|debug|info|warn|error
    -v, --verbose              Sets log level to 'debug'.  This prints extra info,
                               like HTTP status code to stderr in 'raw' mode.

Subcommands:
    raw                        Makes an HTTP request and prints the response on stdout.
                               'raw' is the default subcommand and may be omitted.
    apply                      Applies settings from TOML/JSON files at given URIs,
                               or from stdin.
    set                        Changes settings and applies them to the system.
    update check               Prints information about available updates.
    update apply               Applies available updates.
    update cancel              Deactivates an applied update.
    reboot                     Reboots the host.

raw options:
    -u, --uri URI              Required; URI to request from the server, e.g. /tx
    -m, -X, --method METHOD    HTTP method to use in request.  Default: GET
    -d, --data DATA            Data to include in the request body.  Default: empty

apply options:
    [ URI ...]                 The list of URIs to TOML or JSON settings files that you
                               want to apply to the system.  If no URI is specified, or
                               if "-" is given, reads from stdin.

reboot options:
    None.

set options:
    KEY=VALUE [KEY=VALUE ...]  The settings you want to set.  For example:
                                  settings.motd="hi there" settings.ecs.cluster=example
                               The "settings." prefix is optional.
                               Settings with dots in the name require nested quotes:
                                  'kubernetes.node-labels."my.label"=hello'
    -j, --json JSON            Alternatively, you can specify settings in JSON format,
                               which can simplify setting multiple values, and is necessary
                               for some numeric settings.  For example:
                                  -j '{"kernel": {"sysctl": {"vm.max_map_count": "262144"}}}'

update check options:
    None.

update apply options:
    -c, --check                Automatically `update check` and apply whatever is found.
    -r, --reboot               Automatically reboot if an update was found and applied.

update cancel options:
    None.

全設定はこんな感じです。

apiclient -u /
{
	"settings": {
		"motd": "Welcome to Bottlerocket!",
		"updates": {
			"metadata-base-url": "https://updates.bottlerocket.aws/2020-07-07/aws-ecs-1/x86_64/",
			"targets-base-url": "https://updates.bottlerocket.aws/targets/",
			"seed": 728,
			"version-lock": "latest",
			"ignore-waves": false
		},
		"host-containers": {
			"control": {
				"source": "328549459982.dkr.ecr.ap-northeast-1.amazonaws.com/bottlerocket-control:v0.5.1",
				"enabled": true,
				"superpowered": false
			},
			"admin": {
				"source": "328549459982.dkr.ecr.ap-northeast-1.amazonaws.com/bottlerocket-admin:v0.7.1",
				"enabled": false,
				"superpowered": true,
				"user-data": "eyJzc2giOnsiYXV0aG9yaXplZC1rZXlzIjpbInNzaC1yc2EgQUFBQUIzTnphQzF5YzJFQUFBQURBUUFCQUFBQkFRQ1U0UXBxcVlDcHhrWU5NVEtYeHVVSEoxRzlnbW1iWXRWTm5VTFNwM3VpWUl3QnJ5Z0lLYVEzK1VrOGdNVUFyZWJjaVhKNVlFd3NGcWdSSk4xcTNGck90UnRidDhmSEJvdEVGV3ptTzd3VFVWTnhIL01INWU5ZkpDTE52UGpHOFNkV3QxbW8wYlZ5WkNBSU5UN1ZCTy96cW1ucVJramlTbk5jZklZWE9yY1ZnVEJqdFhkb0Y2VnlCeU05QU94K3d1QzV6aXBTTkVqdTlBM0g1aTc0dS85SFNhZ2dkcGNpUGpVclQ3Y2ZUbDZRN2IrQkZEYUJkbWFpdERYSnNkaG9uRWc5K1RZNkJuRVVHcy9EK2hjTEl2bjlDN2JBeGNHbXJpOTZzMEhkQTVHM0RoVkszNE9DMUdETmQwNng5Sm9QeGk3ZjRVVDVGUDdnQ3VSTmliK0NSSzk1IHRva3lvLW5ha2F5YW1hLm5vYnVoaXJvIl19fQ=="
			}
		},
		"ntp": {
			"time-servers": [
				"169.254.169.123",
				"2.amazon.pool.ntp.org"
			]
		},
		"kernel": {
			"lockdown": "integrity"
		},
		"aws": {
			"region": "ap-northeast-1"
		},
		"ecs": {
			"cluster": "bottlerocket",
			"allow-privileged-containers": false,
			"logging-drivers": [
				"json-file",
				"awslogs",
				"none"
			],
			"loglevel": "info"
		},
		"metrics": {
			"metrics-url": "https://metrics.bottlerocket.aws/v1/metrics",
			"send-metrics": true,
			"service-checks": [
				"apiserver",
				"chronyd",
				"containerd",
				"host-containerd",
				"docker",
				"ecs"
			]
		}
	},
	"services": {
		"metricdog": {
			"configuration-files": [
				"metricdog-toml",
				"proxy-env"
			],
			"restart-commands": [
				"/bin/systemctl try-restart metricdog.service"
			]
		},
		"ntp": {
			"configuration-files": [
				"chrony-conf"
			],
			"restart-commands": [
				"/bin/systemctl try-reload-or-restart chronyd.service"
			]
		},
		"updog": {
			"configuration-files": [
				"updog-toml"
			],
			"restart-commands": []
		},
		"ecs": {
			"configuration-files": [
				"ecs-config"
			],
			"restart-commands": [
				"/usr/bin/ecs-settings-applier",
				"/bin/systemctl try-reload-or-restart ecs.service"
			]
		},
		"bootstrap-containers": {
			"configuration-files": [],
			"restart-commands": [
				"/usr/bin/bootstrap-containers create-containers"
			]
		},
		"docker": {
			"configuration-files": [
				"proxy-env"
			],
			"restart-commands": [
				"/bin/systemctl try-restart docker.service"
			]
		},
		"host-containers": {
			"configuration-files": [],
			"restart-commands": [
				"/usr/bin/host-containers"
			]
		},
		"motd": {
			"configuration-files": [
				"motd"
			],
			"restart-commands": []
		},
		"containerd": {
			"configuration-files": [
				"containerd-config-toml",
				"proxy-env"
			],
			"restart-commands": [
				"/bin/systemctl try-restart containerd.service"
			]
		},
		"sysctl": {
			"configuration-files": [],
			"restart-commands": [
				"/usr/bin/corndog sysctl"
			]
		},
		"lockdown": {
			"configuration-files": [],
			"restart-commands": [
				"/usr/bin/corndog lockdown"
			]
		},
		"host-containerd": {
			"configuration-files": [
				"proxy-env"
			],
			"restart-commands": [
				"/bin/systemctl try-restart host-containerd.service"
			]
		}
	},
	"configuration-files": {
		"motd": {
			"path": "/etc/motd",
			"template-path": "/usr/share/templates/motd"
		},
		"containerd-config-toml": {
			"path": "/etc/containerd/config.toml",
			"template-path": "/usr/share/templates/containerd-config-toml_basic"
		},
		"chrony-conf": {
			"path": "/etc/chrony.conf",
			"template-path": "/usr/share/templates/chrony-conf"
		},
		"proxy-env": {
			"path": "/etc/network/proxy.env",
			"template-path": "/usr/share/templates/proxy-env"
		},
		"ecs-config": {
			"path": "/etc/ecs/ecs.config",
			"template-path": "/usr/share/templates/ecs.config"
		},
		"updog-toml": {
			"path": "/etc/updog.toml",
			"template-path": "/usr/share/templates/updog-toml"
		},
		"metricdog-toml": {
			"path": "/etc/metricdog.toml",
			"template-path": "/usr/share/templates/metricdog-toml"
		}
	},
	"os": {
		"pretty_name": "Bottlerocket OS 1.1.4",
		"variant_id": "aws-ecs-1",
		"version_id": "1.1.4",
		"build_id": "f5239c49",
		"arch": "x86_64"
	}
}

まとめ

管理方法の違いや機能上の制約には注意する必要がありますが、ECS-Optimized Amazon Linux AMIと比較してBottlerocketにはセキュリティなどのアドバンテージがあります。 既存のECS on EC2環境の構成次第(制約を受容可能か)では比較的簡単に移行することも可能だと思いますので、セキュリティを重視している方は検証してみてはいかがでしょうか?