CI/CD: CodeDeploy
5. AWS CodeDeploy
🤔 CodeDeploy가 뭔가요?
비유로 이해하기: CodeDeploy는 배포 자동화 로봇입니다.
- EC2, Lambda, ECS에 자동 배포
- 점진적 배포 (Canary, Linear)
- 실패 시 자동 롤백
CodeDeploy 지원 플랫폼
| 플랫폼 | 배포 방식 | Agent 필요 |
|---|---|---|
| EC2/On-premises | In-place, Blue/Green | ✅ |
| Lambda | Blue/Green (Alias) | ❌ |
| ECS | Blue/Green (Task Definition) | ❌ |
EC2 In-place 배포
┌─────────────────────────────────────────────────────────────────┐
│ In-place Deployment │
│ │
│ 기존 인스턴스에서 애플리케이션 업데이트 │
│ │
│ 초기 상태: │
│ [v1] [v1] [v1] [v1] │
│ │
│ HalfAtATime (절반씩): │
│ [v2] [v2] [v1] [v1] → [v2] [v2] [v2] [v2] │
│ ↑ ↑ ↑ ↑ │
│ 업데이트 중 완료 │
│ │
│ 배포 속도 옵션: │
│ • AllAtOnce: 모두 동시 (다운타임 최대) │
│ • HalfAtATime: 절반씩 (50% 용량 유지) │
│ • OneAtATime: 하나씩 (가장 느림, 가장 안전) │
│ • Custom: 사용자 정의 % │
│ │
└─────────────────────────────────────────────────────────────────┘EC2 Blue/Green 배포
┌─────────────────────────────────────────────────────────────────┐
│ Blue/Green Deployment │
│ │
│ 새 인스턴스 그룹(Green) 생성 후 트래픽 전환 │
│ │
│ Step 1: 초기 상태 │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ ALB │ │
│ │ │ │ │
│ │ ↓ 100% │ │
│ │ ┌───────────┐ │ │
│ │ │ ASG Blue │ [v1] [v1] [v1] │ │
│ │ └───────────┘ │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ Step 2: Green 그룹 생성 + 배포 │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ ALB │ │
│ │ │ │ │
│ │ ↓ 100% │ │
│ │ ┌───────────┐ │ │
│ │ │ ASG Blue │ [v1] [v1] [v1] │ │
│ │ └───────────┘ │ │
│ │ ┌───────────┐ │ │
│ │ │ ASG Green │ [v2] [v2] [v2] ← 새로 생성 │ │
│ │ └───────────┘ │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ Step 3: 트래픽 전환 │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ ALB │ │
│ │ │ │ │
│ │ ↓ 100% │ │
│ │ ┌───────────┐ │ │
│ │ │ ASG Green │ [v2] [v2] [v2] │ │
│ │ └───────────┘ │ │
│ │ ┌───────────┐ │ │
│ │ │ ASG Blue │ [v1] [v1] [v1] ← 삭제 또는 유지 │ │
│ │ └───────────┘ │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ ⚠️ Blue/Green에는 Load Balancer 필수! │
│ │
└─────────────────────────────────────────────────────────────────┘Blue/Green 프로비저닝 모드
┌─────────────────────────────────────────────────────────────────┐
│ 프로비저닝 모드 │
│ │
│ 1️⃣ 수동(Manual) 모드: │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ • Blue/Green 인스턴스를 태그로 식별 │ │
│ │ • v1, v2 인스턴스를 수동으로 미리 프로비저닝 │ │
│ │ • 트래픽을 한 번에 또는 점진적으로 v2로 이동 │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ 2️⃣ 자동(Automatic) 모드 - ASG 사용: │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ • 기존 ASG를 참조하기만 하면 됨 │ │
│ │ • CodeDeploy가 자동으로 새 ASG 생성 │ │
│ │ • 동일한 설정, 동일한 용량 복사 │ │
│ │ • 새 ASG에 새 인스턴스 추가되면 ALB가 v1→v2 리디렉션 │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ 💡 자동 모드가 더 편리하고 권장됨! │
│ │
└─────────────────────────────────────────────────────────────────┘Blue 인스턴스 종료 옵션
┌─────────────────────────────────────────────────────────────────┐
│ 인스턴스 종료 옵션 │
│ │
│ 배포 완료 후 Blue(v1) 인스턴스 처리 방법: │
│ │
│ 1️⃣ 자동 종료 (대기 시간 설정): │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ • 종료 대기 시간 설정 가능 (최대 2일) │ │
│ │ • 대기 시간 동안 문제 발견 시 롤백 가능 │ │
│ │ • 대기 시간 경과 후 Blue 인스턴스 자동 종료 │ │
│ │ │ │
│ │ 예: 1시간 설정 → 1시간 동안 모니터링 후 종료 │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ 2️⃣ 인스턴스 유지 (Keep Alive): │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ • 가장 안전하지만 가장 비용이 많이 드는 옵션 │ │
│ │ • 인스턴스가 자동 종료되지 않음 │ │
│ │ • 직접 수동으로 종료해야 함 │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘Blue/Green Hook 실행 순서
┌─────────────────────────────────────────────────────────────────┐
│ Blue/Green Hook 실행 순서 │
│ │
│ 💡 In-place와 Hook은 동일하지만 실행 순서와 위치가 다름! │
│ │
│ 🟢 Green(v2) 인스턴스에서 실행: │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 1. ApplicationStop │ │
│ │ 2. BeforeInstall │ │
│ │ 3. Install ← CodeDeploy 예약 │ │
│ │ 4. AfterInstall │ │
│ │ 5. ApplicationStart │ │
│ │ 6. ValidateService │ │
│ │ 7. BeforeAllowTraffic │ │
│ │ 8. AllowTraffic ← CodeDeploy 예약 (ELB → v2 트래픽) │ │
│ │ 9. AfterAllowTraffic │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ 🔵 Blue(v1) 인스턴스에서 실행: │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 1. BeforeBlockTraffic │ │
│ │ 2. BlockTraffic ← CodeDeploy 예약 (ELB에서 v1 제거) │ │
│ │ 3. AfterBlockTraffic │ │
│ │ │ │
│ │ ⚠️ 이후 인스턴스 종료되므로 나머지 Hook 실행 안 함! │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ 흐름: │
│ v2에 앱 설치 → v2로 트래픽 허용 → v1에서 트래픽 차단 → v1 종료│
│ │
└─────────────────────────────────────────────────────────────────┘배포 구성 (Deployment Configuration)
| 구성 | 설명 | 가동 중단 시간 |
|---|---|---|
| AllAtOnce | 한 번에 최대한 많은 인스턴스에 배포 | 최대 |
| HalfAtATime | 한 번에 절반의 인스턴스에 배포 | 중간 |
| OneAtATime | 한 번에 하나씩 배포 | 최소 |
| Custom | 사용자 정의 배포 비율 설정 | 설정에 따름 |
SNS 알림
┌─────────────────────────────────────────────────────────────────┐
│ CodeDeploy SNS 알림 │
│ │
│ CodeDeploy가 배포 이벤트를 SNS 주제로 전송 가능 │
│ │
│ CodeDeploy ──event──→ SNS Topic ──→ Email/Lambda/etc. │
│ │
│ 전송 가능한 이벤트: │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ • DeploymentSuccess: 배포 성공 │ │
│ │ • DeploymentFailure: 배포 실패 │ │
│ │ • InstanceFailure: 개별 인스턴스 배포 실패 │ │
│ │ • DeploymentStart: 배포 시작 │ │
│ │ • DeploymentStop: 배포 중단 │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ 사용 예: │
│ 인스턴스 1개 실패 → InstanceFailure → SNS → 이메일 알림 │
│ │
└─────────────────────────────────────────────────────────────────┘CodeDeploy Agent
EC2/On-premises에서 필요:
• EC2 인스턴스에 설치되어야 함
• Systems Manager로 자동 설치/업데이트 가능
• S3에서 배포 번들 다운로드 권한 필요 (IAM)
EC2 Instance Profile:
{
"Effect": "Allow",
"Action": [
"s3:Get*",
"s3:List*"
],
"Resource": [
"arn:aws:s3:::bucket-name/*"
]
}appspec.yml (EC2/On-premises)
# appspec.yml
version: 0.0
os: linux
files:
- source: /
destination: /var/www/html
hooks:
BeforeInstall:
- location: scripts/before_install.sh
timeout: 300
runas: root
AfterInstall:
- location: scripts/after_install.sh
timeout: 300
runas: root
ApplicationStart:
- location: scripts/start_server.sh
timeout: 300
runas: root
ValidateService:
- location: scripts/validate_service.sh
timeout: 300
runas: rootEC2 Deployment Hooks
┌─────────────────────────────────────────────────────────────────┐
│ Deployment Hooks 순서 │
│ │
│ 로드밸런서 사용 시: │
│ │
│ Start │
│ ↓ │
│ BeforeBlockTraffic ← 스크립트 실행 가능 │
│ ↓ │
│ BlockTraffic (LB에서 트래픽 차단) ← CodeDeploy 예약 │
│ ↓ │
│ AfterBlockTraffic ← 스크립트 실행 가능 │
│ ↓ │
│ ApplicationStop ← 스크립트 실행 가능 │
│ ↓ │
│ DownloadBundle ← CodeDeploy 예약 │
│ ↓ │
│ BeforeInstall ← 스크립트 실행 가능 (파일 복호화, 백업) │
│ ↓ │
│ Install ← CodeDeploy 예약 │
│ ↓ │
│ AfterInstall ← 스크립트 실행 가능 (설정, 권한 변경) │
│ ↓ │
│ ApplicationStart ← 스크립트 실행 가능 (서비스 시작) │
│ ↓ │
│ ValidateService ← 스크립트 실행 가능 (헬스체크) │
│ ↓ │
│ BeforeAllowTraffic ← 스크립트 실행 가능 │
│ ↓ │
│ AllowTraffic (LB에서 트래픽 허용) ← CodeDeploy 예약 │
│ ↓ │
│ AfterAllowTraffic ← 스크립트 실행 가능 │
│ ↓ │
│ End │
│ │
└─────────────────────────────────────────────────────────────────┘Hook 실행 주체 구분
┌─────────────────────────────────────────────────────────────────┐
│ Hook 실행 주체 │
│ │
│ 🔷 CodeDeploy 예약 단계 (사용자 스크립트 실행 불가): │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ • BlockTraffic: LB에서 트래픽 차단 │ │
│ │ • DownloadBundle: S3에서 애플리케이션 번들 다운로드 │ │
│ │ • Install: 파일 복사 및 설치 │ │
│ │ • AllowTraffic: LB로부터 트래픽 허용 │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ 🔶 사용자 스크립트 실행 가능 단계: │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ • BeforeBlockTraffic, AfterBlockTraffic │ │
│ │ • ApplicationStop │ │
│ │ • BeforeInstall, AfterInstall │ │
│ │ • ApplicationStart │ │
│ │ • ValidateService │ │
│ │ • BeforeAllowTraffic, AfterAllowTraffic │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ 💡 로드 밸런서 사용 시 흐름: │
│ 트래픽 차단 → 번들 다운로드/설치 → 트래픽 허용 │
│ │
└─────────────────────────────────────────────────────────────────┘CodeDeploy Agent의 스크립트 실행 방식
┌─────────────────────────────────────────────────────────────────┐
│ 스크립트 실행 흐름 │
│ │
│ 1. CodeDeploy Agent가 배포 번들 다운로드 │
│ (appspec.yml + 스크립트 파일 포함) │
│ │
│ 2. appspec.yml의 hooks 섹션 읽기 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ hooks: │ │
│ │ AfterInstall: │ │
│ │ - location: scripts/RunResourceTests.sh │ │
│ │ timeout: 300 │ │
│ │ runas: root │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 3. 해당 단계에서 지정된 스크립트 실행 │
│ 예: AfterInstall 단계 → RunResourceTests.sh 실행 │
│ │
│ 4. 스크립트 결과에 따라 배포 성공/실패 결정 │
│ │
└─────────────────────────────────────────────────────────────────┘CodeDeploy 환경 변수
┌─────────────────────────────────────────────────────────────────┐
│ 스크립트에서 사용 가능한 환경 변수 │
│ │
│ CodeDeploy Agent가 스크립트 실행 시 환경 변수 주입: │
│ │
│ 변수명 │ 설명 │
│ ─────────────────────────────┼────────────────────────────────│
│ DEPLOYMENT_ID │ 배포 ID │
│ DEPLOYMENT_GROUP_NAME │ 배포 그룹 이름 │
│ DEPLOYMENT_GROUP_ID │ 배포 그룹 ID │
│ APPLICATION_NAME │ 애플리케이션 이름 │
│ LIFECYCLE_EVENT │ 현재 실행 중인 후크 이름 │
│ │
│ 스크립트 예시: │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ #!/bin/bash │ │
│ │ echo "배포 그룹: $DEPLOYMENT_GROUP_NAME" │ │
│ │ echo "배포 ID: $DEPLOYMENT_ID" │ │
│ │ │ │
│ │ if [ "$DEPLOYMENT_GROUP_NAME" == "Production" ]; then │ │
│ │ # 프로덕션 전용 작업 │ │
│ │ fi │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘Hook별 사용 목적
| Hook | 주요 용도 |
|---|---|
| BeforeInstall | 파일 복호화, 구 버전 백업 생성 |
| AfterInstall | 애플리케이션 설정, 파일 권한 변경 |
| ApplicationStart | ApplicationStop에서 중단된 서비스 재시작 |
| ValidateService | 배포 성공 여부 확인 (헬스체크, 테스트) |
| BeforeAllowTraffic | LB 트래픽 수신 전 최종 상태 확인 (헬스체크) |
Lambda 배포
┌─────────────────────────────────────────────────────────────────┐
│ Lambda Deployment │
│ │
│ CodeDeploy가 Lambda Alias의 트래픽을 점진적으로 전환 │
│ │
│ Lambda Function │
│ ├── Version 1 (현재) │
│ ├── Version 2 (새로운) │
│ └── Prod Alias → Version 1 (100%) + Version 2 (0%) │
│ │
│ 배포 진행: │
│ V1: 100% → 90% → 80% → ... → 0% │
│ V2: 0% → 10% → 20% → ... → 100% │
│ │
│ 배포 옵션: │
│ • LambdaCanary10Percent5Minutes │
│ → 10% 전환, 5분 대기, 문제 없으면 100% │
│ • LambdaLinear10PercentEvery3Minutes │
│ → 3분마다 10%씩 증가 │
│ • LambdaAllAtOnce │
│ → 즉시 100% 전환 │
│ │
│ ⚠️ CodeDeploy Agent 불필요! │
│ │
└─────────────────────────────────────────────────────────────────┘appspec.yml (Lambda)
# appspec.yml for Lambda
version: 0.0
Resources:
- MyLambdaFunction:
Type: AWS::Lambda::Function
Properties:
Name: "my-function"
Alias: "prod"
CurrentVersion: "1"
TargetVersion: "2"
Hooks:
- BeforeAllowTraffic: "CodeDeployHook_BeforeAllowTraffic"
- AfterAllowTraffic: "CodeDeployHook_AfterAllowTraffic"ECS 배포
┌─────────────────────────────────────────────────────────────────┐
│ ECS Deployment (Blue/Green) │
│ │
│ 새 Task Definition으로 새 Task Set 생성 후 트래픽 전환 │
│ │
│ ALB │
│ │ │
│ ┌──────┴──────┐ │
│ ↓ ↓ │
│ Target Group Target Group │
│ (Blue) (Green) │
│ │ │ │
│ ↓ ↓ │
│ [v1][v1] [v2][v2] │
│ │
│ 100% - X% X% → X가 점진적으로 100%까지 │
│ │
│ 배포 옵션: │
│ • ECSCanary10Percent5Minutes │
│ • ECSLinear10PercentEvery3Minutes │
│ • ECSAllAtOnce │
│ │
│ ⚠️ ALB 필수! │
│ ⚠️ CodeDeploy Agent 불필요! │
│ ⚠️ Task Definition + Container Image 미리 생성 필요 │
│ │
└─────────────────────────────────────────────────────────────────┘Rollback
롤백 조건:
• 배포 실패 시 자동 롤백
• CloudWatch Alarm 임계값 초과 시 자동 롤백
• 수동 롤백
롤백 동작:
• 이전 버전을 "새 배포"로 다시 배포
• 이전 버전으로 "복원"하는 게 아님!CodeDeploy 트러블슈팅
┌─────────────────────────────────────────────────────────────────┐
│ CodeDeploy 트러블슈팅 │
│ │
│ 1. InvalidSignatureException │
│ 원인: EC2 시간이 맞지 않음 │
│ 해결: NTP로 시간 동기화 │
│ │
│ 2. "Too few healthy instances" │
│ 원인: │
│ • CodeDeploy Agent 미설치/미실행 │
│ • IAM 권한 부족 │
│ • HTTP Proxy 설정 필요 │
│ • 시간 동기화 문제 │
│ │
│ 3. ASG 스케일아웃 중 배포 │
│ 문제: 새 인스턴스에 이전 버전 배포됨 │
│ 해결: CodeDeploy가 자동으로 follow-on 배포 실행 │
│ │
│ 4. AllowTraffic 실패 (에러 로그 없음) │
│ 원인: ELB 헬스체크 설정 오류 │
│ 해결: 헬스체크 경로/포트 확인 │
│ │
└─────────────────────────────────────────────────────────────────┘