Claude Code × AWS ECS/Fargate 완전 가이드 | 컨테이너 배포 자동화하기
Claude Code로 AWS ECS/Fargate 배포를 자동화하세요. 태스크 정의부터 서비스 설정, Blue/Green 배포, CDK 인프라 구축까지 — Masa의 실무 경험을 바탕으로 해설합니다.
“AWS에서 컨테이너를 실행하고 싶은데, ECS 설정이 너무 복잡하다” — 이것은 많은 개발자가 처음 마주치는 벽입니다. 태스크 정의, 서비스, 클러스터, 로드 밸런서, 오토 스케일링… 설정 항목이 너무 많아서 어디서부터 손을 대야 할지 모릅니다.
저는 업무에서 ECS/Fargate를 사용한 서버리스 컨테이너 환경을 구축하고 있는데, Claude Code에 구성을 전달하는 것만으로 태스크 정의부터 CDK 코드까지 일괄 생성할 수 있게 된 이후로 배포 작업이 훨씬 편해졌습니다. 이 글에서는 그 실전 절차를 해설합니다.
ECS/Fargate 기초를 3분 만에 정리
클러스터: ECS 컨테이너가 동작하는 "박스"
태스크 정의: 컨테이너의 설정 명세서 (이미지, CPU, 메모리, 환경 변수)
서비스: 태스크를 몇 대 기동할지의 설정 (오토 스케일링 포함)
Fargate: 서버 관리가 필요 없는 컨테이너 실행 엔진
EC2와 달리, Fargate는 서버 프로비저닝·패치 적용이 필요 없습니다. 컨테이너 설정에만 집중할 수 있습니다.
Step 1: 태스크 정의 자동 생성
claude -p "
다음 조건으로 ECS 태스크 정의를 JSON으로 생성해줘.
- 앱: Node.js API (포트 3000)
- CPU: 512 (0.5 vCPU)
- 메모리: 1024 MB
- 환경 변수: DATABASE_URL (Secrets Manager에서 취득), NODE_ENV=production
- 로그: CloudWatch Logs (로그 그룹 /ecs/myapp)
- 헬스 체크: /health 엔드포인트, 30초 간격
- 컨테이너 이미지: 123456789.dkr.ecr.ap-northeast-1.amazonaws.com/myapp:latest
- 실행 롤: ecsTaskExecutionRole
- 태스크 롤: myapp-task-role (DynamoDB·S3 접근 권한)
"
생성되는 태스크 정의:
{
"family": "myapp-task",
"networkMode": "awsvpc",
"requiresCompatibilities": ["FARGATE"],
"cpu": "512",
"memory": "1024",
"executionRoleArn": "arn:aws:iam::123456789:role/ecsTaskExecutionRole",
"taskRoleArn": "arn:aws:iam::123456789:role/myapp-task-role",
"containerDefinitions": [
{
"name": "myapp",
"image": "123456789.dkr.ecr.ap-northeast-1.amazonaws.com/myapp:latest",
"portMappings": [{ "containerPort": 3000, "protocol": "tcp" }],
"environment": [{ "name": "NODE_ENV", "value": "production" }],
"secrets": [
{
"name": "DATABASE_URL",
"valueFrom": "arn:aws:secretsmanager:ap-northeast-1:123456789:secret:prod/database-url"
}
],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/ecs/myapp",
"awslogs-region": "ap-northeast-1",
"awslogs-stream-prefix": "ecs"
}
},
"healthCheck": {
"command": ["CMD-SHELL", "curl -f http://localhost:3000/health || exit 1"],
"interval": 30,
"timeout": 5,
"retries": 3,
"startPeriod": 60
}
}
]
}
Step 2: CDK로 ECS/Fargate 환경 구축
태스크 정의뿐만 아니라, 클러스터·서비스·ALB까지 CDK로 한 번에 생성합니다.
claude -p "
lib/ecs-stack.ts에 다음 ECS/Fargate 환경을 CDK TypeScript로 구현해줘.
- VPC: 기존 VPC import (vpcId를 환경 변수에서 취득)
- ECS 클러스터: Fargate만
- 태스크 정의: 위에서 생성한 것과 동일한 사양
- ALB: HTTPS (ACM 인증서 ARN을 환경 변수에서 취득), HTTP는 301 리다이렉트
- 서비스: 최소 2대, 최대 10대의 오토 스케일링
- CPU 사용률 70%에서 스케일 아웃
- 대상 추적 스케일링
- Blue/Green 배포 대응 (CodeDeploy 연계)
- CloudWatch 대시보드에 서비스 가동 상태 표시
"
// lib/ecs-stack.ts
import * as cdk from "aws-cdk-lib";
import * as ec2 from "aws-cdk-lib/aws-ec2";
import * as ecs from "aws-cdk-lib/aws-ecs";
import * as ecsp from "aws-cdk-lib/aws-ecs-patterns";
import * as acm from "aws-cdk-lib/aws-certificatemanager";
export class EcsStack extends cdk.Stack {
constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// 기존 VPC import
const vpc = ec2.Vpc.fromLookup(this, "Vpc", {
vpcId: process.env.VPC_ID!,
});
// ECS 클러스터
const cluster = new ecs.Cluster(this, "Cluster", {
vpc,
clusterName: "myapp-cluster",
containerInsights: true, // CloudWatch Container Insights 활성화
});
// ACM 인증서
const certificate = acm.Certificate.fromCertificateArn(
this, "Certificate",
process.env.CERTIFICATE_ARN!
);
// 태스크 정의
const taskDef = new ecs.FargateTaskDefinition(this, "TaskDef", {
cpu: 512,
memoryLimitMiB: 1024,
});
const container = taskDef.addContainer("app", {
image: ecs.ContainerImage.fromEcrRepository(
ecr.Repository.fromRepositoryName(this, "Repo", "myapp")
),
environment: { NODE_ENV: "production" },
logging: ecs.LogDrivers.awsLogs({ streamPrefix: "ecs" }),
healthCheck: {
command: ["CMD-SHELL", "curl -f http://localhost:3000/health || exit 1"],
interval: cdk.Duration.seconds(30),
timeout: cdk.Duration.seconds(5),
retries: 3,
startPeriod: cdk.Duration.seconds(60),
},
});
container.addPortMappings({ containerPort: 3000 });
// ALB + Fargate 서비스 (패턴으로 간결하게)
const service = new ecsp.ApplicationLoadBalancedFargateService(
this, "Service", {
cluster,
taskDefinition: taskDef,
desiredCount: 2,
certificate,
redirectHTTP: true,
publicLoadBalancer: true,
}
);
// 오토 스케일링 설정
const scaling = service.service.autoScaleTaskCount({
minCapacity: 2,
maxCapacity: 10,
});
scaling.scaleOnCpuUtilization("CpuScaling", {
targetUtilizationPercent: 70,
scaleInCooldown: cdk.Duration.seconds(60),
scaleOutCooldown: cdk.Duration.seconds(60),
});
// Output
new cdk.CfnOutput(this, "LoadBalancerDns", {
value: service.loadBalancer.loadBalancerDnsName,
});
}
}
Step 3: GitHub Actions로 CI/CD 파이프라인 구축
claude -p "
GitHub Actions로 다음 CI/CD 파이프라인을 만들어줘:
1. main 브랜치로의 push를 트리거
2. Docker 이미지를 빌드하여 ECR에 푸시
3. ECS 태스크 정의의 image 태그를 새로운 SHA로 업데이트
4. ECS 서비스에 새로운 태스크 정의를 배포
5. 배포 완료를 Slack에 알림
환경: ap-northeast-1, ECR 리포지토리명: myapp
"
name: Deploy to ECS
on:
push:
branches: [main]
env:
AWS_REGION: ap-northeast-1
ECR_REPOSITORY: myapp
ECS_CLUSTER: myapp-cluster
ECS_SERVICE: myapp-service
CONTAINER_NAME: app
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ env.AWS_REGION }}
- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v2
- name: Build, tag, and push image to ECR
id: build-image
env:
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
IMAGE_TAG: ${{ github.sha }}
run: |
docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
echo "image=$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG" >> $GITHUB_OUTPUT
- name: Download task definition
run: |
aws ecs describe-task-definition --task-definition myapp-task \
--query taskDefinition > task-definition.json
- name: Update ECS task definition with new image
id: task-def
uses: aws-actions/amazon-ecs-render-task-definition@v1
with:
task-definition: task-definition.json
container-name: ${{ env.CONTAINER_NAME }}
image: ${{ steps.build-image.outputs.image }}
- name: Deploy to ECS
uses: aws-actions/amazon-ecs-deploy-task-definition@v1
with:
task-definition: ${{ steps.task-def.outputs.task-definition }}
service: ${{ env.ECS_SERVICE }}
cluster: ${{ env.ECS_CLUSTER }}
wait-for-service-stability: true
- name: Notify Slack on success
if: success()
uses: slackapi/slack-github-action@v1
with:
webhook: ${{ secrets.SLACK_WEBHOOK }}
payload: |
{"text": "✅ Deployed to ECS: ${{ github.sha }}"}
Step 4: Blue/Green 배포 설정
claude -p "
ECS 서비스에서 Blue/Green 배포 (CodeDeploy)를 설정하기 위한
CDK 코드와 AppSpec 파일을 생성해줘.
롤백 조건: 배포 후 5분 이내에 CloudWatch 알람이 발생하면 자동 롤백
"
# appspec.yaml (CodeDeploy용)
version: 0.0
Resources:
- TargetService:
Type: AWS::ECS::Service
Properties:
TaskDefinition: <TASK_DEFINITION>
LoadBalancerInfo:
ContainerName: app
ContainerPort: 3000
PlatformVersion: LATEST
Hooks:
- BeforeAllowTraffic: "arn:aws:lambda:ap-northeast-1:123456789:function:health-check"
- AfterAllowTraffic: "arn:aws:lambda:ap-northeast-1:123456789:function:smoke-test"
함정 5가지
1. 헬스 체크의 startPeriod를 깜빡하기
Fargate 컨테이너는 시작 직후에 헬스 체크가 실행되지만, 앱의 기동이 느리면 즉시 UNHEALTHY가 됩니다. startPeriod: 60 (초)를 설정하여 앱의 기동 시간을 확보합시다.
2. 태스크 롤과 실행 롤을 혼동하기
executionRole (ecsTaskExecutionRole): 컨테이너 기동에 필요한 권한
→ ECR에서 이미지 pull, CloudWatch Logs에 쓰기
taskRole (myapp-task-role): 앱이 사용하는 권한
→ DynamoDB, S3, SQS 등으로의 접근
어느 롤에 무엇을 추가할지 자주 틀립니다.
3. awsvpc 네트워크 모드에서의 보안 그룹 설정
Fargate는 반드시 awsvpc 네트워크 모드가 필요합니다. 컨테이너의 보안 그룹을 ALB에서만으로 제한하는 것을 잊으면, 컨테이너가 직접 외부에 공개됩니다.
4. Secrets Manager 취득에 실행 롤이 필요
secrets로 Secrets Manager의 값을 취득하려면 executionRole에 secretsmanager:GetSecretValue 권한이 필요합니다. 누락되면 컨테이너가 기동하지 않는 경우가 많습니다.
5. 배포 시의 desired_count: 0 문제
오토 스케일링에서 최솟값이 0인 서비스는 심야에 모든 컨테이너가 꺼져서 아침의 기동이 느려집니다. 최솟값은 프로덕션에서 최소 2대로 설정합시다.
정리
| 태스크 | Claude Code의 기여 |
|---|---|
| 태스크 정의 생성 | 요건을 전달하기만 해도 JSON 완성 |
| CDK 구현 | 클러스터·서비스·ALB·오토 스케일링 일괄 생성 |
| CI/CD 설정 | GitHub Actions 워크플로우 생성 |
| Blue/Green 배포 | AppSpec·CodeDeploy 설정을 자동 생성 |
| 트러블 해결 | 에러 로그에서 원인과 수정 방법을 제시 |
ECS는 설정 항목이 많지만, Claude Code에 “이런 구성이 필요하다”고 전달하기만 하면 베스트 프랙티스에 맞는 설정이 일식으로 갖춰집니다. 우선 CDK부터 시작하는 것이 가장 편하고 추천합니다.
관련 기사
- Claude Code × AWS Lambda 완전 가이드
- Claude Code × AWS IAM 완전 가이드
- Claude Code × AWS CloudFormation/CDK 완전 가이드
참고 자료
Claude Code 워크플로우를 한 단계 업그레이드하세요
지금 바로 Claude Code에 복사해 쓸 수 있는 검증된 프롬프트 템플릿 50선.
무료 PDF: 5분 완성 Claude Code 치트시트
이메일 주소만 등록하시면 A4 한 장짜리 치트시트 PDF를 즉시 보내드립니다.
개인정보는 엄격하게 관리하며 스팸은 보내지 않습니다.
이 글을 작성한 사람
Masa
Claude Code를 적극 활용하는 엔지니어. 10개 언어, 2,000페이지 이상의 테크 미디어 claudecode-lab.com을 운영 중.
관련 글
Claude Code × Amazon Bedrock 완전 가이드 | AWS에서 Claude 프로덕션 운영하기
Claude Code로 Amazon Bedrock을 활용하는 완전 가이드. IAM 인증, 스트리밍, Lambda 통합, RAG 구현, 비용 최적화까지 — Masa의 실제 프로덕션 구현 경험을 바탕으로 해설.
Claude Code × AWS CodePipeline/CodeBuild 완전 가이드 | CI/CD 파이프라인 자동 구축
Claude Code로 AWS CodePipeline·CodeBuild CI/CD를 자동 구축. 파이프라인 설계·buildspec.yml 생성·테스트 자동화·CDK 인프라 정의까지 실전 코드로 해설.
Claude Code × AWS CloudWatch 완벽 가이드 | 로그 분석·알람 설정·대시보드 자동 구축
Claude Code로 AWS CloudWatch를 효율화하세요. 로그 패턴 분석·알람 자동 설정·메트릭 대시보드 구축·인시던트 조사까지 실전 코드로 해설합니다.