こんにちは、ニキです。
今回の記事では、ECSタスクをEC2上で実行します。
ECSを使えばコンテナ化されたアプリケーションを簡単にデプロイできます。また、Fargateと比較すると請求額を削減できます。
以下の流れで進めます。
- クラスターの作成
- Amazon ECS AMI を使用してインスタンスを起動
- コンテナインスタンスをクラスターに登録
- タスク定義の作成
- タスクの実行
簡単のためにECRではなく、Docker公式イメージを使います。
では、解説していきます。
ECSクラスターの作成
クラスターを作成します。
ここでは、MyClusterというクラスター名にしています。
aws ecs create-cluster --cluster-name MyCluster
以下のように出力されます。
{
"cluster": {
"clusterArn": "arn:aws:ecs:ap-northeast-1:825046422689:cluster/MyCluster",
"clusterName": "MyCluster",
"status": "ACTIVE",
"registeredContainerInstancesCount": 0,
"runningTasksCount": 0,
"pendingTasksCount": 0,
"activeServicesCount": 0,
"statistics": [],
"tags": [],
"settings": [
{
"name": "containerInsights",
"value": "disabled"
}
],
"capacityProviders": [],
"defaultCapacityProviderStrategy": []
}
}
ECSコンソール上で、以下のように作成したクラスターを確認できます。
ECSコンテナインスタンスをクラスターに登録
Amazon ECS AMI を使用してインスタンスを起動します。
タスクを実行するには、ECS用に最適化したコンテナインスタンスを起動する必要があります。
その他には高度な詳細で以下のように設定する以外は、通常の起動方法と同じなのでさらっと解説します。
- IAMインスタンスプロフィール: ecsInstaceRoleを選択
- ユーザーデータ: 指定のクラスターでコンテナインスタンスが起動される、スクリプトを記述
EC2起動方法の詳細は以下の記事で解説しています。
アプリケーションと OS イメージ (Amazon マシンイメージ) :
以下から、Amazon ECS AMIを選択します。
インスタンスタイプとキーペアを選択します。
ネットワーク設定とストレージを設定します。
高度な詳細で以下のように設定します。
- IAMインスタンスプロフィール: ecsInstaceRole(自動で作成されます)
- ユーザーデータ:
#!/bin/bash
echo ECS_CLUSTER=MyCluster >> /etc/ecs/ecs.config
概要を確認します。
指定のクラスター内にECSコンテナインスタンスが起動しているかを確認します。
aws ecs list-container-instances --cluster MyCluster
以下のようであれば、正常に起動しています。
{
"containerInstanceArns": [
"arn:aws:ecs:ap-northeast-1:aws_account_id:container-instance/MyCluster/container_instance_ID"
]
}
指定のクラスターに、コンテナインスタンスを登録します。
この作業で、クラスター内でコンテナインスタンスを使用できるようになります。
aws ecs describe-container-instances --cluster MyCluster --container-instances container_instance_ID
以下のように出力されます。
{
"containerInstances": [
{
"containerInstanceArn": "arn:aws:ecs:ap-northeast-1:account_id:container-instance/MyCluster/container_instance_ID",
"ec2InstanceId": "*************",
"version": 3,
"versionInfo": {
"agentVersion": "1.76.0",
"agentHash": "7ab9dd56",
"dockerVersion": "DockerVersion: 20.10.23"
},
"remainingResources": [
{
"name": "CPU",
"type": "INTEGER",
"doubleValue": 0.0,
"longValue": 0,
"integerValue": 2048
},
{
"name": "MEMORY",
"type": "INTEGER",
"doubleValue": 0.0,
"longValue": 0,
"integerValue": 1855
},
{
"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": 1855
},
{
"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": "unknown-"
},
{
"name": "ecs.ami-id",
"value": "ami-0c9def8def64a90c8"
},
{
"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": "ecs.capability.efsAuth"
},
{
"name": "ecs.capability.full-sync"
},
{
"name": "com.amazonaws.ecs.capability.docker-remote-api.1.30"
},
{
"name": "com.amazonaws.ecs.capability.docker-remote-api.1.31"
},
{
"name": "com.amazonaws.ecs.capability.docker-remote-api.1.32"
},
{
"name": "com.amazonaws.ecs.capability.logging-driver.fluentd"
},
{
"name": "ecs.capability.firelens.options.config.file"
},
{
"name": "ecs.capability.logging-driver.awsfirelens.log-driver-buffer-limit"
},
{
"name": "ecs.availability-zone",
"value": "ap-northeast-1a"
},
{
"name": "ecs.capability.aws-appmesh"
},
{
"name": "com.amazonaws.ecs.capability.logging-driver.awslogs"
},
{
"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.privileged-container"
},
{
"name": "com.amazonaws.ecs.capability.docker-remote-api.1.29"
},
{
"name": "ecs.cpu-architecture",
"value": "arm64"
},
{
"name": "ecs.capability.firelens.fluentbit"
},
{
"name": "com.amazonaws.ecs.capability.ecr-auth"
},
{
"name": "com.amazonaws.ecs.capability.docker-remote-api.1.20"
},
{
"name": "ecs.capability.service-connect-v1"
},
{
"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.task-eia"
},
{
"name": "ecs.capability.private-registry-authentication.secretsmanager"
},
{
"name": "com.amazonaws.ecs.capability.logging-driver.syslog"
},
{
"name": "com.amazonaws.ecs.capability.logging-driver.awsfirelens"
},
{
"name": "ecs.capability.firelens.options.config.s3"
},
{
"name": "com.amazonaws.ecs.capability.logging-driver.json-file"
},
{
"name": "ecs.capability.execution-role-awslogs"
},
{
"name": "ecs.vpc-id",
"value": "vpc-096810d0157e0326f"
},
{
"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.docker-plugin.amazon-ecs-volume-plugin"
},
{
"name": "ecs.capability.task-eni"
},
{
"name": "ecs.capability.firelens.fluentd"
},
{
"name": "ecs.capability.efs"
},
{
"name": "ecs.capability.execution-role-ecr-pull"
},
{
"name": "ecs.capability.task-eni.ipv6"
},
{
"name": "ecs.capability.container-health-check"
},
{
"name": "ecs.os-family",
"value": "LINUX"
},
{
"name": "ecs.capability.execute-command"
},
{
"name": "ecs.subnet-id",
"value": "subnet-07d67e95d14649319"
},
{
"name": "ecs.instance-type",
"value": "t4g.small"
},
{
"name": "com.amazonaws.ecs.capability.task-iam-role-network-host"
},
{
"name": "ecs.capability.increased-task-cpu-limit"
},
{
"name": "ecs.capability.network.container-port-range"
},
{
"name": "ecs.capability.container-ordering"
},
{
"name": "ecs.capability.cni-plugin-version",
"value": "unknown-"
},
{
"name": "ecs.capability.env-files.s3"
},
{
"name": "ecs.capability.pid-ipc-namespace-sharing"
},
{
"name": "ecs.capability.secrets.ssm.environment-variables"
},
{
"name": "com.amazonaws.ecs.capability.task-iam-role"
}
],
"registeredAt": "2023-10-08T18:59:31.079000+09:00",
"attachments": [],
"tags": []
}
],
"failures": []
}
ECSコンソール上で、コンテナインスタンスの登録を確認できます。
ECSタスクの実行
タスク定義ファイルを作成します。
touch task-definition.json
今回はNginxを例に以下のように作成します。
動作可能な最小構成にしています。他にもタスク定義パラメーターはあり、以下のリンクから確認できます。
{
"containerDefinitions": [
{
"name": "nginx",
"image": "nginx",
"memory": 10,
"portMappings": [
{
"containerPort": 80,
"hostPort": 80,
"protocol": "tcp"
}
]
}
],
"family": "nginx"
}
タスク定義を登録します。
aws ecs register-task-definition --cli-input-json file://task-definition.json
以下のように出力されます。
{
"taskDefinition": {
"taskDefinitionArn": "arn:aws:ecs:ap-northeast-1:account_id:task-definition/nginx:2",
"containerDefinitions": [
{
"name": "nginx",
"image": "nginx",
"cpu": 0,
"memory": 10,
"portMappings": [],
"essential": true,
"environment": [],
"mountPoints": [],
"volumesFrom": []
}
],
"family": "nginx",
"revision": 1,
"volumes": [],
"status": "ACTIVE",
"placementConstraints": [],
"compatibilities": [
"EXTERNAL",
"EC2"
],
"registeredAt": "2023-10-09T15:21:46.147000+09:00",
"registeredBy": "arn:aws:sts::account_id:assumed-role/************"
}
}
タスク定義の一覧を表示します。
aws ecs list-task-definitions
以下のように、作成したタスク定義が表示されます。
{
"taskDefinitionArns": [
"arn:aws:ecs:ap-northeast-1:825046422689:task-definition/nginx:1"
]
}
ECSコンソールからも確認できます。
タスクを実行します。
aws ecs run-task --cluster MyCluster --task-definition nginx:1 --count 1
以下のように出力されます。
{
"tasks": [
{
"attachments": [],
"attributes": [
{
"name": "ecs.cpu-architecture",
"value": "arm64"
}
],
"availabilityZone": "ap-northeast-1a",
"clusterArn": "arn:aws:ecs:ap-northeast-1:account_id:cluster/MyCluster",
"containerInstanceArn": "arn:aws:ecs:ap-northeast-1:account_id:container-instance/MyCluster/task_ID",
"containers": [
{
"containerArn": "arn:aws:ecs:ap-northeast-1:account_id:container/MyCluster/task_ID/***************",
"taskArn": "arn:aws:ecs:ap-northeast-1:account_id:task/MyCluster/task_ID",
"name": "nginx",
"image": "nginx",
"lastStatus": "PENDING",
"networkInterfaces": [],
"cpu": "0",
"memory": "10"
}
],
"cpu": "0",
"createdAt": "2023-10-09T16:23:13.916000+09:00",
"desiredStatus": "RUNNING",
"enableExecuteCommand": false,
"group": "family:nginx",
"lastStatus": "PENDING",
"launchType": "EC2",
"memory": "10",
"overrides": {
"containerOverrides": [
{
"name": "nginx"
}
],
"inferenceAcceleratorOverrides": []
},
"tags": [],
"taskArn": "arn:aws:ecs:ap-northeast-1:account_id:task/MyCluster/task_ID",
"taskDefinitionArn": "arn:aws:ecs:ap-northeast-1:account_id:task-definition/nginx:3",
"version": 1
}
],
"failures": []
}
タスクの一覧を表示します。
aws ecs list-tasks --cluster MyCluster
実行中のタスクが表示されます。
{
"taskArns": [
"arn:aws:ecs:ap-northeast-1:account_id:task/MyCluster/task_ID"
]
}
ECSコンソールからも確認できます。
Nginxを例に使ったので、ついでにブラウザからアクセスできるか確認します。
以下のように表示されれば正常に動作しています。
EC2に接続して、コンテナの状態を確認してみます。
sudo docker ps
想定通り動作しているのが確認できました。
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4c32404e3165 nginx "/docker-entrypoint.…" 17 minutes ago Up 17 minutes 0.0.0.0:80->80/tcp, :::80->80/tcp ecs-nginx-1-nginx-acd5f9d58c8098865e00
b73c8bb3e22b amazon/amazon-ecs-agent:latest "/agent" 35 minutes ago Up 35 minutes (healthy) ecs-agent
まとめ
今回の記事では、ECSタスクをEC2上で実行する方法を解説しました。