[CL] Docker 컨테이너화 배포 설계 - 100-hours-a-week/2-hertz-wiki GitHub Wiki
📚 목차
📄 Docker 도입 전략 설명서 (vs 기존 CI/CD 소스 배포)
1. 도입 배경 및 목적
우리 서비스는 짧고 빈번한 배포 준비로 기능이 자주 바뀌고, 푸쉬 알림을 통해 트래픽이 집중되는 시간대도 존재합니다. 이에 따라 개발과 운영 모두 빠르고 민감한 대응이 필수적입니다. 또한 기존 방식은 수동 설치와 운영 서버에 대한 빌드를 직접 수행해서 올려야하는 위험이 존재했습니다. 따라서 다음과 같은 근거로 Docker를 도입하려고 합니다.
1.1 기존 배포 방식의 구조
기존에는 수동으로 초기 인스턴스 환경을 구축하고, GitHub Actions 기반 CI/CD를 통해 소스 코드를 서버에 pull 하여, 해당 서버에서 deploy.sh
를 실행해 빌드 및 서비스를 재시작하는 방식으로 배포를 수행했습니다.
GitHub Actions trigger → CI 테스트 → CD 서버로 코드 자동 배포 → 자동 빌드 및 서비스 재시작
1.2 기존 방식의 문제점
문제점 | 상세 내용 |
---|---|
환경 일관성 부족 | - 인스턴스마다 Node, Java, Python 등 실행 환경의 수동 설치 필요- 버전 차이로 로컬/서버 불일치 문제 발생 |
빌드 실패 위험 | - 운영 서버 직접 빌드로 OS/의존성 충돌 발생 가능- 빌드 실패 시 운영 서비스 중단 위험 |
확장성/유연성 부족 | - 새로운 인스턴스마다 환경 수동 세팅 필요- 오토스케일링, 무중단 배포 부적합 |
배포 추적/관리 어려움 | - 현재 배포 버전의 커밋 파악 어려움- git 기록에만 의존한 배포 및 운영관리가 불편 |
롤백 복잡성 및 지연 | - 문제가 생기면 pull → 빌드 → 재시작 과정 필요- 빠른 복구가 어려움 |
1.3 배포 방식 비교
항목 | 기존 방식 (소스 배포) | Docker 기반 배포 |
---|---|---|
배포 속도 | 5~10분 (서버에서 빌드 포함) | 2~3분 (이미지 실행만) |
환경 일관성 | 낮음 | 매우 높음 |
확장성 | 낮음 | 높음 (이미지 복제) |
버전 관리 | Git commit 기반 | 이미지 태그 기반 |
실패 복구 (롤백) | 재배포 필요 | 이미지 교체로 즉시 복구 |
운영 복잡도 | 높은 운영 개입 필요 | 자동화 가능 |
1.4. 배포 절차 비교
Before) 기존 배포 절차 (CI/CD)
- 각 서비스 별 초기 세팅
- GitHub Actions → SSH 접속
deploy.sh
실행 (git pull → PM2 or nohup)- 헬스체크 자동화
- Discord 자동 알림 (성공/실패)
- 롤백 시 이전 커밋 기록 기반 재 빌드 후 실행
After) Docker 기반 배포 절차
- GitHub Actions → Docker Image Build
- ECR 푸시
- CodeDeploy + ASG 템플릿
- Green 인스턴스 생성 및 Docker Run
- 헬스체크 자동화
- ALB 트래픽 전환 → Blue→Green
- Discord 자동 알림 (성공/실패) + 성공 시 Blue 제거
- 롤백 시 태깅으로 관리한 이전 버전 이미지로 run(Blue로 전환)
1.5 Docker로 전환 시 기대 효과
-
배포 시간 50% 이상 단축 빌드 과정 제거, 이미지 실행만으로 배포 완료
-
운영 환경 일관성 확보 모든 환경에서 동일한 이미지 사용 → 실행 오류 최소화
-
버전 통제 및 가시성 강화 어떤 이미지가 언제 배포되었는지 태그 및 GitHub Action 기록으로 추적
-
롤백 용이성 이전 이미지로 교체만 하면 즉시 복구 가능
-
확장성 및 마이크로서비스 대응력 향상 서비스별 분리된 이미지 관리 → 자동 확장(ASG, ECS 등) 용이
1.6 결론
우리 서비스는 기능이 자주 바뀌고, 트래픽이 집중되는 시간대도 존재합니다. 따라서 개발과 운영 모두 빠르고 민감한 대응이 필수적입니다.
현재는 GitHub Actions로 코드 배포는 자동화했지만, 운영 서버에서 직접 빌드하고 환경을 맞추는 구조는 여전히 불안정하며, 확장성 면에서도 한계가 뚜렷합니다. 그에 비해 Docker는 이미지 패키징을 통한 배포의 통일성을 보장하고, 이미지 태그를 통하여 QA·운영·롤백에 신속한 대응이 가능합니다. 이미지를 사용하기 때문에 단순한 컨테이너 및 인스턴스 복제로 트래픽 급증에 대한 대응이 가능합니다.
특히, FE/BE/AI/WebSocket 등 이기종 환경을 포함하는 3-Tier 구조에서 Docker는 빌드 자동화, 환경 일관성, 배포 속도, 확장성에서 확실한 경쟁력을 제공하여, 서비스의 안정성과 속도를 모두 확보할 수 있는 가장 현실적인 선택입니다.
따라서 우리는 Docker 기반 컨테이너 환경으로 아키텍처를 마이그레이션하여, 운영 효율성과 서비스 확장성을 획기적으로 개선하고자 합니다.
2. 컨테이너 관리 전략
2.1 이미지 레지스트리
- Amazon ECR (Elastic Container Registry) 사용
- 모든 컨테이너 이미지는 ECR에 저장 및 버전 관리됨
- CI/CD 파이프라인(GitHub Actions 등)에서 이미지 빌드 후 ECR로 push
- ECR에 Push → CodeDeploy → EC2 인스턴스 Pull & Deploy 구조 사용
branch-shortCommitHash
)
2.2 태깅 정책: 커밋 기반 태그 (2.2.1 태깅 형식
[브랜치명]-[짧은 커밋 해시]
ex) main-98a1f2c
, develop-98a1f2c
2.2.2 사용 이유 및 장점
- 버전 추적성 확보
- 어떤 커밋을 기준으로 이미지가 빌드되었는지를 명확하게 알 수 있습니다.
- 특정 문제가 발생했을 때, 해당 커밋 해시를 기준으로 코드와 이미지 상태를 정확히 재현할 수 있습니다.
- CI/CD 파이프라인과 연계 용이
- GitHub Actions에서 커밋 해시를 기반으로 자동으로 태그를 생성할 수 있어 자동화가 용이합니다.
- 각 배포마다 고유한 태그가 부여되므로 동시 배포 충돌 방지 및 이전 이미지 보존에 유리합니다.
- 브랜치별 관리 가능
main-xxx
,develop-xxx
,feature-xxx
식으로 브랜치명 접두어를 사용하면 태그만으로도 운영/테스트 환경 구분이 가능합니다.develop-*
이미지는 스테이징에서만,main-*
이미지는 프로덕션에만 사용할 수 있도록 태그 기반 룰 설정 가능
- 롤백 대응이 빠름
- 배포 시 문제가 발생한 커밋의 태그를 기반으로 즉시 해당 이미지로 롤백 가능
- 운영 환경에서는
main-a3f1c2d
같은 태그를 기준으로 안전하게 이력 관리
2.3 리소스 할당 정책 (CPU/Memory)
각 컨테이너는 예상되는 부하와 트래픽 패턴 및 테스트를 기준으로 산정하였습니다.
- 프론트엔드 (Next.js): t3.small(2 vCPU / 2GB)
- Next.js: --cpus=1, --memory=2g
- 백엔드 (Spring Boot): t3.medium(2 vCPU / 4GB)
- cpus=1.5, --memory=3.0g
- 웹소켓(Socket.IO): t3.medium (2 vCPU / 4GB) - cpus=1, --memory=1.5g
- kafka: t3.medium (2 vCPU / 4GB)
- zookeeper : --cpus=0.5 , --memory=0.5g
- broker1 : --cpus:2.0 , --memory=2g
- broker2~3 : --cpus:1.0 , --memory=2g
2.4 개발 환경과 운영 환경의 컨테이너 활용 차이
항목 | 개발 환경(Dev) | 운영 환경(Prod) |
---|---|---|
인프라 구성 | 단일 EC2 인스턴스에서 각 서비스 독립 실행 | Auto Scaling Group(ASG) 기반 멀티 인스턴스 구성 |
배포 구조 | 블루그린 없이 직접 덮어쓰기 방식 배포 | Blue-Green 배포 전략 적용 (ALB + 2개 ASG) |
컨테이너 실행 방식 | GitHub Actions → ECR → CodeDeploy로 자동 배포 | GitHub Actions → ECR → CodeDeploy로 자동 배포 |
네트워크 구성 | 프론트엔드 ↔ 백엔드 간 직접 인스턴스 IP 통신 | ALB가 모든 트래픽을 받아 프론트/백으로 분산 |
리버스 프록시 | Nginx가 Next.js 컨테이너 앞에서 포워딩 | 동일하게 구성되며, 프론트 ASG 내에서 분산됨 |
데이터베이스 | EC2 내부에서 MySQL, Redis 각 컨테이너 실행 (Private subnet) | EC2 내부에서 MySQL, Redis 각 컨테이너 실행 (Private subnet) |
헬스체크 및 모니터링 | ALB Health Check 연동 예정 | ALB Health Check 연동 예정 |
환경 변수 | Github Actions → Dockerfile 빌드 시 Github Secrets로 전달 | Github Actions → Dockerfile 빌드 시 Github Secrets로 전달 |
인증/보안 구성 | 보안 그룹 제한 없이 개발 편의 우선 | EC2/ALB 보안 그룹으로 IP 및 포트 제한 설정 |
운영 환경은 가용성과 확장성, 장애 대응을 고려하여 Blue-Green 업데이트 및 ASG 등을 갖추고 있으며, 개발 환경은 빠른 테스트와 단일 진입점 구성을 우선시하여 단순한 구조로 유지됨.
3. 인스턴스 부하 테스트
3.1 Backend
wrk -t8 -c100 -d30s http://localhost:9411/api/v2/spans -s post-spans.lua
- 옵션
- t8: 8개의 쓰레드
- c100: 100개의 동시 연결
- d30s: 30초간 테스트
테스트 결과
항목 | t3.medium | t3.small |
---|---|---|
CPU 사용률 | 107.82% | 110.73% |
메모리 사용량 | 332.3MiB / 3GiB (10.82%) | 336.3MiB / 1.857GiB (17.69%) |
요청 처리량 (RPS) | 9,329.94 req/sec | 8,685.84 req/sec |
총 요청 수 (30초간) | 280,032 | 260,786 |
전송량 (총) | 28.04MB | 26.11MB |
평균 응답 지연 시간 | 10.31ms | 11.09ms |
최대 응답 지연 시간 | 65.49ms | 62.75ms |
평가
기준 | t3.small | t3.medium |
---|---|---|
단기 테스트 | ✅ 충분히 가능 | ✅ 더 안정적 |
실서비스 운영 | ⚠️ 성능은 되지만 크레딧/메모리 한계 위험 | ✅ 추천 |
버스트 내성 | ⚠️ 크레딧 바닥 시 급격한 저하 | ✅ 탄력적 운영 가능 |
장시간 Span 수집 | ⚠️ GC/메모리 스파이크 가능 | ✅ 지속 가능성 높음 |
3.2 kafka
시나리오: “실시간 채팅 서비스 – 50명~70명 동시 접속”을 가정
- 채팅 유형: 1:1 채팅과 그룹 채팅 혼합
- 총 메시지 수:
- 그룹 채팅: 20,000건 (40%)
- 1:1 채팅: 30,000건 (60%)
- 메시지 크기: 약 200바이트
- Kafka 클러스터: 브로커 3개, replication factor 3
- 전송 속도 제한 (throughput = 5,000 records/sec)
- 급격한 폭주 없이 초당 약 5,000건 전송 (부드럽게 가하는 부하)
- 약 10초에 50,000건 → 전체 테스트는 약 10~12초 소요 예상
t3.medium
항목 | 결과 |
---|---|
처리량 | 매우 안정적 (4900~5000 req/sec) |
평균 지연 | 그룹 70210ms, 개인 2050ms 수준 |
최대 지연 | 500~800ms 구간, 점진적으로 개선 |
리소스 추정 | CPU 1.5코어, 메모리 3GB 정도면 충분히 버틸 수 있음 |
부하 수준 | “부드러운 부하”로 정상 작동 |
📄 시스템 구성도 및 기술 명세(기술 구성 명세)
1. 전체 시스템 구조 개요 (Docker 기반 구성)
아키텍처 다이어그램
2. 이미지 빌드 및 배포 흐름
CI/CD 다이어그램
- GitHub Actions에서 브랜치 푸시(
main
,develop
) 시 CI 트리거 Dockerfile
기반으로 애플리케이션 빌드- Docker 이미지에 다음과 같은 태그 부여 → 예시:
main-a1b2c3d
,develop-9z8y7x
- 빌드된 이미지를 Amazon ECR에 push
- 운영 환경에서는 CodeDeploy 와 Auto Scaling Group(ASG)을 통해 다음 절차로 무중단 배포를 수행
- 신규 버전 배포를 위한 EC2 인스턴스를 ASG에 의해 자동 생성
- 새 인스턴스에서 ECR로부터 최신 Docker 이미지 pull 및 컨테이너 실행
- Blue ↔ Green 전환: CodeDeploy가 기존 Target Group에서 기존 인스턴스를 제거하고, 새 인스턴스를 새 Target Group에 등록
- 헬스체크 성공 시, ALB 트래픽을 새로운 Target Group(Green)으로 전환
- 이전 버전은 일정 시간 유지 후
desired=0
설정으로 종료하거나 완전히 삭제
CI/CD 파이프라인은 서비스 단위로 분리되어 있으며, 프론트엔드와 백엔드, AI는 각각 독립적으로 배포됩니다.
3. 네트워크 및 연결 구조
- 운영 환경: 프론트엔드, 백엔드, WebSocket 서버는 각각 독립된 Auto Scaling Group에서 실행되며, 모든 요청은 ALB를 통해 분산됩니다.
- 컨테이너 내부 네트워크는 기본적으로
bridge
모드 사용 - 프론트(Nginx) → Next.js: 동일 EC2 내 컨테이너 간
http://nextjs:3000
으로 연결 - 프론트 → 백엔드 API 요청: ALB를 통해 백엔드 ASG로 라우팅됨
- 프론트 → WebSocket 연결:
wss://socket.example.com
도메인을 통해 직접 WebSocket 서버에 연결
4. 데이터 볼륨 및 영속성 전략
서비스 | 데이터 저장 방식 |
---|---|
MySQL | /data/mysql:/var/lib/mysql 로 EC2의 로컬 디스크에 마운트 |
Redis | /data/redis:/data 로 RDB snapshot을 EC2 내에 보존 |
Next.js, Spring Boot, WebSocket | Stateless 서비스로 데이터 저장 없음. 배포 및 재시작에 영향 없음 |
- RDS 사용 전에는 DB 서버를 별도의 EC2 인스턴스에 구성하여 프론트/백엔드 컨테이너와 분리
- 데이터 컨테이너는 private subnet에서 실행되며 외부 접근은 차단됨
- 백엔드 컨테이너는 Redis와 MySQL에 내부 IP로 직접 접근
5. Dockerfile 예시
Frontend(Next.js+Nginx)
Dockerfile
# 1단계: 빌드
FROM node:18-alpine AS builder
WORKDIR /app
COPY ./package*.json ./
RUN npm install
COPY . .
RUN npm run build
# 2단계: 실행용
FROM node:18-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
# node_modules와 .next만 가져옴
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/.next ./.next
COPY --from=builder /app/public ./public
COPY --from=builder /app/package.json ./
CMD ["npm", "run", "start"]
docker-compose.frontend.yml
version: '3.8'
services:
nextjs:
build:
context: .
dockerfile: Dockerfile
container_name: nextjs-app
restart: always
environment:
- PORT=3000
ports:
- "3000:3000" # 외부에서 바로 접근 가능하도록 매핑
deploy:
resources:
limits:
cpus: '1.0'
memory: 2g
networks:
- frontend-net
networks:
frontend-net:
driver: bridge
Backend(Spring Boot)
Dockerfile
# 1. Java 17 기반 이미지 사용
FROM eclipse-temurin:17-jdk-alpine as builder
# 2. 작업 디렉토리 설정
WORKDIR /app
# 3. 빌드에 필요한 파일 복사
COPY gradlew .
COPY gradle gradle
COPY build.gradle settings.gradle ./
COPY src src
# 4. 의존성 캐시
RUN ./gradlew dependencies || return 0
# 5. 애플리케이션 빌드
RUN ./gradlew clean build -x test
# --- 실제 실행 이미지로 옮기기 ---
FROM eclipse-temurin:17-jdk-alpine
# 앱 실행 디렉토리
WORKDIR /app
# JAR 파일 복사 (최신 버전 자동 복사)
COPY --from=builder /app/build/libs/*.jar app.jar
# 8080 포트 오픈
EXPOSE 8080
# 실행
ENTRYPOINT ["java", "-jar", "app.jar"]
docker-compose.backend.yaml
version: "3.8"
services:
springboot-server:
build:
context: .
dockerfile: Dockerfile
container_name: springboot-server
ports:
- "8080:8080"
deploy:
resources:
limits:
cpus: "1.5"
memory: 3g
environment:
SPRING_PROFILES_ACTIVE: prod
restart: always
****
Socket.IO
Dockerfile
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 5000
CMD ["node", "server.js"]
docker-compose.websocket.yml
version: "3.8"
services:
socket-server:
build: .
container_name: socket-server
ports:
- "5000:5000"
environment:
- PORT=5000
- CORS_ORIGIN=https://app.example.com
- REDIS_HOST=redis://redis:6379
depends_on:
- redis
deploy:
resources:
limits:
cpus: "1"
memory: 1.5g
AI(Fast API)
Dockerfile
FROM python:3.10-slim
# 기본 디렉토리 생성
WORKDIR /app
# requirements.txt 설치
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# 애플리케이션 소스 복사
COPY . .
EXPOSE 8000
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000"]
docker-compose.ai.yaml
version: "3.8"
services:
ai-server:
build: ./ai-server
container_name: ai-server
ports:
- "8000:8000"
volumes:
- ./ai-server:/app
- ./ai-server/model:/app/model # 파인튜닝 모델 경로 공유
environment:
- CHROMA_HOST=http://chroma-db:8001
depends_on:
- chroma-db
chroma-db:
image: chromadb/chroma
container_name: chroma-db
ports:
- "8001:8000"
volumes:
- chroma_data:/chroma/.chromadb
volumes:
chroma_data:
kafka
docker-compose.kafka.yaml
version: '3.8'
services:
zookeeper:
image: confluentinc/cp-zookeeper:7.5.0
container_name: zookeeper
ports:
- "2181:2181"
environment:
ZOOKEEPER_CLIENT_PORT: 2181
ZOOKEEPER_TICK_TIME: 2000
kafka1:
image: confluentinc/cp-kafka:7.5.0
container_name: kafka1
ports:
- "9092:9092"
environment:
KAFKA_BROKER_ID: 1
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://localhost:9092
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
kafka2:
image: confluentinc/cp-kafka:7.5.0
container_name: kafka2
ports:
- "9093:9093"
environment:
KAFKA_BROKER_ID: 2
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://localhost:9093
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
kafka3:
image: confluentinc/cp-kafka:7.5.0
container_name: kafka3
ports:
- "9094:9094"
environment:
KAFKA_BROKER_ID: 3
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://localhost:9094
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
6. Docker 기술 요소 요약
구성 요소 | 베이스 이미지 | 컨테이너 수 | 주요 포트 | 역할 |
---|---|---|---|---|
Next.js | node:18-alpine |
EC2 당 1개 | 3000 | 클라이언트 UI 및 SSR |
Spring Boot | eclipse-temurin:17-jdk-alpine |
EC2 당 1개 | 8080 | API 서버 |
Socket.IO | node:18-alpine |
EC2 당 1개 | 5000 | 실시간 메시지 송수신 처리 (WebSocket 기반) |
FastAPI | python:3.10-slim |
인스턴스 당 1개 | 8000 | AI API 서버 + 추론 모델 |
MySQL | mysql:8.0 |
EC2 당 1개 | 3306 | 사용자 및 메시지 저장 |
Redis | redis:7.0-alpine |
EC2 당 1개 | 6379 | Pub/Sub 및 캐시 |
Kafka Broker | confluentinc/cp-kafka:7.5.0 |
EC2 당 3개 | 9092~9094 | 메시지 큐 역할, WebSocket ↔ Backend 연계 |
Zookeeper | confluentinc/cp-zookeeper:7.5.0 |
EC2 당 1개 | 2181 | Kafka 클러스터 메타데이터 저장 및 브로커 관리 |
7. 전체 환경 변수 목록
Next.js
환경변수 | 설명 | 예시 |
---|---|---|
NEXT_PUBLIC_API_URL |
브라우저에서 사용할 백엔드 API의 주소 | https://api.example.com |
NODE_ENV |
환경 구분 (개발/운영) | production 또는 development |
Spring Boot
환경변수 | 설명 | 예시 |
---|---|---|
SPRING_DATASOURCE_URL |
MySQL DB 접속 주소 (JDBC 포맷) | jdbc:mysql://db:3306/appdb |
SPRING_DATASOURCE_USERNAME |
DB 접속 ID | appuser |
SPRING_DATASOURCE_PASSWORD |
DB 접속 비밀번호 | securepassword |
JWT_SECRET |
JWT 서명 키 (보안 정보) | super-secret-key |
REDIS_HOST |
Redis 접속 주소 | redis://redis:6379 |
FAST_API_URL |
AI 서버 URL | https://ai-api.example.com |
Socket.IO
환경변수 | 설명 | 예시 |
---|---|---|
PORT |
Socket.IO 서버가 리스닝할 포트 | 5000 |
CORS_ORIGIN |
허용된 CORS Origin 주소 | https://app.example.com |
REDIS_HOST |
Redis Pub/Sub 백엔드 주소 | redis://redis:6379 |
NODE_ENV |
실행 환경 구분 | production |
AI (fastAPI + ai model)
환경변수 | 설명 | 예시 |
API_HOST |
FastAPI가 바인딩할 호스트 | 0.0.0.0 |
API_PORT |
FastAPI가 리스닝할 포트 | 8000 |
ENV |
실행 환경 | development, production 등 |
CHROMA_HOST |
ChromaDB가 실행 중인 호스트명 | localhost 또는 chroma |
CHROMA_PORT |
ChromaDB 포트 | 8001 |
CHROMA_COLLECTION_NAME |
유사도 검색에 사용할 컬렉션명 | user_embeddings |
MySQL
환경변수 | 설명 | 예시 |
---|---|---|
MYSQL_ROOT_PASSWORD |
루트 비밀번호 (초기화 시 필요) | rootpass123 |
MYSQL_DATABASE |
자동 생성할 기본 DB 이름 | appdb |
Redis
환경변수 | 설명 | 예시 |
---|---|---|
없음 | Redis는 별도 환경변수 없이 기본 설정으로 실행 가능 | - |
Kafka
경변수 | 설명 | 예시 |
---|---|---|
KAFKA_BROKER_ID |
브로커 고유 ID (중복 불가) | 1, 2, 3 |
KAFKA_ZOOKEEPER_CONNECT |
연결할 Zookeeper 호스트 목록 | zookeeper:2181 |
KAFKA_ADVERTISED_LISTENERS |
외부 클라이언트가 접속할 주소 (컨테이너 외부 노출) | PLAINTEXT://localhost:9092 |
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP |
리스너 명칭 → 프로토콜 매핑 | PLAINTEXT:PLAINTEXT |
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR |
Consumer Group 오프셋 저장용 토픽 복제 수 | 1 (테스트) / 3 (운영) |
KAFKA_LOG_RETENTION_HOURS |
메시지 보관 시간 (기본값: 168시간 = 7일) | 168 |
KAFKA_MESSAGE_MAX_BYTES |
최대 메시지 크기 (Byte) | 1000000 |
환경 변수는 모두 Github Secrets을 이용해서 관리할 예정임
📄 AWS 최종 비용 산정
1. 비용 산정 기준
- 일일 활성 사용자 (DAU): 약 150명
- 프론트엔드(Next.js) 평균 트래픽: 500MB~1GB/일
- 웹소켓(Socket.IO) 활성 연결 수: 평균 100명 동시 접속
- API 호출량: 약 10,000~20,000회/일
- Kafka 트래픽: 소형 메시지 기준, 10GB/월 미만
- DB 트래픽(MySQL/Redis): 소형 트래픽, 캐시 중심 구조
2. 세부 예상 비용
그룹 | 리전 | 서비스 | 설명 | 구성 요약 | 월별 비용 (USD) |
---|---|---|---|---|---|
ALB-public | 서울(ap-northeast-2) | Application Load Balancer | 프론트엔드 트래픽 수용 | ALB 수 (1) | 19.35 |
ALB-private | 서울(ap-northeast-2) | Application Load Balancer | 백엔드 API 트래픽 수용 | ALB 수 (1) | 17.89 |
NAT G/W | 서울(ap-northeast-2) | NAT Gateway | 워커노드, 백엔드 아웃바운드 | NAT G/W 수 (1) | 43.1 |
S3-deploy-script (Storage) | 서울(ap-northeast-2) | S3 Standard | Deploy Script 저장 | 1GB 스토리지, PUT/COPY/POST/LIST 요청(60), GET 요청(100) | 0.03 |
S3-deploy-script (Data Transfer) | 서울(ap-northeast-2) | Data Transfer | 스크립트 파일 전송 트래픽 | Inbound/Outbound 0TB | 0 |
ECR-docker | 서울(ap-northeast-2) | Elastic Container Registry | Docker Image 저장 | 저장 5GB, Pull 5GB/월 | 1.13 |
WAF | 서울(ap-northeast-2) | AWS Web Application Firewall | 웹 공격 방어 | 웹 ACL 1개, 규칙 5개, 그룹 1개 | 16.6 |
EC2-frontend | 서울(ap-northeast-2) | EC2 (t3.small) | Next.js 프론트엔드 서버 | 1대, 20GB EBS | 20.8 |
EC2-backend | 서울(ap-northeast-2) | EC2 (t3.medium) | Spring Boot 백엔드 서버 | 1대, 30GB EBS | 40.7 |
EC2-websocket | 서울(ap-northeast-2) | EC2 (t3.medium) | Socket.IO 웹소켓 서버 | 1대, 30GB EBS | 40.7 |
EC2-kafka | 서울(ap-northeast-2) | EC2 (t3.medium) | Kafka 브로커 + Zookeeper 서버 | 1대, 30GB EBS | 40.7 |
EC2-DB | 서울(ap-northeast-2) | EC2 (t3.medium) | MySQL + Redis 서버 | 1대, 100GB EBS | 54.33 |
3. 리소스 설명
- ALB-public: Next.js(프론트엔드) 트래픽 수용
- ALB-private: 프론트 → 백엔드 API 요청 수용
- NAT Gateway: 워커노드 및 백엔드 서버의 외부 요청 처리
- S3-deploy-script: GitHub Actions용 배포 스크립트 저장
- ECR-docker: Docker 이미지 저장소
- WAF: Application Load Balancer 보안 강화
- EC2-frontend: Next.js 서버 구동
- EC2-backend: Spring Boot API 서버 구동
- EC2-websocket: Socket.IO 기반 WebSocket 서버 구동
- EC2-kafka: Kafka 브로커 및 Zookeeper 구동
- EC2-DB: MySQL, Redis 데이터베이스 서버 구동
4. 총 월 예상 비용
총 월 예상 비용: 약 295.33 USD
👉 AWS Pricing Calculator 링크 보기
📄 GCP 최종 비용 산정
1. 비용 산정 기준
- GCP 리소스는 모두 서울 리전(asia-northeast3) 에 배치합니다.
- GCE 인스턴스는 월 730시간을 기준으로 고려했습니다.
- GPU 서버는 월 90시간만 사용하여, 비용 최적화를 고려했습니다.
2. 세부 예상 비용
그룹 | 리전 | 서비스 | 설명 | 구성 요약 | 월별 비용 (USD) |
---|---|---|---|---|---|
GCE-ai-embeded | 서울(asia-northeast3) | Compute Engine | AI 임베딩 서버 (CPU Only) | e2-standard-4, 4vCPU, 16GB RAM, 50GB 디스크 | 132.01 |
GPU-ai (NVIDIA L4) | 서울(asia-northeast3) | Cloud GPU | AI Inference용 GPU 서버 (90시간 사용) | g2-standard-4, 4vCPU, 16GB RAM, L4 GPU 0.1개 | 81.69 |
GCE-ai-moderation | 서울(asia-northeast3) | Compute Engine | Moderation 서버 (채팅 클린봇 서버) | e2-standard-2, 2vCPU, 8GB RAM, 10GB 디스크 | 64.05 |
3. 리소스 설명
- GCE-ai-embeded: 사용자 추천, 검색 임베딩 서비스용 CPU 서버
- GPU-ai (NVIDIA L4): 대형 LLM 기반 인퍼런스 처리용 GPU 서버 (90시간/월 가동)
- GCE-ai-moderation: 채팅 Moderation(클린봇) 처리용 경량 AI 서버
4. 총 월 예상 비용
총 월 예상 비용: 약 277.76 USD
(※ GCP 온디맨드 기준, 별도 할인 프로그램 적용 없음)