# ========================== # 멀티 스테이지 Dockerfile # - 백엔드: Node.js + Express + TypeScript # - 프론트엔드: Next.js (프로덕션 빌드) # ========================== # ------------------------------ # Stage 1: 백엔드 빌드 # ------------------------------ FROM node:20.10-alpine AS backend-builder WORKDIR /app/backend # 백엔드 의존성 설치 COPY backend-node/package*.json ./ RUN npm ci --only=production && \ npm cache clean --force # 백엔드 소스 복사 및 빌드 COPY backend-node/tsconfig.json ./ COPY backend-node/src ./src RUN npm install -D typescript @types/node && \ npm run build && \ npm prune --production # ------------------------------ # 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 ENV NEXT_PUBLIC_API_URL="https://logistream.kpslp.kr/api" RUN npm run build:no-lint # ------------------------------ # Stage 3: 최종 런타임 이미지 # ------------------------------ FROM node:20.10-alpine AS runtime # 보안 강화: 비특권 사용자 생성 RUN addgroup -g 1001 -S nodejs && \ adduser -S nodejs -u 1001 WORKDIR /app # 백엔드 런타임 파일 복사 COPY --from=backend-builder --chown=nodejs:nodejs /app/backend/dist ./backend/dist COPY --from=backend-builder --chown=nodejs:nodejs /app/backend/node_modules ./backend/node_modules COPY --from=backend-builder --chown=nodejs:nodejs /app/backend/package.json ./backend/package.json # 프론트엔드 런타임 파일 복사 COPY --from=frontend-builder --chown=nodejs:nodejs /app/frontend/.next ./frontend/.next COPY --from=frontend-builder --chown=nodejs:nodejs /app/frontend/node_modules ./frontend/node_modules COPY --from=frontend-builder --chown=nodejs:nodejs /app/frontend/package.json ./frontend/package.json COPY --from=frontend-builder --chown=nodejs:nodejs /app/frontend/public ./frontend/public COPY --from=frontend-builder --chown=nodejs:nodejs /app/frontend/next.config.mjs ./frontend/next.config.mjs # 백엔드 디렉토리 생성 (업로드, 로그, 데이터) # /app/uploads, /app/data 경로는 백엔드 코드에서 동적으로 하위 디렉토리 생성 # 상위 디렉토리에 쓰기 권한 부여하여 런타임에 자유롭게 생성 가능하도록 함 RUN mkdir -p /app/backend/uploads /app/backend/logs /app/backend/data \ /app/uploads /app/data && \ chown -R nodejs:nodejs /app/backend /app/uploads /app/data && \ chmod -R 777 /app/uploads /app/data && \ chmod -R 755 /app/backend # 프론트엔드 standalone 모드를 위한 디렉토리 생성 RUN mkdir -p /app/frontend/data && \ chown -R nodejs:nodejs /app/frontend && \ chmod -R 755 /app/frontend # 시작 스크립트 생성 RUN echo '#!/bin/sh' > /app/start.sh && \ echo 'set -e' >> /app/start.sh && \ echo '' >> /app/start.sh && \ echo '# 백엔드 시작 (백그라운드)' >> /app/start.sh && \ echo 'cd /app/backend' >> /app/start.sh && \ echo 'echo "Starting backend on port 8080..."' >> /app/start.sh && \ echo 'PORT=8080 node dist/app.js &' >> /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 'PORT=3000 exec npm start' >> /app/start.sh && \ chmod +x /app/start.sh && \ chown nodejs:nodejs /app/start.sh # ============================================================ # 환경변수 설정 (임시 조치) # helm-charts의 values_logistream.yaml 관리자가 설정 완료 시 삭제 예정 # ============================================================ ENV NODE_ENV=production \ LOG_LEVEL=info \ HOST=0.0.0.0 \ DATABASE_URL="postgresql://postgres:ph0909!!@39.117.244.52:11132/plm" \ JWT_SECRET="ilshin-plm-super-secret-jwt-key-2024" \ ENCRYPTION_KEY="ilshin-plm-mail-encryption-key-32characters-2024-secure" \ JWT_EXPIRES_IN="24h" \ CORS_CREDENTIALS="true" \ CORS_ORIGIN="https://logistream.kpslp.kr" \ KMA_API_KEY="ogdXr2e9T4iHV69nvV-IwA" \ ITS_API_KEY="d6b9befec3114d648284674b8fddcc32" \ NEXT_TELEMETRY_DISABLED="1" \ NEXT_PUBLIC_API_URL="https://logistream.kpslp.kr/api" # 비특권 사용자로 전환 USER nodejs # 포트 노출 EXPOSE 3000 8080 # 헬스체크 (백엔드와 프론트엔드 둘 다 확인) HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \ CMD wget --no-verbose --tries=1 --spider http://localhost:8080/api/health && \ wget --no-verbose --tries=1 --spider http://localhost:3000/ || exit 1 # 컨테이너 시작 CMD ["/app/start.sh"]