Need U V1 : CD 파이프라인 설계 - 100-hours-a-week/KTB4-4th-wiki GitHub Wiki
- 설계 목적
- V1 배포 구조와 CD 대상
- CD 방식 및 Trigger 정책
- 공통 배포 원칙
- Backend CD
- AI Server CD
- Frontend CD
- Artifact 및 ECR 관리
- Application Secret 관리
- 배포 전략
- Health Check 및 Rollback
- Monitoring
- 배포 보안
- 동시 배포 방지
- 전체 CD Pipeline
- CI / CD 경계
- V1 최종 기준
Need U는 CI를 통해 Frontend, Backend, AI Server의 코드를 검증하고 배포 Artifact를 생성한다.
CI 성공만으로 Production 배포가 완료되는 것은 아니다.
CI
↓
배포 가능한 Artifact 생성
↓
배포 버전 선택
↓
Production 반영
↓
Health Check
↓
실패 시 Rollback
V1 CD의 목적은 CI에서 검증한 Artifact를 동일한 절차로 운영 환경에 반영하고, 배포 실패 시 직전 정상 버전으로 복구할 수 있도록 하는 것이다.
수동으로 EC2에 접속해 배포하면 다음 문제가 발생할 수 있다.
- 잘못된 버전 배포
- 담당자마다 다른 배포 절차
- 환경 설정 누락
- Rollback 지연
- 현재 운영 버전 추적 어려움
따라서 GitHub Actions, AWS OIDC, SSM Run Command, Docker Compose를 이용해 배포 절차를 표준화한다.
V1 Production 구조는 다음과 같다.
EC2 t3.medium
├─ Nginx
│ ├─ / → React/Vite 정적 파일
│ └─ /api → Spring Boot Backend
│
├─ Docker Compose
│ ├─ Backend (Spring Boot)
│ ├─ AI Server (FastAPI)
│ └─ Redis
│
├─ MySQL
└─ PostgreSQL + pgvector
CD 관점에서는 세 개의 배포 단위를 구분한다.
| 구분 | Artifact | 저장 위치 | Production 반영 방식 |
|---|---|---|---|
| Frontend | Vite dist/
|
GitHub Actions Artifact | Host Nginx 정적 파일 교체 |
| Backend | Docker Image | Amazon ECR | Docker Compose Service 교체 |
| AI Server | Docker Image | Amazon ECR | Docker Compose Service 교체 |
Redis, MySQL, PostgreSQL + pgvector는 Application 배포 시 매번 교체하지 않는다.
Application 배포
├─ Frontend → 필요 시 교체
├─ Backend → 필요 시 교체
└─ AI Server → 필요 시 교체
유지
├─ Redis
├─ MySQL
├─ PostgreSQL + pgvector
└─ Nginx
Backend와 AI Server는 각각 독립적인 Docker Image로 관리하며, 각 Repository의 Git Commit SHA를 Image Tag로 사용한다.
Backend → needu-backend:<Backend Commit SHA>
AI Server → needu-ai:<AI Commit SHA>
Need U V1은 Continuous Delivery 방식을 사용한다.
| 구분 | Continuous Delivery | Continuous Deployment |
|---|---|---|
| CI | 자동 | 자동 |
| Artifact 생성 | 자동 | 자동 |
| Production 배포 | 담당자가 실행 | 자동 |
| V1 적용 | O | X |
V1에서는 main Merge와 Production 배포를 분리한다.
main CI 성공
↓
Artifact 생성
↓
배포 가능 상태
↓
담당자 배포 결정
↓
workflow_dispatch
↓
Production
즉:
main Merge ≠ Production Deploy
- V1 예상 Peak Traffic은 약
0.16 RPS로 낮다. - 계획 배포는 주 2회, 사용자 활동이 적은 새벽 시간대를 기본으로 한다.
- V1은 Recreate 방식의 중단 배포를 사용한다.
- Merge 시점과 실제 서비스 중단 시점을 분리해야 한다.
- 배포 빈도가 높지 않아 완전 자동 Production 배포의 이점이 크지 않다.
Frontend, Backend, AI Server CD 모두 수동 Trigger를 사용한다.
on:
workflow_dispatch:각 Repository에서 자신이 배포할 버전을 입력받는다.
Frontend CD
→ commit_sha = Frontend Commit SHA
Backend CD
→ image_tag = Backend Commit SHA
AI CD
→ image_tag = AI Commit SHA
- 해당 Commit의
mainCI 성공 -
needu-frontend-<SHA>Artifact 존재 - Playwright E2E 성공
- 배포할 Commit SHA 확인
- 해당 Commit의
mainCI 성공 -
needu-backend:<SHA>Image가 ECR에 존재 - 배포할 Commit SHA 확인
- 해당 Commit의
mainCI 성공 -
needu-ai:<SHA>Image가 ECR에 존재 - Docker Build Check 성공
- 배포할 Commit SHA 확인
Redis / PostgreSQL + pgvector Integration Test는 현재 필수 배포 조건에 포함하지 않는다. 관련 Adapter와 Test가 구현되어 CI release-check에 추가되면 이후 배포 조건에도 반영한다.
공통적으로 계획된 배포 시간인지 확인한 뒤 Production CD를 실행한다.
Production EC2에서 Source Code를 다시 Build하지 않는다.
CI
↓
검증된 Artifact 생성
↓
Artifact 저장
↓
CD
↓
동일 Artifact Production 배포
Backend와 AI Server는 CI에서 만든 Docker Image를 ECR에 저장하고 CD에서 그대로 Pull한다.
Frontend도 CI에서 생성한 dist/를 그대로 배포한다.
배포 버전은 Git Commit SHA로 식별한다.
Frontend
needu-frontend-93fbc21
Backend
needu-backend:a82f3c1
AI Server
needu-ai:7e42c91
latest는 사용하지 않는다.
GitHub Actions에서 EC2에 직접 SSH 접속하지 않는다.
GitHub Actions
↓
AWS OIDC
↓
IAM Role
↓
SSM Run Command
↓
EC2 Deploy Script
SSM은 배포 명령을 EC2에 전달하는 수단으로 사용한다.
Backend를 배포할 때 AI Server나 Redis를 함께 재시작하지 않는다.
AI Server를 배포할 때 Backend나 Redis를 함께 재시작하지 않는다.
Backend 배포
→ Backend만 교체
AI 배포
→ AI Server만 교체
Frontend 배포
→ dist만 교체
Application 간 불필요한 영향 범위를 줄이기 위한 정책이다.
Backend는 Spring Boot Docker Image를 ECR에서 Pull하여 Docker Compose Service를 교체한다.
수동 CD 실행
↓
배포할 Backend SHA 입력
↓
ECR Image 존재 확인
↓
SSM Run Command
↓
기존 정상 Backend Tag 기록
↓
신규 Image Pull
↓
Backend Service 교체
↓
Health Check
성공:
Health Check 성공
↓
신규 Tag 저장
↓
배포 완료
실패:
Health Check 실패
↓
직전 정상 Tag로 변경
↓
이전 Image Pull
↓
Backend Service 재실행
↓
Rollback Health Check
Backend → 교체
AI Server → 유지
Redis → 유지
MySQL → 유지
PostgreSQL + pgvector → 유지
Nginx → 유지
name: Backend Production CD
on:
workflow_dispatch:
inputs:
image_tag:
description: "배포할 Backend Commit SHA"
required: true
type: string
permissions:
contents: read
id-token: write
concurrency:
group: production-deploy
cancel-in-progress: false
jobs:
deploy:
runs-on: ubuntu-latest
environment: production
steps:
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ vars.BACKEND_CD_ROLE_ARN }}
aws-region: ap-northeast-2
- name: Verify Image
run: |
aws ecr describe-images \
--repository-name needu-backend \
--image-ids imageTag=${{ inputs.image_tag }}
- name: Deploy via SSM
run: |
COMMAND_ID=$(aws ssm send-command \
--instance-ids "${{ vars.EC2_INSTANCE_ID }}" \
--document-name "AWS-RunShellScript" \
--parameters "commands=[\"cd /home/ec2-user/needu && ./deploy-backend.sh ${{ inputs.image_tag }}\"]" \
--query "Command.CommandId" \
--output text)
echo "COMMAND_ID=$COMMAND_ID" >> "$GITHUB_ENV"
aws ssm wait command-executed \
--command-id "$COMMAND_ID" \
--instance-id "${{ vars.EC2_INSTANCE_ID }}"고정 container_name에 의존하지 않고 Compose Service ID를 기준으로 Health 상태를 확인한다.
#!/bin/bash
set -Eeuo pipefail
NEW_TAG="$1"
PREV_TAG=$(cat .last_deployed_backend_tag 2>/dev/null || true)
export BACKEND_IMAGE_TAG="$NEW_TAG"
docker compose pull backend
docker compose up -d --no-deps backend
HEALTHY=false
for i in $(seq 1 12); do
CONTAINER_ID=$(docker compose ps -q backend)
STATUS=$(docker inspect \
-f '{{.State.Health.Status}}' \
"$CONTAINER_ID" 2>/dev/null || true)
if [ "$STATUS" = "healthy" ]; then
HEALTHY=true
break
fi
sleep 5
done
if [ "$HEALTHY" = true ]; then
echo "$NEW_TAG" > .last_deployed_backend_tag
exit 0
fi
if [ -z "$PREV_TAG" ]; then
exit 1
fi
export BACKEND_IMAGE_TAG="$PREV_TAG"
docker compose pull backend
docker compose up -d --no-deps backend
exit 1Rollback 이후에도 Health Check를 다시 수행하도록 실제 Script에서 보완한다.
진행 중인 HTTP Request가 즉시 끊기지 않도록 Spring Boot Graceful Shutdown을 사용한다.
예:
server:
shutdown: graceful
spring:
lifecycle:
timeout-per-shutdown-phase: 20sDocker Compose:
services:
backend:
stop_grace_period: 25s20s, 25s는 초기값이며 실제 Request 처리 시간과 Shutdown 시간을 측정한 뒤 조정한다.
AI Server는 FastAPI 기반 Docker Image를 ECR에서 Pull하여 Docker Compose Service를 교체한다.
ECR
└─ needu-ai:<AI Commit SHA>
수동 AI CD 실행
↓
배포할 AI SHA 입력
↓
ECR needu-ai Image 존재 확인
↓
SSM Run Command
↓
기존 정상 AI Tag 기록
↓
신규 AI Image Pull
↓
AI Server Service 교체
↓
AI Health Check
성공:
Health Check 성공
↓
신규 AI Tag 저장
↓
AI 배포 완료
실패:
Health Check 실패
↓
직전 정상 AI Tag로 변경
↓
이전 AI Image 실행
↓
Rollback Health Check
AI Server → 교체
Backend → 유지
Redis → 유지
MySQL → 유지
PostgreSQL + pgvector → 유지
Nginx → 유지
Redis를 재시작하지 않으므로 AI Server 배포 때문에 대화 State나 Cache가 불필요하게 초기화되는 것을 방지한다.
PostgreSQL + pgvector 역시 AI Application Image와 수명주기를 분리한다.
AI Server 배포 후에는 FastAPI Health Endpoint로 Application이 요청을 받을 수 있는 상태인지 확인한다.
예:
GET /health
초기 배포 성공 기준:
- AI Container가 실행 중일 것
- Health Endpoint가 HTTP 200을 반환할 것
- FastAPI Application이 요청을 받을 수 있을 것
/health Endpoint가 현재 AI Repository에 구현되어 있는지는 배포 전 확인한다. 아직 없다면 CD 적용 전에 간단한 Health Endpoint를 추가한다.
Redis, PostgreSQL + pgvector 등 Dependency 상태를 Health Endpoint에 포함할지는 실제 운영 필요에 따라 확장한다.
name: AI Production CD
on:
workflow_dispatch:
inputs:
image_tag:
description: "배포할 AI Commit SHA"
required: true
type: string
permissions:
contents: read
id-token: write
concurrency:
group: production-deploy
cancel-in-progress: false
jobs:
deploy:
runs-on: ubuntu-latest
environment: production
steps:
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ vars.AI_CD_ROLE_ARN }}
aws-region: ap-northeast-2
- name: Verify Image
run: |
aws ecr describe-images \
--repository-name needu-ai \
--image-ids imageTag=${{ inputs.image_tag }}
- name: Deploy via SSM
run: |
COMMAND_ID=$(aws ssm send-command \
--instance-ids "${{ vars.EC2_INSTANCE_ID }}" \
--document-name "AWS-RunShellScript" \
--parameters "commands=[\"cd /home/ec2-user/needu && ./deploy-ai.sh ${{ inputs.image_tag }}\"]" \
--query "Command.CommandId" \
--output text)
echo "COMMAND_ID=$COMMAND_ID" >> "$GITHUB_ENV"
aws ssm wait command-executed \
--command-id "$COMMAND_ID" \
--instance-id "${{ vars.EC2_INSTANCE_ID }}"#!/bin/bash
set -Eeuo pipefail
NEW_TAG="$1"
PREV_TAG=$(cat .last_deployed_ai_tag 2>/dev/null || true)
export AI_IMAGE_TAG="$NEW_TAG"
docker compose pull ai
docker compose up -d --no-deps ai
# Health Check
# 실패 시 AI_IMAGE_TAG를 PREV_TAG로 되돌리고
# 동일한 Compose Service를 다시 실행한다.실제 Service 이름과 Health Endpoint는 AI Repository / Compose 구현과 맞춘다.
LLM API 또는 Embedding API 응답을 기다리는 중에 AI Container가 즉시 종료되면 진행 중인 요청이 끊길 수 있다.
따라서 FastAPI Server도 Graceful Shutdown이 가능하도록 구성한다.
Docker Compose에서는 AI Service에 stop_grace_period를 설정하고 실제 요청 시간을 측정한 뒤 값을 조정한다.
Frontend는 Docker Image를 사용하지 않는다.
CI에서 생성한 dist/ Artifact를 EC2 Nginx 정적 파일 경로에 반영한다.
수동 CD 실행
↓
Frontend Commit SHA 입력
↓
GitHub Actions Artifact 확인
↓
dist 다운로드
↓
EC2 전달
↓
기존 dist 백업
↓
신규 dist 적용
↓
Nginx 검증
성공:
신규 dist 유지
↓
Frontend 배포 완료
실패:
신규 dist 제거
↓
이전 dist 복구
Frontend는 파일 하나씩 덮어쓰지 않고 Directory 단위로 교체한다.
예:
/var/www/needu
/var/www/needu.prev
/var/www/needu.new
name: Frontend Production CD
on:
workflow_dispatch:
inputs:
commit_sha:
description: "배포할 Frontend Commit SHA"
required: true
type: string
permissions:
contents: read
actions: read
id-token: write
concurrency:
group: production-deploy
cancel-in-progress: false
jobs:
deploy:
runs-on: ubuntu-latest
environment: production
steps:
- name: Download Frontend Artifact
run: |
echo "Download needu-frontend-${{ inputs.commit_sha }}"
- name: Validate Artifact
run: |
test -f dist/index.html
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ vars.FRONTEND_CD_ROLE_ARN }}
aws-region: ap-northeast-2
- name: Deploy via SSM
run: |
aws ssm send-command \
--instance-ids "${{ vars.EC2_INSTANCE_ID }}" \
--document-name "AWS-RunShellScript" \
--parameters "commands=[\"cd /home/ec2-user/needu && ./deploy-frontend.sh ${{ inputs.commit_sha }}\"]"GitHub Actions Artifact를 EC2로 전달하는 구체적인 전송 방식은 구현 단계에서 확정한다.
중요한 기준은 Frontend에 Docker/ECR을 추가하지 않고 dist/ 자체를 배포한다는 점이다.
| 구성요소 | Artifact | 저장 위치 |
|---|---|---|
| Frontend | Vite dist/
|
GitHub Actions Artifact |
| Backend | Docker Image | Amazon ECR needu-backend
|
| AI Server | Docker Image | Amazon ECR needu-ai
|
| Redis | 없음 | 공식 Redis Image 사용 |
| MySQL | 없음 | EC2 Host Process |
| PostgreSQL + pgvector | 없음 | EC2 Host Process |
Amazon ECR
├─ needu-backend
└─ needu-ai
PR 단계에서는 Docker Build 가능 여부만 확인한다.
PR
→ Docker Build Check
→ ECR Push X
main CI 성공 후에만 실제 Production 후보 Image를 ECR에 저장한다.
main
→ Docker Build
→ Commit SHA Tag
→ ECR Push
V1 초기에는 이전 Production Image를 ECR에 유지한다.
현재 Backend
needu-backend:a82f3c1
이전 Backend
needu-backend:91bd020
현재 AI
needu-ai:7e42c91
이전 AI
needu-ai:51ad933
배포 횟수가 증가해 Image가 많이 누적되면 ECR Lifecycle Policy를 검토한다.
다음과 같은 Secret은 Docker Image와 Git Repository에 포함하지 않는다.
Backend 예:
KAKAO_API_KEY
DB_PASSWORD
JWT_SECRET
AI Server 예:
LLM_API_KEY
EMBEDDING_API_KEY
AI_DB_PASSWORD
V1에서는 EC2의 환경 파일을 Docker Compose에 주입한다.
예:
/home/ec2-user/needu/.env
필요한 경우 Service별 환경 파일로 분리할 수 있다.
.env.backend
.env.ai
핵심 원칙은 각 Container에 필요한 Secret만 전달하는 것이다.
파일 권한은 운영 계정만 읽을 수 있도록 제한한다.
chmod 600 .envGit에는 포함하지 않는다.
.env
.env.*V1에서는 관리 단순성을 위해 EC2 환경 파일을 사용한다.
팀 규모 증가, Secret Rotation, 중앙 관리 필요성이 생기면 Parameter Store 또는 Secrets Manager를 검토한다.
Backend와 AI Server 모두 Recreate 방식을 사용한다.
기존 Service
↓
종료
↓
신규 Container 실행
↓
Health Check
↓
정상 서비스
| 항목 | Recreate | Blue-Green / Rolling |
|---|---|---|
| 동일 Service 동시 실행 | 1개 | 2개 이상 |
| Downtime | 발생 | 최소화 |
| Memory 사용량 | 낮음 | 증가 |
| Port / Routing 관리 | 단순 | 복잡 |
| Rollback | 이전 Image 재실행 | Traffic 전환 |
| V1 운영 복잡도 | 낮음 | 높음 |
V1의 예상 Peak Traffic은 약 0.16 RPS다.
짧은 계획 Downtime의 사용자 영향이 상대적으로 작다.
기본 배포 빈도는 주 2회이며 사용자 활동이 적은 새벽 시간대를 사용한다.
V1은 하나의 t3.medium에서 여러 Process를 함께 운영한다.
EC2
├─ Nginx
├─ Backend
├─ AI Server
├─ Redis
├─ MySQL
└─ PostgreSQL + pgvector
Blue-Green을 적용하면 Backend 또는 AI Server를 기존 버전과 신규 버전 두 개씩 동시에 실행해야 하므로 Memory 여유가 더 필요하다.
따라서 V1에서는 짧은 Downtime을 허용하고 운영이 단순한 Recreate 방식을 사용한다.
Backend는 Spring Boot Actuator Endpoint를 사용한다.
GET /actuator/health
배포 성공 기준:
- Container 실행
- Health Endpoint HTTP 200
- Application Status 정상
AI Server는 FastAPI Health Endpoint를 사용한다.
예:
GET /health
배포 성공 기준:
- Container 실행
- Health Endpoint HTTP 200
- FastAPI Process가 Request 처리 가능 상태
정확한 Endpoint와 Dependency Check 범위는 AI 구현 시 확정한다.
신규 Backend
↓
Health 실패
↓
이전 Backend SHA
↓
ECR Pull
↓
Backend Recreate
↓
Rollback Health Check
신규 AI Server
↓
Health 실패
↓
이전 AI SHA
↓
ECR Pull
↓
AI Service Recreate
↓
Rollback Health Check
신규 dist
↓
검증 실패
↓
needu.prev 복구
Health Check를 통과했지만 Smoke Test 또는 실제 사용자 동작에서 문제가 발견되면 직전 정상 SHA로 동일한 workflow_dispatch를 다시 실행한다.
별도 Rollback Workflow를 만들지 않는다.
정상 버전 SHA 입력
↓
기존 CD Pipeline 재실행
배포와 Rollback이 동일한 절차를 사용하도록 하기 위함이다.
Application Image Rollback과 Database Schema Rollback은 별개다.
Backend 또는 AI Server가 새로운 Schema를 요구하는데 Database를 파괴적으로 변경한 경우 Application Image만 되돌려도 정상 동작하지 않을 수 있다.
따라서 V1에서는 가능한 한 하위 호환 가능한 Schema 변경을 사용한다.
피해야 할 예:
- 기존 Column 즉시 삭제
- 기존 Column Rename
- 비호환 Type 변경
- 기존 Vector Schema를 즉시 제거
PostgreSQL + pgvector의 Embedding Model / Document Schema 변경으로 전체 재임베딩이 필요한 경우에도 Application Rollback과 Vector Data Rollback을 별도로 고려해야 한다.
배포 직후 다음을 확인한다.
- EC2 CPU
- EC2 Memory
- Disk 사용량
- Docker Container 상태
/actuator/health- Backend Application Log
- HTTP 5xx
- MySQL 연결 오류
- AI Server 호출 오류
/health- FastAPI Log
- HTTP 5xx
- Redis 연결 오류
- PostgreSQL + pgvector 연결 오류
- Vector Search 오류 / 지연
- LLM / Embedding API 오류
- Nginx 상태
- 정적 파일 제공 여부
- 주요 화면 Smoke Test
V1에서는 Canary 분석이나 Error Rate 기반 자동 Rollback까지 적용하지 않는다.
Health Check
+
Application Log
+
CloudWatch
+
간단한 Smoke Test
를 기준으로 배포 직후 상태를 확인한다.
배포 경로는 다음과 같다.
GitHub Actions
↓
AWS OIDC
↓
IAM Role
↓
SSM Run Command
↓
EC2
| 항목 | 정책 |
|---|---|
| SSH | 배포에 사용하지 않음 |
| GitHub → AWS | OIDC |
| 장기 AWS Access Key | 사용하지 않음 |
| EC2 배포 명령 | SSM Run Command |
| Backend Image Pull | EC2 IAM Role |
| AI Image Pull | EC2 IAM Role |
| Application Secret | EC2 환경 파일 |
| 환경 파일 Git 관리 | 금지 |
CD Workflow는 필요한 범위의 권한만 가진다.
예:
Backend CD Role
├─ needu-backend Image 조회
└─ 대상 EC2 SSM Command
AI CD Role
├─ needu-ai Image 조회
└─ 대상 EC2 SSM Command
Frontend CD Role
└─ 대상 EC2 SSM Command
EC2는 Backend와 AI Image를 ECR에서 Pull할 수 있어야 한다.
EC2 Instance Role
├─ needu-backend Pull
└─ needu-ai Pull
V1은 단일 EC2를 사용한다.
Frontend, Backend, AI CD가 동시에 실행되면 Resource 사용량과 배포 Script 상태가 겹칠 수 있다.
따라서 Production 배포는 하나의 공통 concurrency Group으로 직렬화한다.
concurrency:
group: production-deploy
cancel-in-progress: falseBackend CD 실행 중
↓
AI CD 요청
↓
대기
↓
Backend CD 완료
↓
AI CD 실행
기존 배포를 강제로 취소하지 않는다.
변경된 Component만 배포한다.
Frontend만 변경
→ Frontend CD
Backend만 변경
→ Backend CD
AI만 변경
→ AI CD
기본 배포 순서는 다음과 같이 둔다.
AI Server
↓
Health Check
Backend
↓
Health Check
Frontend
↓
Smoke Test
AI Server를 먼저 배포하는 이유는 신규 Backend가 새로운 AI API를 호출하는 경우 Backend보다 AI Endpoint가 먼저 준비되어 있어야 하기 때문이다.
Frontend는 Backend API에 의존할 수 있으므로 Backend가 정상 상태가 된 뒤 배포한다.
단, 이 순서는 API 변경이 하위 호환된다는 전제에서 사용한다.
호환되지 않는 API 변경이 필요한 경우 한 번에 양쪽을 깨뜨리는 방식보다 다음과 같이 단계적으로 변경한다.
1. AI Server가 기존 + 신규 Contract를 모두 지원
2. AI Server 배포
3. Backend가 신규 Contract 사용
4. Backend 배포
5. 필요 시 이전 Contract 제거
각 Repository main CI 성공
↓
Frontend dist / Backend Image / AI Image 생성
↓
배포 대기
↓
담당자 workflow_dispatch 실행
↓
AI Server 필요 시 배포
↓
AI Health Check
↓
Backend 필요 시 배포
↓
Backend Health Check
↓
Frontend 필요 시 배포
↓
Smoke Test
↓
전체 배포 완료
중간 단계에서 실패하면 해당 Component를 직전 정상 버전으로 Rollback하고 이후 Component 배포는 진행하지 않는다.
| 구분 | CI | CD |
|---|---|---|
| 목적 | 배포 가능한 Artifact 검증 / 생성 | Artifact를 Production에 반영 |
| Trigger | PR / main Push |
workflow_dispatch |
| Frontend | Build / E2E → dist/ Artifact |
Nginx 정적 파일 반영 |
| Backend | Test / Docker Build → ECR Push | Image Pull → Backend Recreate → Health Check |
| AI Server | Unit Test / Ruff / Docker Build → ECR Push | Image Pull → AI Recreate → Health Check |
| 실패 | Merge 차단 / Artifact 생성 중단 | Rollback / 기존 버전 유지 |
| EC2 접근 | 없음 | SSM |
- Frontend Build / E2E와
dist/Artifact 생성 - Backend Test / Docker Build와 ECR Image 생성
- AI Unit Test / Ruff / Docker Build와 ECR Image 생성
- 배포할 Artifact가 Git Commit SHA로 추적 가능한 상태
Redis / PostgreSQL + pgvector Integration Test는 현재 AI CI 필수 범위가 아니며, 관련 Adapter와 Test 구현 후 추가한다.
- 지정한 Artifact 존재 확인
- Production 반영
- Backend / AI Service 단위 Recreate
- Health Check
- 배포 실패 시 직전 정상 버전 복구
| 한계 | 내용 |
|---|---|
| Recreate Downtime | Backend / AI Service 교체 중 짧은 중단 가능 |
| 단일 EC2 | Host 장애 시 전체 서비스 영향 |
| Smoke Test 일부 수동 | Health Check가 모든 기능 정상 여부를 보장하지 않음 |
| DB Rollback 자동화 없음 | Application Rollback과 Schema Rollback 분리 |
| Secret 수동 관리 | 환경 파일 변경 / Rotation 자동화 없음 |
| 외부 API 의존 | LLM / Embedding API 장애는 Application Rollback만으로 해결되지 않을 수 있음 |
| 수동 Production 결정 | 담당자가 CD를 실행해야 함 |
EC2 t3.medium
├─ Nginx
├─ Docker Compose
│ ├─ Backend
│ ├─ AI Server
│ └─ Redis
├─ MySQL
└─ PostgreSQL + pgvector
Frontend
→ needu-frontend-<SHA>
→ GitHub Actions Artifact
Backend
→ needu-backend:<SHA>
→ Amazon ECR
AI Server
→ needu-ai:<SHA>
→ Amazon ECR
Frontend
→ workflow_dispatch
→ dist 배포
→ 실패 시 이전 Directory 복구
Backend
→ workflow_dispatch
→ ECR Image 확인
→ SSM
→ Backend Recreate
→ /actuator/health
→ 실패 시 이전 SHA Image
AI Server
→ workflow_dispatch
→ ECR Image 확인
→ SSM
→ AI Service Recreate
→ /health
→ 실패 시 이전 SHA Image
-
mainMerge와 Production 배포를 분리한다. - Frontend, Backend, AI Server는 각각 독립적으로 배포한다.
- Backend와 AI Server는 각각 별도 ECR Repository를 사용한다.
- Production EC2에서 Source를 다시 Build하지 않는다.
- Git Commit SHA로 배포 버전을 추적한다.
- Application 배포 시 Redis와 Database를 함께 재시작하지 않는다.
- Backend와 AI Server는 Recreate 배포를 사용한다.
- AI Server는 현재
mainCI 성공 + Docker Build Check + ECR Image 존재를 배포 조건으로 사용한다. - 배포 성공은 단순 Container 실행이 아니라 Health Check로 판단한다.
- 실패 시 직전 정상 Artifact로 복구한다.
- 여러 Component가 함께 변경되면 AI → Backend → Frontend 순으로 배포하되 API 하위 호환성을 유지한다.
- GitHub Actions → AWS는 OIDC, EC2 배포 명령은 SSM을 사용한다.
- Production 배포는 공통 Concurrency Group으로 직렬화한다.