[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.tsoutput: '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.tsoutput: '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: