[STK9-02] Dockerfile + 프로덕션 docker-compose
작업 내용 (설계 의도)
변경 사항
백엔드와 프론트엔드를 Docker 이미지로 패키징하고, 프로덕션 배포용 docker-compose를 신설한다. 기존 docker-compose.yml(개발 환경, MySQL만)은 변경하지 않는다.
backend/Dockerfile: eclipse-temurin:21-jre-alpine 기반. Gradle 빌드 결과물(*.jar)을 COPY해 실행. 빌드는 CI/CD에서 수행하므로 multi-stage 빌드 불필요.
frontend/Dockerfile: Multi-stage 빌드.
- Stage 1 (builder):
node:20-alpine,npm ci,next build - Stage 2 (runner):
node:20-alpine, standalone 결과물만 복사 next.config.ts에output: 'standalone'추가 필수
docker-compose.prod.yml: 3개 서비스(mysql, backend, frontend). 환경변수는 .env 파일 또는 서버 환경변수로 주입. mysql에 healthcheck 포함, backend는 mysql healthy 후 기동.
다이어그램
컨테이너 구성
flowchart LR FE[frontend :3000] --> BE[backend :8080] BE --> DB[mysql :3306] subgraph docker-compose.prod.yml FE BE DB end
테스트 케이스
docker build -f backend/Dockerfile backend/가 오류 없이 성공한다docker build -f frontend/Dockerfile frontend/가 오류 없이 성공한다docker-compose -f docker-compose.prod.yml up -d로 3개 컨테이너가 모두 healthy 상태가 된다curl http://localhost:8080/actuator/health가 200을 반환한다curl http://localhost:3000이 Next.js 페이지를 반환한다- frontend standalone 빌드 후
node server.js가 오류 없이 기동된다 next.config.ts에output: 'standalone'없을 때 빌드 실패를 확인하고 설정 추가 후 통과된다
docker-compose.prod.yml 참고
services:
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: stock
TZ: Asia/Seoul
volumes:
- stock-mysql-prod-data:/var/lib/mysql
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-uroot", "-p${MYSQL_ROOT_PASSWORD}"]
interval: 5s
timeout: 3s
retries: 20
backend:
image: ghcr.io/biuea3866/stock-backend:latest
environment:
SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/stock
SPRING_DATASOURCE_USERNAME: root
SPRING_DATASOURCE_PASSWORD: ${MYSQL_ROOT_PASSWORD}
TZ: Asia/Seoul
ports:
- "8080:8080"
depends_on:
mysql:
condition: service_healthy
frontend:
image: ghcr.io/biuea3866/stock-frontend:latest
environment:
NEXT_PUBLIC_API_URL: http://localhost:8080
ports:
- "3000:3000"
depends_on:
- backend
volumes:
stock-mysql-prod-data: