diff --git a/docker/deploy/backend.Dockerfile b/docker/deploy/backend.Dockerfile new file mode 100644 index 00000000..c0b830ca --- /dev/null +++ b/docker/deploy/backend.Dockerfile @@ -0,0 +1,46 @@ +# syntax=docker/dockerfile:1 + +# Base image (Debian-based for glibc + OpenSSL compatibility) +FROM node:20-bookworm-slim AS base +WORKDIR /app +ENV NODE_ENV=production +# Install OpenSSL, curl (for healthcheck), and required certs +RUN apt-get update \ + && apt-get install -y --no-install-recommends openssl ca-certificates curl \ + && rm -rf /var/lib/apt/lists/* + +# Dependencies stage (install production dependencies) +FROM base AS deps +COPY package*.json ./ +RUN npm ci --omit=dev --prefer-offline --no-audit && npm cache clean --force + +# Build stage (compile TypeScript) +FROM node:20-bookworm-slim AS build +WORKDIR /app +COPY package*.json ./ +RUN npm ci --prefer-offline --no-audit && npm cache clean --force +COPY tsconfig.json ./ +COPY src ./src +RUN npm run build + +# Runtime image +FROM base AS runner +ENV NODE_ENV=production + +# Create non-root user +RUN groupadd -r appgroup && useradd -r -g appgroup appuser + +# Copy production node_modules +COPY --from=deps /app/node_modules ./node_modules +# Copy built files +COPY --from=build /app/dist ./dist +# Copy package files +COPY package*.json ./ + +# Create logs and uploads directories and set permissions +RUN mkdir -p logs uploads && chown -R appuser:appgroup logs uploads && chmod -R 755 logs uploads + +EXPOSE 3001 +USER appuser +CMD ["node", "dist/app.js"] + diff --git a/docker/deploy/docker-compose.yml b/docker/deploy/docker-compose.yml new file mode 100644 index 00000000..caa4eea7 --- /dev/null +++ b/docker/deploy/docker-compose.yml @@ -0,0 +1,59 @@ +version: "3.8" + +services: + # Node.js 백엔드 + backend: + build: + context: ../../backend-node + dockerfile: ../docker/deploy/backend.Dockerfile + container_name: pms-backend-prod + restart: always + environment: + NODE_ENV: production + PORT: "3001" + 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 + JWT_EXPIRES_IN: 24h + CORS_ORIGIN: https://v1.vexplor.com + CORS_CREDENTIALS: "true" + LOG_LEVEL: info + volumes: + - /home/vexplor/backend_data:/app/uploads + labels: + - traefik.enable=true + - traefik.http.routers.backend.rule=Host(`api.vexplor.com`) + - traefik.http.routers.backend.entrypoints=websecure,web + - traefik.http.routers.backend.tls=true + - traefik.http.routers.backend.tls.certresolver=le + - traefik.http.services.backend.loadbalancer.server.port=3001 + + # Next.js 프론트엔드 + frontend: + build: + context: ../../frontend + dockerfile: ../docker/deploy/frontend.Dockerfile + args: + - NEXT_PUBLIC_API_URL=https://api.vexplor.com + container_name: pms-frontend-prod + restart: always + environment: + NODE_ENV: production + NEXT_PUBLIC_API_URL: https://api.vexplor.com + NEXT_TELEMETRY_DISABLED: "1" + PORT: "3000" + HOSTNAME: 0.0.0.0 + volumes: + - /home/vexplor/frontend_data:/app/data + labels: + - traefik.enable=true + - traefik.http.routers.frontend.rule=Host(`v1.vexplor.com`) + - traefik.http.routers.frontend.entrypoints=websecure,web + - traefik.http.routers.frontend.tls=true + - traefik.http.routers.frontend.tls.certresolver=le + - traefik.http.services.frontend.loadbalancer.server.port=3000 + +networks: + default: + name: toktork_server_default + external: true diff --git a/docker/deploy/frontend.Dockerfile b/docker/deploy/frontend.Dockerfile new file mode 100644 index 00000000..794dcaf1 --- /dev/null +++ b/docker/deploy/frontend.Dockerfile @@ -0,0 +1,59 @@ +# Multi-stage build for Next.js +FROM node:18-alpine AS base + +# Install dependencies only when needed +FROM base AS deps +RUN apk add --no-cache libc6-compat +WORKDIR /app + +# Install dependencies +COPY package.json package-lock.json* ./ +RUN npm ci + +# Rebuild the source code only when needed +FROM base AS builder +WORKDIR /app +COPY --from=deps /app/node_modules ./node_modules +COPY . . + +# Disable telemetry during the build +ENV NEXT_TELEMETRY_DISABLED 1 + +# 빌드 시 환경변수 설정 (ARG로 받아서 ENV로 설정) +ARG NEXT_PUBLIC_API_URL=https://api.vexplor.com +ENV NEXT_PUBLIC_API_URL=$NEXT_PUBLIC_API_URL + +# Build the application +ENV DISABLE_ESLINT_PLUGIN=true +RUN npm run build + +# Production image, copy all the files and run next +FROM base AS runner +WORKDIR /app + +ENV NODE_ENV production +ENV NEXT_TELEMETRY_DISABLED 1 + +RUN addgroup --system --gid 1001 nodejs +RUN adduser --system --uid 1001 nextjs + +# Copy the Next.js build output +COPY --from=builder /app/public ./public + +# Production 모드에서는 .next 폴더 전체를 복사 +COPY --from=builder --chown=nextjs:nodejs /app/.next ./.next +COPY --from=builder --chown=nextjs:nodejs /app/package.json ./package.json + +# node_modules 복사 (production dependencies) +COPY --from=deps --chown=nextjs:nodejs /app/node_modules ./node_modules + +USER nextjs + +EXPOSE 3000 + +ENV PORT 3000 +ENV HOSTNAME "0.0.0.0" + +# Next.js start 명령어 사용 +CMD ["npm", "start"] + diff --git a/scripts/prod/deploy.sh b/scripts/prod/deploy.sh new file mode 100755 index 00000000..409ed04b --- /dev/null +++ b/scripts/prod/deploy.sh @@ -0,0 +1,53 @@ +#!/bin/bash + +# PMS 운영 환경 배포 스크립트 +# 사용법: ./docker/deploy/deploy.sh + +set -e + +# 프로젝트 루트로 이동 +cd "$(dirname "$0")/../.." + +# 도커 컴포즈 파일 경로 +COMPOSE_FILE="docker/deploy/docker-compose.yml" + +echo "======================================" +echo "PMS 운영 환경 배포" +echo "======================================" + +# Git 최신 코드 가져오기 +echo "" +echo "[1/5] Git 최신 코드 가져오기..." +git pull origin main + +# 기존 컨테이너 중지 및 제거 +echo "" +echo "[2/5] 기존 컨테이너 중지..." +docker-compose -f "$COMPOSE_FILE" down + +# 오래된 이미지 정리 +echo "" +echo "[3/5] Docker 이미지 정리..." +docker image prune -f + +# 새로운 이미지 빌드 +echo "" +echo "[4/5] Docker 이미지 빌드..." +docker-compose -f "$COMPOSE_FILE" build --no-cache + +# 컨테이너 실행 +echo "" +echo "[5/5] 컨테이너 실행..." +docker-compose -f "$COMPOSE_FILE" up -d + +# 배포 완료 +echo "" +echo "======================================" +echo "배포 완료!" +echo "======================================" +echo "" +echo "Frontend: https://v1.vexplor.com" +echo "Backend: https://api.vexplor.com" +echo "" +docker-compose -f "$COMPOSE_FILE" ps +echo ""