컨테이너 서비스 (ECS/EKS/Fargate vs GKE/Cloud Run)
컨테이너 서비스 (ECS/EKS/Fargate vs GKE/Cloud Run)¶
1. 컨테이너 개요¶
1.1 컨테이너 vs VM¶
┌─────────────────────────────────────────────────────────────┐
│ 가상 머신 (VM) │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ App A │ │ App B │ │ App C │ │
│ ├─────────┤ ├─────────┤ ├─────────┤ │
│ │Guest OS │ │Guest OS │ │Guest OS │ ← 각 VM마다 OS │
│ └─────────┘ └─────────┘ └─────────┘ │
│ ┌─────────────────────────────────────────────────────────┐│
│ │ Hypervisor ││
│ └─────────────────────────────────────────────────────────┘│
│ ┌─────────────────────────────────────────────────────────┐│
│ │ Host OS ││
│ └─────────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ 컨테이너 │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ App A │ │ App B │ │ App C │ │
│ ├─────────┤ ├─────────┤ ├─────────┤ │
│ │ Libs │ │ Libs │ │ Libs │ ← 라이브러리만 │
│ └─────────┘ └─────────┘ └─────────┘ │
│ ┌─────────────────────────────────────────────────────────┐│
│ │ Container Runtime ││
│ └─────────────────────────────────────────────────────────┘│
│ ┌─────────────────────────────────────────────────────────┐│
│ │ Host OS ││
│ └─────────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────────┘
1.2 서비스 비교¶
| 항목 | AWS | GCP |
|---|---|---|
| 컨테이너 레지스트리 | ECR | Artifact Registry |
| 컨테이너 오케스트레이션 | ECS | - |
| Kubernetes 관리형 | EKS | GKE |
| 서버리스 컨테이너 | Fargate | Cloud Run |
| App Platform | App Runner | Cloud Run |
2. 컨테이너 레지스트리¶
2.1 AWS ECR (Elastic Container Registry)¶
# 1. ECR 레포지토리 생성
aws ecr create-repository \
--repository-name my-app \
--region ap-northeast-2
# 2. Docker 로그인
aws ecr get-login-password --region ap-northeast-2 | \
docker login --username AWS --password-stdin \
123456789012.dkr.ecr.ap-northeast-2.amazonaws.com
# 3. 이미지 빌드 및 태그
docker build -t my-app .
docker tag my-app:latest \
123456789012.dkr.ecr.ap-northeast-2.amazonaws.com/my-app:latest
# 4. 이미지 푸시
docker push 123456789012.dkr.ecr.ap-northeast-2.amazonaws.com/my-app:latest
# 5. 이미지 목록 확인
aws ecr list-images --repository-name my-app
2.2 GCP Artifact Registry¶
# 1. Artifact Registry API 활성화
gcloud services enable artifactregistry.googleapis.com
# 2. 레포지토리 생성
gcloud artifacts repositories create my-repo \
--repository-format=docker \
--location=asia-northeast3 \
--description="My Docker repository"
# 3. Docker 인증 설정
gcloud auth configure-docker asia-northeast3-docker.pkg.dev
# 4. 이미지 빌드 및 태그
docker build -t my-app .
docker tag my-app:latest \
asia-northeast3-docker.pkg.dev/PROJECT_ID/my-repo/my-app:latest
# 5. 이미지 푸시
docker push asia-northeast3-docker.pkg.dev/PROJECT_ID/my-repo/my-app:latest
# 6. 이미지 목록 확인
gcloud artifacts docker images list \
asia-northeast3-docker.pkg.dev/PROJECT_ID/my-repo
3. AWS ECS (Elastic Container Service)¶
3.1 ECS 개념¶
┌─────────────────────────────────────────────────────────────┐
│ ECS Cluster │
│ ┌─────────────────────────────────────────────────────────┐│
│ │ Service ││
│ │ ┌───────────────┐ ┌───────────────┐ ││
│ │ │ Task │ │ Task │ ← 컨테이너 그룹 ││
│ │ │ ┌───────────┐ │ │ ┌───────────┐ │ ││
│ │ │ │ Container │ │ │ │ Container │ │ ││
│ │ │ └───────────┘ │ │ └───────────┘ │ ││
│ │ └───────────────┘ └───────────────┘ ││
│ └─────────────────────────────────────────────────────────┘│
│ ┌───────────────────┐ ┌───────────────────┐ │
│ │ EC2 Instance │ │ Fargate │ │
│ │ (자체 관리) │ │ (서버리스) │ │
│ └───────────────────┘ └───────────────────┘ │
└─────────────────────────────────────────────────────────────┘
3.2 ECS 클러스터 생성¶
# 1. 클러스터 생성 (Fargate)
aws ecs create-cluster \
--cluster-name my-cluster \
--capacity-providers FARGATE FARGATE_SPOT
# 2. Task Definition 생성
# task-definition.json
{
"family": "my-task",
"networkMode": "awsvpc",
"requiresCompatibilities": ["FARGATE"],
"cpu": "256",
"memory": "512",
"executionRoleArn": "arn:aws:iam::123456789012:role/ecsTaskExecutionRole",
"containerDefinitions": [
{
"name": "my-container",
"image": "123456789012.dkr.ecr.ap-northeast-2.amazonaws.com/my-app:latest",
"essential": true,
"portMappings": [
{
"containerPort": 80,
"protocol": "tcp"
}
],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/ecs/my-task",
"awslogs-region": "ap-northeast-2",
"awslogs-stream-prefix": "ecs"
}
}
}
]
}
aws ecs register-task-definition --cli-input-json file://task-definition.json
# 3. 서비스 생성
aws ecs create-service \
--cluster my-cluster \
--service-name my-service \
--task-definition my-task:1 \
--desired-count 2 \
--launch-type FARGATE \
--network-configuration "awsvpcConfiguration={subnets=[subnet-xxx],securityGroups=[sg-xxx],assignPublicIp=ENABLED}"
3.3 ECS Service Connect¶
ECS Service Connect는 별도의 프록시나 서비스 메시 설정 없이 서비스 간 통신을 위한 내장 서비스 메시 기능을 제공합니다.
// Service Connect가 포함된 서비스 정의
{
"cluster": "my-cluster",
"serviceName": "backend-service",
"taskDefinition": "backend-task:1",
"serviceConnectConfiguration": {
"enabled": true,
"namespace": "my-app-namespace",
"services": [
{
"portName": "http",
"discoveryName": "backend",
"clientAliases": [
{
"port": 80,
"dnsName": "backend.local"
}
]
}
]
},
"desiredCount": 2,
"launchType": "FARGATE",
"networkConfiguration": {
"awsvpcConfiguration": {
"subnets": ["subnet-xxx"],
"securityGroups": ["sg-xxx"]
}
}
}
주요 장점: - 내장 서비스 디스커버리 (AWS Cloud Map 통합) - 서비스 간 자동 로드 밸런싱 - 추가 에이전트 없이 트래픽 메트릭 및 관측성(Observability) 제공 - 외부 서비스 메시(Istio, Consul) 불필요
3.4 ECS Exec (컨테이너 디버깅)¶
ECS Exec을 사용하면 실행 중인 컨테이너에 대화형 셸로 접근하여 디버깅할 수 있습니다.
# 서비스에서 ECS Exec 활성화
aws ecs update-service \
--cluster my-cluster \
--service my-service \
--enable-execute-command
# 대화형 셸 세션 시작
aws ecs execute-command \
--cluster my-cluster \
--task TASK_ID \
--container my-container \
--interactive \
--command "/bin/sh"
# 일회성 명령 실행
aws ecs execute-command \
--cluster my-cluster \
--task TASK_ID \
--container my-container \
--command "cat /app/config.json"
참고: ECS Exec을 사용하려면 태스크 역할에
ssmmessages권한이 필요하며, 태스크 정의에initProcessEnabled: true가 포함되어야 합니다.
4. AWS EKS (Elastic Kubernetes Service)¶
4.1 EKS 클러스터 생성¶
# 1. eksctl 설치 (macOS)
brew install eksctl
# 2. 클러스터 생성
eksctl create cluster \
--name my-cluster \
--region ap-northeast-2 \
--nodegroup-name my-nodes \
--node-type t3.medium \
--nodes 2 \
--nodes-min 1 \
--nodes-max 4
# 3. kubeconfig 업데이트
aws eks update-kubeconfig --name my-cluster --region ap-northeast-2
# 4. 클러스터 확인
kubectl get nodes
4.2 EKS Auto Mode¶
EKS Auto Mode(2024년 말 출시)는 GKE Autopilot과 유사하게 노드 관리를 자동화하여 EKS 운영을 단순화합니다.
# Auto Mode로 EKS 클러스터 생성
eksctl create cluster \
--name my-auto-cluster \
--region ap-northeast-2 \
--auto-mode
# 또는 기존 클러스터에 Auto Mode 활성화
aws eks update-cluster-config \
--name my-cluster \
--compute-config enabled=true \
--kubernetes-network-config '{"elasticLoadBalancing":{"enabled":true}}' \
--storage-config '{"blockStorage":{"enabled":true}}'
| 기능 | EKS Standard | EKS Auto Mode |
|---|---|---|
| 노드 프로비저닝 | 수동 (관리형 노드 그룹 또는 Karpenter) | 자동 |
| 노드 OS 업데이트 | 사용자 관리 | AWS 관리 |
| 로드 밸런서 | AWS LB Controller 설치 필요 | 내장 |
| 스토리지(EBS CSI) | EBS CSI 드라이버 설치 필요 | 내장 |
| 과금 | EC2 인스턴스 기반 | Pod 리소스 기반 (오버헤드 포함) |
| 적합 대상 | 세밀한 제어 필요 시 | 간소화된 운영 |
4.3 애플리케이션 배포¶
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
replicas: 3
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: my-app
image: 123456789012.dkr.ecr.ap-northeast-2.amazonaws.com/my-app:latest
ports:
- containerPort: 80
resources:
requests:
memory: "128Mi"
cpu: "250m"
limits:
memory: "256Mi"
cpu: "500m"
---
apiVersion: v1
kind: Service
metadata:
name: my-app-service
spec:
type: LoadBalancer
selector:
app: my-app
ports:
- port: 80
targetPort: 80
# 배포
kubectl apply -f deployment.yaml
# 상태 확인
kubectl get pods
kubectl get services
5. GCP GKE (Google Kubernetes Engine)¶
5.1 GKE 클러스터 생성¶
# 1. GKE API 활성화
gcloud services enable container.googleapis.com
# 2. 클러스터 생성 (Autopilot - 권장)
gcloud container clusters create-auto my-cluster \
--region=asia-northeast3
# 또는 Standard 클러스터
gcloud container clusters create my-cluster \
--region=asia-northeast3 \
--num-nodes=2 \
--machine-type=e2-medium
# 3. 클러스터 인증 정보 가져오기
gcloud container clusters get-credentials my-cluster \
--region=asia-northeast3
# 4. 클러스터 확인
kubectl get nodes
5.2 GKE Autopilot 심화¶
GKE Autopilot은 Google이 노드, 스케일링, 보안을 포함한 전체 클러스터 인프라를 관리하는 완전 관리형 Kubernetes 모드입니다.
Autopilot vs Standard:
| 항목 | Autopilot | Standard |
|---|---|---|
| 노드 관리 | Google 자동 관리 | 사용자 관리 |
| 과금 | Pod 리소스 기반 | 노드 기반 |
| 보안 | 강화된 기본값 (경량화 OS, Workload Identity, Shielded GKE 노드) | 수동 구성 |
| 확장성 | 자동 HPA/VPA | 수동/자동 구성 |
| GPU 지원 | 지원 (L4, A100, H100, TPU) | 지원 |
| Spot Pod | 지원 | 지원 (선점형 노드) |
| DaemonSet | 허용 (과금 포함) | 허용 |
| 특권 Pod | 불허 | 허용 |
| 적합 대상 | 대부분의 워크로드, 비용 최적화 | 세밀한 제어, 특수 커널 요구 시 |
Autopilot 보안 기능 (기본 활성화):
- containerd 기반 Container-Optimized OS
- Workload Identity (노드 서비스 계정 키 불필요)
- Shielded GKE 노드 (보안 부팅, 무결성 모니터링)
- 네트워크 정책 적용
- Pod 보안 표준 (기본 Baseline)
- Binary Authorization 지원
# Autopilot에서 Spot Pod 배포 (최대 60-91% 비용 절감)
cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: batch-processor
spec:
replicas: 5
selector:
matchLabels:
app: batch-processor
template:
metadata:
labels:
app: batch-processor
spec:
nodeSelector:
cloud.google.com/gke-spot: "true"
terminationGracePeriodSeconds: 25
containers:
- name: worker
image: asia-northeast3-docker.pkg.dev/PROJECT_ID/my-repo/worker:latest
resources:
requests:
cpu: "500m"
memory: "1Gi"
# Autopilot에서 GPU 요청
# nvidia.com/gpu: "1"
limits:
cpu: "500m"
memory: "1Gi"
tolerations:
- key: cloud.google.com/gke-spot
operator: Equal
value: "true"
effect: NoSchedule
EOF
5.3 애플리케이션 배포¶
# deployment.yaml (GKE)
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
replicas: 3
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: my-app
image: asia-northeast3-docker.pkg.dev/PROJECT_ID/my-repo/my-app:latest
ports:
- containerPort: 80
resources:
requests:
memory: "128Mi"
cpu: "250m"
limits:
memory: "256Mi"
cpu: "500m"
---
apiVersion: v1
kind: Service
metadata:
name: my-app-service
spec:
type: LoadBalancer
selector:
app: my-app
ports:
- port: 80
targetPort: 80
kubectl apply -f deployment.yaml
kubectl get services
6. 서버리스 컨테이너¶
6.1 AWS Fargate¶
Fargate는 서버 프로비저닝 없이 컨테이너를 실행합니다.
특징: - EC2 인스턴스 관리 불필요 - 태스크 수준에서 리소스 정의 - ECS 또는 EKS와 함께 사용
# ECS + Fargate로 서비스 생성
aws ecs create-service \
--cluster my-cluster \
--service-name my-fargate-service \
--task-definition my-task:1 \
--desired-count 2 \
--launch-type FARGATE \
--platform-version LATEST \
--network-configuration "awsvpcConfiguration={subnets=[subnet-xxx],securityGroups=[sg-xxx],assignPublicIp=ENABLED}"
6.2 GCP Cloud Run¶
Cloud Run은 컨테이너를 서버리스로 실행합니다.
특징: - 완전 관리형 - 요청 기반 자동 확장 (0까지) - 사용한 만큼만 과금 - HTTP 트래픽 또는 이벤트 기반
# 1. 이미지 배포
gcloud run deploy my-service \
--image=asia-northeast3-docker.pkg.dev/PROJECT_ID/my-repo/my-app:latest \
--region=asia-northeast3 \
--platform=managed \
--allow-unauthenticated
# 2. 서비스 URL 확인
gcloud run services describe my-service \
--region=asia-northeast3 \
--format='value(status.url)'
# 3. 트래픽 분할 (Blue/Green)
gcloud run services update-traffic my-service \
--region=asia-northeast3 \
--to-revisions=my-service-00002-abc=50,my-service-00001-xyz=50
6.3 Cloud Run vs App Runner 비교¶
| 항목 | GCP Cloud Run | AWS App Runner |
|---|---|---|
| 소스 | 컨테이너 이미지, 소스 코드 | 컨테이너 이미지, 소스 코드 |
| 최대 메모리 | 32GB | 12GB |
| 최대 타임아웃 | 60분 | 30분 |
| 0으로 스케일 | 지원 | 지원 (옵션) |
| VPC 연결 | 지원 | 지원 |
| GPU | 지원 | 미지원 |
7. 서비스 선택 가이드¶
7.1 결정 트리¶
서버리스 컨테이너가 필요한가?
├── Yes → Cloud Run / Fargate / App Runner
│ └── Kubernetes 기능 필요?
│ ├── Yes → Fargate on EKS
│ └── No → Cloud Run (GCP) / Fargate on ECS (AWS)
└── No → Kubernetes가 필요한가?
├── Yes → GKE (Autopilot/Standard) / EKS
└── No → ECS on EC2 / Compute Engine + Docker
7.2 사용 사례별 권장¶
| 사용 사례 | AWS 권장 | GCP 권장 |
|---|---|---|
| 단순 웹앱 | App Runner | Cloud Run |
| 마이크로서비스 | ECS Fargate + Service Connect | Cloud Run |
| K8s (간소화) | EKS Auto Mode | GKE Autopilot |
| K8s (전체 제어) | EKS Standard | GKE Standard |
| ML/GPU 워크로드 | EKS + GPU | GKE Autopilot + GPU |
| 배치 작업 | ECS Task | Cloud Run Jobs |
| 이벤트 처리 | Fargate + EventBridge | Cloud Run + Eventarc |
| 비용 민감 배치 | Fargate Spot | Autopilot Spot Pod |
8. 과금 비교¶
8.1 ECS/EKS vs GKE¶
AWS ECS (Fargate):
vCPU: $0.04048/시간 (서울)
메모리: $0.004445/GB/시간 (서울)
예: 0.5 vCPU, 1GB, 24시간
= (0.5 × $0.04048 × 24) + (1 × $0.004445 × 24)
= $0.49 + $0.11 = $0.60/일
AWS EKS:
클러스터: $0.10/시간 ($72/월)
+ 노드 비용 (EC2) 또는 Fargate 비용
GCP GKE:
Autopilot: vCPU $0.0445/시간, 메모리 $0.0049/GB/시간
Standard: 관리 수수료 $0.10/시간/클러스터 + 노드 비용
예: Autopilot 0.5 vCPU, 1GB, 24시간
= (0.5 × $0.0445 × 24) + (1 × $0.0049 × 24)
= $0.53 + $0.12 = $0.65/일
8.2 Cloud Run 과금¶
CPU: $0.00002400/vCPU-초 (요청 처리 중)
메모리: $0.00000250/GB-초
요청: $0.40/100만 요청
무료 티어:
- 200만 요청/월
- 360,000 GB-초
- 180,000 vCPU-초
9. 실습: 간단한 웹앱 배포¶
9.1 Dockerfile 준비¶
# Dockerfile
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8080
CMD ["python", "app.py"]
# app.py
from flask import Flask
import os
app = Flask(__name__)
@app.route('/')
def hello():
return f"Hello from {os.environ.get('CLOUD_PROVIDER', 'Container')}!"
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8080)
# requirements.txt
flask==3.0.0
gunicorn==21.2.0
9.2 GCP Cloud Run 배포¶
# 빌드 및 배포 (소스에서 직접)
gcloud run deploy my-app \
--source=. \
--region=asia-northeast3 \
--allow-unauthenticated \
--set-env-vars=CLOUD_PROVIDER=GCP
9.3 AWS App Runner 배포¶
# 1. ECR에 이미지 푸시 (앞서 설명한 방법)
# 2. App Runner 서비스 생성
aws apprunner create-service \
--service-name my-app \
--source-configuration '{
"ImageRepository": {
"ImageIdentifier": "123456789012.dkr.ecr.ap-northeast-2.amazonaws.com/my-app:latest",
"ImageRepositoryType": "ECR",
"ImageConfiguration": {
"Port": "8080",
"RuntimeEnvironmentVariables": {
"CLOUD_PROVIDER": "AWS"
}
}
},
"AuthenticationConfiguration": {
"AccessRoleArn": "arn:aws:iam::123456789012:role/AppRunnerECRAccessRole"
}
}'
10. 다음 단계¶
- 07_Object_Storage.md - 객체 스토리지
- 09_Virtual_Private_Cloud.md - VPC 네트워킹