44장. ECS의 구조 — Cluster · Task · Service
이 장에서 말하고자 하는 것
도커 이미지를 ECR에 올렸으니
이제 그 이미지를 실제로 돌리는 도구가 필요하다.
Amazon ECS (Elastic Container Service)
다.
이 장은 ECS가 무엇이고 어떤 구성 요소로 동작하는지 본다.
1. ECS는 무엇을 해주는가
ECS는 컨테이너 오케스트레이션 서비스다.
다음을 자동으로 한다.
- 컨테이너 어디서 돌릴지 결정
- 죽으면 다시 띄우기
- 트래픽 분배(ALB 연동)
- 로그/메트릭 수집
- 배포 (Rolling / Blue-Green)
사람이 EC2에 SSH로 들어가 docker run 하지 않게 해준다.
2. ECS의 4개 핵심 개념
Task Definition : 컨테이너 1대의 "설계도"
Task : 실제로 돌고 있는 컨테이너 묶음
Service : Task가 항상 N개 살아 있도록 관리하는 컨트롤러
Cluster : 위 모든 것이 들어 있는 논리적 공간
[Cluster: msa]
├─ Service "orders"
│ ├─ Task 1 (Task Definition: orders:7)
│ └─ Task 2
├─ Service "users"
│ └─ ...
3. Task Definition — 컨테이너 설계도
어떤 이미지를 / 어떤 자원으로 / 어떤 환경 변수로 돌릴지의 정의.
- 이미지 URL
- CPU · 메모리
- 환경 변수
- 포트
- IAM Role
- 로그 설정
자세한 건 45장.
4. Task — 살아 있는 컨테이너 묶음
Task는 하나 이상의 컨테이너 다.
Task A
├─ app 컨테이너
└─ log-forwarder 컨테이너 (사이드카)
대부분 Task = 컨테이너 1개.
필요할 때만 사이드카를 추가한다.
Task는 일회용이다. 죽으면 끝, Service가 다시 띄운다.
5. Service — Task를 N개 유지하는 컨트롤러
desiredCount = 2
├─ Task 1 죽음 → Service가 새 Task 띄움
└─ Task 2 정상
Service는 또한
- ALB Target Group에 Task IP 자동 등록
- 헬스 체크 실패 시 교체
- 새 버전 배포 (Rolling)
까지 한다. 운영의 대부분은 Service 단위.
6. Cluster — 논리적 그룹
환경별로 나누는 게 일반적이다.
prod 클러스터 → 운영
stage 클러스터 → 스테이징
dev 클러스터 → 개발
7. Capacity Provider — 컨테이너를 어디서 돌릴까
- Fargate — 서버리스, 노드 관리 없음
- EC2 — 본인이 만든 EC2 클러스터
이 선택을 추상화한 게 Capacity Provider다. 자세한 비교는 46장.
8. 우리 서비스에서
[Cluster: msa]
├─ Service "orders" (Fargate, desired=2)
├─ Service "users" (Fargate, desired=2)
├─ Service "payments" (Fargate, desired=2)
└─ Service "web" (Fargate, desired=2)
9. 직접 확인해보기 — CLI
aws ecs create-cluster --cluster-name msa
aws ecs register-task-definition \
--cli-input-json file://task-def.json
aws ecs create-service \
--cluster msa \
--service-name orders \
--task-definition orders:1 \
--desired-count 2 \
--launch-type FARGATE \
--network-configuration "awsvpcConfiguration={subnets=[...],securityGroups=[...]}"
aws ecs list-tasks --cluster msa --service-name orders
10. 코드로는 이렇게 생겼다 — Terraform
resource "aws_ecs_cluster" "main" {
name = "msa"
setting {
name = "containerInsights"
value = "enabled"
}
}
resource "aws_ecs_task_definition" "orders" {
family = "orders"
network_mode = "awsvpc"
requires_compatibilities = ["FARGATE"]
cpu = "512"
memory = "1024"
execution_role_arn = aws_iam_role.task_execution.arn
container_definitions = jsonencode([{
name = "app"
image = "${aws_ecr_repository.orders.repository_url}:v1"
essential = true
portMappings = [{ containerPort = 8080 }]
}])
}
resource "aws_ecs_service" "orders" {
name = "orders"
cluster = aws_ecs_cluster.main.id
task_definition = aws_ecs_task_definition.orders.arn
desired_count = 2
launch_type = "FARGATE"
network_configuration {
subnets = [aws_subnet.private_a.id, aws_subnet.private_b.id]
security_groups = [aws_security_group.task.id]
}
}
11. 이렇게 쓰면 망한다 — 안티패턴
안티패턴 1. Container Insights를 안 켠다
ECS의 메트릭이 제대로 안 모인다.
안티패턴 2. 한 클러스터에 prod와 dev를 섞는다
권한 · 네트워크 · 비용이 다 섞인다.
안티패턴 3. Task에 외부 IP를 직접 노출한다
assign_public_ip = true 는 보안 위험. Task는 프라이빗 서브넷.
안티패턴 4. Service 없이 RunTask로만 띄운다
RunTask는 일회성. 운영 서비스는 무조건 Service.
12. 한 줄로 정리
ECS는 Cluster 안에서 Service가 Task Definition으로 Task를 N개 살아 있게 유지하는 구조다
13. 이 장의 핵심 정리
- ECS의 네 축은 Cluster · Service · Task Definition · Task 다.
- Task Definition은 설계도, Task는 실행 인스턴스다.
- Service가 Task 수와 배포를 책임진다.
- Capacity Provider는 Fargate/EC2 선택을 추상화한다.
- 환경별로 Cluster를 나누고 Container Insights를 켠다.
- 운영 서비스에 RunTask 단독은 쓰지 않는다.