# ========================== # 멀티 스테이지 Dockerfile # - 백엔드: Spring Boot (Java 21) # - 프론트엔드: Next.js (프로덕션 빌드) # ========================== # ------------------------------ # Stage 1: 백엔드 빌드 (Spring Boot) # ------------------------------ FROM eclipse-temurin:21-jdk-alpine AS backend-builder WORKDIR /app/backend # Gradle Wrapper 복사 COPY backend-spring/gradlew ./ COPY backend-spring/gradle ./gradle RUN chmod +x gradlew # 의존성 캐싱 COPY backend-spring/build.gradle backend-spring/settings.gradle ./ RUN ./gradlew dependencies --no-daemon || true # 소스 복사 및 빌드 COPY backend-spring/src ./src RUN ./gradlew bootJar --no-daemon # ------------------------------ # Stage 2: 프론트엔드 빌드 # ------------------------------ FROM node:20.10-alpine AS frontend-builder WORKDIR /app/frontend # 프론트엔드 의존성 설치 COPY frontend/package*.json ./ RUN npm ci && \ npm cache clean --force # 프론트엔드 소스 복사 COPY frontend/ ./ # Next.js 프로덕션 빌드 (린트 비활성화) ENV NEXT_TELEMETRY_DISABLED=1 ENV NODE_ENV=production RUN npm run build:no-lint # ------------------------------ # Stage 3: 최종 런타임 이미지 # ------------------------------ FROM eclipse-temurin:21-jre-alpine AS runtime RUN apk add --no-cache curl nodejs npm # 비특권 사용자 생성 RUN addgroup -g 1001 -S appgroup && \ adduser -S appuser -u 1001 -G appgroup WORKDIR /app # 백엔드 JAR 복사 COPY --from=backend-builder --chown=appuser:appgroup /app/backend/build/libs/*.jar ./backend/app.jar # 프론트엔드 런타임 파일 복사 COPY --from=frontend-builder --chown=appuser:appgroup /app/frontend/.next ./frontend/.next COPY --from=frontend-builder --chown=appuser:appgroup /app/frontend/node_modules ./frontend/node_modules COPY --from=frontend-builder --chown=appuser:appgroup /app/frontend/package.json ./frontend/package.json COPY --from=frontend-builder --chown=appuser:appgroup /app/frontend/public ./frontend/public COPY --from=frontend-builder --chown=appuser:appgroup /app/frontend/next.config.mjs ./frontend/next.config.mjs # 업로드 디렉토리 생성 RUN mkdir -p /app/backend/uploads /app/backend/logs && \ chown -R appuser:appgroup /app # 시작 스크립트 생성 RUN echo '#!/bin/sh' > /app/start.sh && \ echo 'set -e' >> /app/start.sh && \ echo '' >> /app/start.sh && \ echo '# Spring Boot 백엔드 시작 (백그라운드)' >> /app/start.sh && \ echo 'cd /app/backend' >> /app/start.sh && \ echo 'echo "Starting Spring Boot backend on port 8081..."' >> /app/start.sh && \ echo 'java -jar app.jar &' >> /app/start.sh && \ echo 'BACKEND_PID=$!' >> /app/start.sh && \ echo '' >> /app/start.sh && \ echo '# 프론트엔드 시작 (포그라운드)' >> /app/start.sh && \ echo 'cd /app/frontend' >> /app/start.sh && \ echo 'echo "Starting frontend on port 3000..."' >> /app/start.sh && \ echo 'npm start &' >> /app/start.sh && \ echo 'FRONTEND_PID=$!' >> /app/start.sh && \ echo '' >> /app/start.sh && \ echo '# 프로세스 모니터링' >> /app/start.sh && \ echo 'wait $BACKEND_PID $FRONTEND_PID' >> /app/start.sh && \ chmod +x /app/start.sh && \ chown appuser:appgroup /app/start.sh USER appuser # 포트 노출 EXPOSE 3000 8081 # 헬스체크 HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \ CMD wget --no-verbose --tries=1 --spider http://localhost:3000/api/health || exit 1 # 컨테이너 시작 CMD ["/app/start.sh"]