Amazon ECS Service Connectがよく分からんので触っておく
概要
2022.11.29のAWS Updateで「Amazon ECS Service Connect」が発表されました。周りの方々は盛り上がっていたけど、自分があんまりコンテナ触らない為か盛り上がりが体感出来なかったので触っておきましょう。というアウトプット。
ざっくり
AWS Cloud Mapが提供する名前空間を使って論理名でサービスを参照・接続でき、ロードバランサーを導入・設定しなくてもECSタスク間で自動的にトラフィックを分散させることができる。
参考
手順
■ecsクラスターの作成
--service-connect-defaults
でAWS Cloud Mapに追加するnamespaceの設定を行いつつクラスターを作成
cmd
aws ecs create-cluster \
--cluster-name tutorial \
--service-connect-defaults namespace=service-connect
result
result
{
"cluster": {
"clusterArn": "arn:aws:ecs:ap-northeast-1:123456789012:cluster/tutorial",
"clusterName": "tutorial",
"status": "PROVISIONING",
"registeredContainerInstancesCount": 0,
"runningTasksCount": 0,
"pendingTasksCount": 0,
"activeServicesCount": 0,
"statistics": [],
"tags": [],
"settings": [
{
"name": "containerInsights",
"value": "enabled"
}
],
"capacityProviders": [],
"defaultCapacityProviderStrategy": [],
"attachments": [
{
"id": "f23637c8-dd3a-4c59-aefc-842f270a4ca0",
"type": "sc",
"status": "ATTACHING",
"details": []
}
],
"attachmentsStatus": "UPDATE_IN_PROGRESS",
"serviceConnectDefaults": {
"namespace": "arn:aws:servicediscovery:ap-northeast-1:123456789012:namespace/ns-vdpucf3aztj23ecw"
}
}
}
result-image
クラスタが出来ました。名前空間
というページが増えていますね
■AWS Cloud Mapに追加されていることを確認
service-connect
という名前空間が追加されていることを確認
cmd
aws servicediscovery \
list-namespaces \
--region ap-northeast-1 \
--filters Name="NAME",Values="service-connect",Condition="EQ"
result
result
{
"Namespaces": [
{
"Id": "ns-vdpucf3aztj23ecw",
"Arn": "arn:aws:servicediscovery:ap-northeast-1:123456789012:namespace/ns-vdpucf3aztj23ecw",
"Name": "service-connect",
"Type": "HTTP",
"Properties": {
"DnsProperties": {
"SOA": {}
},
"HttpProperties": {
"HttpName": "service-connect"
}
},
"CreateDate": "2022-11-29T11:33:22.132000+00:00"
}
]
}
result-image
■タスク定義ファイル作成
タスク定義を記載したjsonファイルを準備し、そのファイルを読み込みタスク定義を構築する
containerDefinitions[].nameがService Connectで追加された名前空間指定の箇所
cmd
cat << EOF > service-connect-nginx.json
{
"family": "service-connect-nginx",
"taskRoleArn": "arn:aws:iam::123456789012:role/ecsTaskExecutionRole",
"executionRoleArn": "arn:aws:iam::123456789012:role/ecsTaskExecutionRole",
"networkMode": "awsvpc",
"containerDefinitions": [
{
"name": "webserver",
"image": "public.ecr.aws/docker/library/nginx:latest",
"cpu": 100,
"portMappings": [
{
"name": "nginx",
"containerPort": 80,
"protocol": "tcp",
"appProtocol": "http"
}
],
"essential": true,
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/ecs/service-connect-nginx",
"awslogs-region": "ap-northeast-1",
"awslogs-stream-prefix": "nginx"
}
}
}
],
"cpu": "256",
"memory": "512"
}
EOF
aws ecs register-task-definition \
--cli-input-json file://service-connect-nginx.json
result
result
{
"taskDefinition": {
"taskDefinitionArn": "arn:aws:ecs:ap-northeast-1:123456789012:task-definition/service-connect-nginx:1",
"containerDefinitions": [
{
"name": "webserver",
"image": "public.ecr.aws/docker/library/nginx:latest",
"cpu": 100,
"portMappings": [
{
"containerPort": 80,
"hostPort": 80,
"protocol": "tcp",
"name": "nginx",
"appProtocol": "http"
}
],
"essential": true,
"environment": [],
"mountPoints": [],
"volumesFrom": [],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/ecs/service-connect-nginx",
"awslogs-region": "ap-northeast-1",
"awslogs-stream-prefix": "nginx"
}
}
}
],
"family": "service-connect-nginx",
"taskRoleArn": "arn:aws:iam::123456789012:role/ecsTaskExecutionRole",
"executionRoleArn": "arn:aws:iam::123456789012:role/ecsTaskExecutionRole",
"networkMode": "awsvpc",
"revision": 1,
"volumes": [],
"status": "ACTIVE",
"requiresAttributes": [
{
"name": "com.amazonaws.ecs.capability.logging-driver.awslogs"
},
{
"name": "ecs.capability.execution-role-awslogs"
},
{
"name": "com.amazonaws.ecs.capability.docker-remote-api.1.19"
},
{
"name": "com.amazonaws.ecs.capability.task-iam-role"
},
{
"name": "com.amazonaws.ecs.capability.docker-remote-api.1.18"
},
{
"name": "ecs.capability.task-eni"
}
],
"placementConstraints": [],
"compatibilities": [
"EC2",
"FARGATE"
],
"cpu": "256",
"memory": "512",
"registeredAt": "2022-11-29T11:57:49.196000+00:00",
"registeredBy": "arn:aws:sts::123456789012:assumed-role/AWSReservedSSO_AWSAdministratorAccess_bf8b32a74b14b58e/ShigeruOda"
}
}
result-image
タスク定義が出来ました。
■サービス作成
- サービス定義を記載したjsonファイルを準備し、そのファイルを読み込みサービスを構築する
- セキュリティグループ、サブネットはデフォルトVPCを利用し、inboundのhttpポート開放
- serviceConnectConfigurationがService Connectの為の設定となります
cmd
cat << EOF > service-connect-nginx-service.json
{
"cluster": "tutorial",
"deploymentConfiguration": {
"maximumPercent": 200,
"minimumHealthyPercent": 0
},
"deploymentController": {
"type": "ECS"
},
"desiredCount": 1,
"enableECSManagedTags": true,
"enableExecuteCommand": true,
"launchType": "FARGATE",
"networkConfiguration": {
"awsvpcConfiguration": {
"assignPublicIp": "ENABLED",
"securityGroups": [
"sg-34692f46"
],
"subnets": [
"subnet-f9bb89a2",
"subnet-9a4c8cd2",
"subnet-725e9559"
]
}
},
"platformVersion": "LATEST",
"propagateTags": "SERVICE",
"serviceName": "service-connect-nginx-service",
"serviceConnectConfiguration": {
"enabled": true,
"namespace": true,
"services": [
{
"portName": "nginx",
"clientAliases": [
{
"port": 80
}
]
}
],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/ecs/service-connect-proxy",
"awslogs-region": "ap-northeast-1",
"awslogs-stream-prefix": "service-connect-proxy"
}
}
},
"taskDefinition": "service-connect-nginx"
}
EOF
aws ecs create-service \
--cluster tutorial \
--cli-input-json file://service-connect-nginx-service.json
result
result
{
"service": {
"serviceArn": "arn:aws:ecs:ap-northeast-1:123456789012:service/tutorial/service-connect-nginx-service",
"serviceName": "service-connect-nginx-service",
"clusterArn": "arn:aws:ecs:ap-northeast-1:123456789012:cluster/tutorial",
"loadBalancers": [],
"serviceRegistries": [],
"status": "ACTIVE",
"desiredCount": 1,
"runningCount": 0,
"pendingCount": 0,
"launchType": "FARGATE",
"platformVersion": "LATEST",
"platformFamily": "Linux",
"taskDefinition": "arn:aws:ecs:ap-northeast-1:123456789012:task-definition/service-connect-nginx:1",
"deploymentConfiguration": {
"deploymentCircuitBreaker": {
"enable": false,
"rollback": false
},
"maximumPercent": 200,
"minimumHealthyPercent": 0
},
"deployments": [
{
"id": "ecs-svc/2314065177896282440",
"status": "PRIMARY",
"taskDefinition": "arn:aws:ecs:ap-northeast-1:123456789012:task-definition/service-connect-nginx:1",
"desiredCount": 1,
"pendingCount": 0,
"runningCount": 0,
"failedTasks": 0,
"createdAt": "2022-11-29T12:38:08.284000+00:00",
"updatedAt": "2022-11-29T12:38:08.284000+00:00",
"launchType": "FARGATE",
"platformVersion": "1.4.0",
"platformFamily": "Linux",
"networkConfiguration": {
"awsvpcConfiguration": {
"subnets": [
"subnet-725e9559",
"subnet-9a4c8cd2",
"subnet-f9bb89a2"
],
"securityGroups": [
"sg-34692f46"
],
"assignPublicIp": "ENABLED"
}
},
"rolloutState": "IN_PROGRESS",
"rolloutStateReason": "ECS deployment ecs-svc/2314065177896282440 in progress.",
"serviceConnectConfiguration": {
"enabled": true,
"namespace": "arn:aws:servicediscovery:ap-northeast-1:123456789012:namespace/ns-vdpucf3aztj23ecw",
"services": [
{
"portName": "nginx",
"discoveryName": "nginx",
"clientAliases": [
{
"port": 80,
"dnsName": "nginx.service-connect"
}
]
}
],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/ecs/service-connect-proxy",
"awslogs-region": "ap-northeast-1",
"awslogs-stream-prefix": "service-connect-proxy"
},
"secretOptions": []
}
},
"serviceConnectResources": [
{
"discoveryName": "nginx",
"discoveryArn": "arn:aws:servicediscovery:ap-northeast-1:123456789012:service/srv-tsw4bbsna23fxcjx"
}
]
}
],
"roleArn": "arn:aws:iam::123456789012:role/aws-service-role/ecs.amazonaws.com/AWSServiceRoleForECS",
"events": [],
"createdAt": "2022-11-29T12:38:08.284000+00:00",
"placementConstraints": [],
"placementStrategy": [],
"networkConfiguration": {
"awsvpcConfiguration": {
"subnets": [
"subnet-725e9559",
"subnet-9a4c8cd2",
"subnet-f9bb89a2"
],
"securityGroups": [
"sg-34692f46"
],
"assignPublicIp": "ENABLED"
}
},
"schedulingStrategy": "REPLICA",
"deploymentController": {
"type": "ECS"
},
"createdBy": "arn:aws:iam::123456789012:role/aws-reserved/sso.amazonaws.com/ap-northeast-1/AWSReservedSSO_AWSAdministratorAccess_bf8b32a74b14b58e",
"enableECSManagedTags": true,
"propagateTags": "SERVICE",
"enableExecuteCommand": true
}
}
result-image
サービスが起動しました
■接続確認
タスクを確認するとパブリック IP
が確認できます。
またコンテナが2つ起動しています
-
webserver
: nginxが起動しているコンテナ -
ecs-service-connect-fphC624
: ecs-service-connectと繋げているコンテナ
パブリック IP
でhttpアクセスするとnginxが確認できます。
ecs-service-connect
のCloudWatchを見るとApp Mesh
、ENVOY
が稼働していることを確認できます。
time="2022-11-29T12:49:57Z" level=info msg="App Mesh Environment Variables: [APPMESH_RESOURCE_ARN=arn:aws:ecs:ap-northeast-1:123456789012:task-set/tutorial/service-connect-nginx-service/ecs-svc/2314065177896282440 APPMESH_METRIC_EXTENSION_VERSION=1 APPMESH_XDS_ENDPOINT=unix:///var/run/ecs/appnet/relay/appnet_relay_listener.sock]"
time="2022-11-29T12:49:57Z" level=info msg="Envoy Environment Variables: [ENVOY_ENABLE_IAM_AUTH_FOR_XDS=0 ENVOY_ADMIN_MODE=UDS ENVOY_CONCURRENCY=2]"
time="2022-11-29T12:49:57Z" level=info msg="Agent Environment Variables: [APPNET_LISTENER_PORT_MAPPING={\"egress\":42084,\"ingress-nginx\":43727} APPNET_AGENT_ADMIN_UDS_PATH=/var/run/ecs/appnet/agent/appnet_admin.sock APPNET_ENVOY_RESTART_COUNT=3 APPNET_AGENT_ADMIN_MODE=UDS]"
time="2022-11-29T12:49:57Z" level=info msg="Disabling IAM Auth for xDS, xDS endpoint UDS path: /var/run/ecs/appnet/relay/appnet_relay_listener.sock"
[2022-11-29 12:49:57.559][1][info] [AppNet Agent] Server started, /var/run/ecs/appnet/agent/appnet_admin.sock
CloudMapを確認するとnginxがecsより追加されていることが確認できます
さらにCloudMapを詳細に確認するとIPアドレスやポートが想定通りであることが確認できます。
ECSの名前空間ページの方がCloud Mapより整理されていて分かりやすいね
感想
ELBやApp Meshを使わないでもCloud Mapで楽にマイクロサービスを実現できる
マイクロサービスをやりたいが、App Meshの運用までやりたくない場合にはコレで良いのでは無いだろうか。。。
Discussion