이 구조는 기능적으로는 분산된 서비스를 잘 운영하고 있으나, 배포 및 운영의 효율성과 신뢰성 측면에서 개선 여지가 크다.
1.2. 기존 운영 및 배포 방식의 한계
항목
현황
문제점
환경 구성
각 EC2 인스턴스에 직접 의존성 설치 ( npm, openjdk 등)
환경 차이에 따른 실행 오류, 재현 어려움
CI/CD 파이프라인
GitHub Actions → zip 업로드 → CodeDeploy
zip 내 실행 스크립트 의존 → 운영 자동화 수준이 낮음
서비스 구성 요소 간 통합
Next.js, Spring Boot, MySQL이 단일 인스턴스에서 병렬 운영
리소스 충돌, 배포/모니터링/복구가 어려움
FastAPI 서버 연동
GCP 별도 구성, 수동 테스트 필요
통합 테스트 어렵고, 배포 시점 동기화 어려움
문제 대응
배포 실패 시 수동 롤백 (scp, cp, mv 등)
시간 소요 크고, 안정성 낮음
1.3. Docker 도입 필요성 요약
이러한 문제들을 근본적으로 해결하기 위해, 서비스의 핵심 구성 요소를 Docker 기반으로 컨테이너화할 필요가 있다.
환경 구성 자동화: Dockerfile로 OS, 라이브러리, 런타임까지 명확히 정의
CI/CD 연동 최적화: GitHub Actions에서 Docker 이미지 빌드 → ECR 푸시 → 배포까지 완전 자동화
배포 안정성 확보: 버전 명시된 이미지 태그 기반으로 재현 가능, 롤백 신속
운영 효율화: 각 구성 요소 컨테이너 격리 → 서비스간 충돌 방지, 자원 사용 최적화
클라우드 네이티브 전환 기반: 이후 ECS, EKS 등 오케스트레이션 환경으로 확장 가능
1.4. 도입 시 고려 포인트
어떤 구성요소를 컨테이너화할 것인가?
프론트(Next.js) / 백엔드(Spring Boot) / DB(MySQL) / AI 서버(FastAPI) 별로 나눠 설계
기존 CodeDeploy와의 연결성 유지 혹은 전환 여부
ECS or Fargate 활용 여부 검토
컨테이너 이미지 저장소는 ECR 또는 GitHub Container Registry 중 선택
기존 모니터링/로그 시스템(CloudWatch, S3)과 통합 유지 필요
2. Docker 도입의 필요성
2.1. 환경 불일치 문제 해결
🚨 현재 문제
개발자는 로컬(Mac, Windows)에서 Node.js, Java, Python 등 개별적으로 설치해 작업
운영 환경은 Amazon Linux 기반 → 라이브러리 버전 차이, OS 디렉토리 구조 차이 발생
“내 로컬에서는 되는데 서버에서는 안 돼요” 문제 반복
✅ Docker 도입 시 개선
Dockerfile을 통해 실행 환경을 명시적으로 정의 (FROM, RUN, COPY, CMD)
개발, 테스트, 운영 전 구간에서 동일한 컨테이너 이미지로 실행
환경 의존성 제거 → 문제 발생 지점이 OS가 아닌 애플리케이션 레벨로 국한
예시: Next.js의 SSR 시 node 버전 차이로 인한 ReferenceError: fetch is not defined 오류 → 컨테이너로 버전 고정하여 해소
2.2. 배포 자동화 수준 향상
🚨 현재 문제
GitHub Actions에서 zip으로 묶은 코드 → S3에 업로드 → CodeDeploy가 EC2에서 압축 해제
.sh 스크립트와 appspec.yml에 로직을 직접 작성 → 변경에 매우 민감, 유지보수 어려움
롤백 시 수동 스크립트 실행 → 다운타임 위험 높음
✅ Docker 도입 시 개선
GitHub Actions에서 Docker 이미지 자동 빌드 및 태깅
AWS ECR에 이미지 푸시 → ECS 혹은 EC2에서 docker run만으로 배포
버전 태그만 변경해도 과거 상태로 즉시 복구 가능 (v1.2.0 → v1.1.9)
정량 근거:
기존 배포 시간: 평균 15분 (압축, 업로드, 배포 대기 포함) -> Docker 도입 후: 평균 10분 (이미지 Pull + 실행)
2.3. 구성 요소별 의존성 및 자원 분리
🚨 현재 문제
Next.js, Spring Boot, MySQL이 동일 EC2 인스턴스 내에 설치되어 공존
포트 충돌, 자원(메모리/CPU) 경쟁, 로그 혼합 저장 등 관리 복잡성 증가
✅ Docker 도입 시 개선
각 서비스별 Docker 컨테이너로 실행 → 독립된 네트워크/자원/로그 경로 사용
장애 격리 및 문제 진단 용이 (e.g., docker logs, docker stats로 개별 추적 가능)
필요 시 개별 컨테이너만 재배포하거나 재시작 가능
예: Spring Boot만 재시작할 때 기존엔 전체 서버를 재부팅해야 했으나, 컨테이너 기반에서는 해당 컨테이너만 restart 하면 됨
2.4. FastAPI 서버와의 통합 및 배포 전략 동일
🚨 현재 문제
GCP에서 운영되는 FastAPI 서버는 AWS 서비스들과 별도 배포 관리
수동 배포 → 관리 일관성 부족
✅ Docker 도입 시 개선
GCP 역시 Docker 지원이 기본 → 동일한 Dockerfile 구조로 FastAPI 이미지 빌드 가능
CI/CD 파이프라인을 동일한 GitHub Actions 워크플로우로 확장 가능
단일 이미지 버전으로 여러 클라우드 간 일관된 배포 전략 확보
2.5. 협업 생산성 향상
🚨 현재 문제
개발자마다 Node.js, Java, Python 등 설치 및 설정이 상이
프로젝트 셋업 문서가 길고, 세팅 중 오류가 자주 발생
✅ Docker 도입 시 개선
docker-compose.yml 하나로 전체 개발 환경 구동 가능
“로컬에서 실행 안 되는 문제” 거의 제거 → 개발에 집중 가능
2.6 향후 확장을 위한 기반 확보
🛠 실무 시나리오
마이크로서비스 아키텍처로의 확장
ECS, Fargate, Kubernetes 기반 오토스케일링 고려
Canary, Blue/Green Deployment, A/B 테스트 등 고급 배포 전략 도입
✅ Docker 없이는 불가능하거나 매우 복잡
모든 오케스트레이션 플랫폼은 컨테이너 기반이 전제
Docker 도입이 되어 있어야 ECS Task, Kubernetes Pod 등으로 이전 가능
2.7. 요약 표
문제 영역
기존 문제
Docker 도입 시
실행 환경 불일치
OS/버전 문제
이미지 기반 환경 통일
배포 자동화
zip + 스크립트 의존
이미지 기반 자동화
운영 효율성
단일 서버 운영
컨테이너별 분리 운영
장애 대응
수동 롤백
이미지 태깅 기반 자동 롤백
확장성
EC2 한계
ECS/K8s 확장 준비 완료
협업 생산성
개발 환경 세팅 소요
1줄로 동일 환경 실행
🧭 3. 도커 아키텍처 설계
3.1. 전체 아키텍처 다이어그램
3.1.1 구성 AWS 리소스
구성 요소
설명
VPC
PROD, DEV 환경을 논리적으로만 분리 운영
Public Subnet
Bastion Host, Grafana를 배치해 외부 접속 및 모니터링 지원
Application Tier
Auto Scaling이 적용된 EC2 인스턴스에 Spring Boot 및 Next.js 컨테이너 실행
DB Tier
사설 서브넷에 배치된 MySQL 컨테이너 구동 EC2 인스턴스. EBS를 활용해 DB 저장
CodeDeploy + ECR
CI/CD 파이프라인과 연동되어, 이미지 배포 자동화 수행
Lambda + CloudWatch
알람 발생 시 SNS와 Discord 연동 알림 수행
WAF + CloudFront + Route 53
사용자 요청을 보호하고 정적 자산을 배포, DNS 도메인 연결 관리
3.1.2 구성 GCP 리소스
구성 요소
설명
VPC (10.178.0.0/20)
GCP의 FastAPI 서버가 위치한 퍼블릭 네트워크
FastAPI 서버
AI 서버
Cloud Storage
Faiss로 활용
3.2. 배포 전략
3.2.1 아키텍처 및 개요
본 아키텍처는 Blue/Green 배포 전략을 채택하여 다운타임 없는 안전한 배포를 목표로 한다.
AWS CodeDeploy, Auto Scaling Group, ALB(Application Load Balancer)를 활용하여
두 개의 대상 그룹(Blue/Green) 간 전환을 자동화하였다.
3.2.2 Blue/Greeen 선택 이유
항목
설명
무중단 배포
실시간으로 대응해야하는 AI 챗봇 서비스상 모델의 변경이 필요해도 서비스 운영 기간에는 배포가 힘든 경우가 많았음. Blue/Green 배포를 사용하면 배포 중에도 기존 트래픽은 Blue 그룹이 유지, 오류 발생 시 롤백 가능.
장애 대응 유연성
챗봇 응답 지연이나 오류 발생은 사용자 불만으로 직결됨. Health check 실패 시 자동 롤백 또는 수동 전환 가능하므로 안정성 확보.
CI/CD 자동화
사용자 피드백이나 챗봇 응답 품질 개선을 빠르게 반영할 수 있도록 GitHub Actions → ECR → CodeDeploy까지 자동화 연동
실시간 모니터링
Codedeploy의 Blue/Green에는 cloudwatch alarm 연동이 가능하므로 Discord 알림으로 배포 진행 상황을 실시간 확인 가능
ASG 확장성
배포 대상이 Auto Scaling Group으로 구성되어 챗봇 사용자 수 증가에 따라 서비스 탄력성 확보
3.2.3 구성 리소스
구성 요소
설명
CodeDeploy
ECR에 푸시된 새 Docker 이미지의 배포를 트리거하고, 대상 그룹 교체를 수행
Auto Scaling Group
서비스 인스턴스를 탄력적으로 운영하며, 각 배포 시 Blue 또는 Green 그룹에 신규 인스턴스를 생성
ALB
라우팅 트래픽을 Blue 또는 Green 대상 그룹 중 하나로 전달
CloudWatch + SNS + Lambda
배포 성공/실패 이벤트를 감지하여 Discord로 실시간 알림 전달
ECR
컨테이너 이미지를 저장하고 CodeDeploy와 연결
Discord
운영/개발자가 실시간으로 배포 상태를 확인할 수 있도록 알림 채널 제공
3.2.4 Blue/Greeen 배포 프로세스
[1] GitHub Actions에서 이미지 빌드 후 ECR에 푸시
↓
[2] CodeDeploy가 CD 트리거 수신 → 신규 ASG 인스턴스 기동 (Green Target Group)
↓
[3] Health Check 성공 시 → ALB 대상 그룹을 Blue → Green 으로 전환
↓
[4] 기존 Blue 그룹은 대기 상태로 유지 또는 종료
↓
[5] CloudWatch Alarm으로 성공/실패 감지 후 → Lambda → SNS → Discord 알림 발송
운영용 이미지에 대해 cosign 서명 자동화 (main 브랜치 배포 시 서명 후 push)
서명 키는 OIDC 연동 + GitHub Actions 내부 Keyless Signing으로 관리
📋 4. Docker 기술 구성 명세서
4.1. Next.js
항목
값
Base Image
node:18-alpine
컨테이너 수
2개 (Dev/Prod)
포트
3000
환경 변수
NODE_ENV, PORT 등
빌드 명령어
npm run build, npm start
📦 Dockerfile
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
EXPOSE 3000
CMD ["npm", "start"]
4.2. Spring Boot
항목 | 값
-- | --
Base Image | gradle:8.5-jdk21-alpine → temurin:21-jdk-alpine
컨테이너 수 | 2개 (Dev/Prod)
포트 | 8080
환경 변수 | SPRING_PROFILES_ACTIVE, DB_HOST 등
빌드 명령어 | gradle clean build --no-daemon
📦 Dockerfile
# 🔹 1단계: 빌드 스테이지FROM gradle:8.5-jdk17-alpine AS build
WORKDIR /app
# 종속성 캐싱을 위해 먼저 복사COPY build.gradle.kts settings.gradle.kts ./
COPY gradle ./gradle
RUN gradle build --no-daemon || return 0
# 전체 소스 복사 후 빌드COPY . .
RUN gradle clean build --no-daemon
# 🔹 2단계: 런타임 이미지FROM eclipse-temurin:17-jdk-alpine
WORKDIR /app
COPY --from=build /app/build/libs/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]