posts

local

Oct 1, 2025 updated Oct 1, 2025 adminarchitecturedockerexpo

아래는 여러분의 Next.js 프로젝트를 로컬에서 빌드 후 EC2(또는 원격)와 내 로컬 Docker 환경에서 각각 배포할 수 있도록 준비한 파일 구성 및 배포 프로세스 예시입니다.

전체 배포 프로세스는 아래와 같이 진행됩니다.

  1. 필요한 파일 준비 • 프로덕션용 빌드를 위한 멀티 스테이지 Dockerfile • 개발/QA용(EC2) 배포를 위한 Compose 파일 (docker-compose.dev.yml) • 내 로컬 테스트용 Compose 파일 (docker-compose.local.yml) • (이미 준비된) 프로덕션용 Compose 파일 (docker-compose.prod.yml) • 배포 스크립트(예: deploy.sh): 로컬에서 빌드, Docker 이미지 생성 → tar 파일로 저장 → SCP 전송 → EC2에서 컨테이너 재시작
  2. 로컬 빌드 • Next.js 애플리케이션을 프로덕션 또는 개발 모드로 빌드 • Docker 이미지를 생성하고, 필요 시 tar 파일로 저장
  3. EC2에 Docker 이미지 배포 • SCP를 통해 tar 파일과 해당 docker-compose 파일을 전송
  4. EC2에서 컨테이너 시작 • 원격 서버에서 기존 컨테이너를 종료한 후 새로운 이미지를 로드 및 docker-compose로 실행

아래에 각 환경별로 사용할 파일들을 상세히 정리했습니다.

A. Dockerfile (프로덕션용 멀티 스테이지 빌드)

파일명: Dockerfile

용도: 프로덕션 배포용 이미지 생성 특징: Next.js를 next build로 빌드한 후 Standalone 모드 출력물을 포함하여 불필요한 파일을 제거

syntax=docker/dockerfile:1

1단계: 빌드 단계

FROM node:18-alpine AS builder

WORKDIR /app

의존성 파일 복사 (yarn, npm, pnpm 중 사용 중인 것을 자동 감지)

COPY package.json package-lock.json* yarn.lock* pnpm-lock.yaml* ./

의존성 설치

RUN if [ -f yarn.lock ]; then yarn install --frozen-lockfile;
elif [ -f package-lock.json ]; then npm ci;
elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm install;
else echo "No lockfile found, installing via yarn" && yarn install; fi

프로젝트 전체 소스 복사

COPY . .

Next.js 프로덕션 빌드 실행

RUN npm run build

2단계: 런타임 단계 (프로덕션 실행 이미지)

FROM node:18-alpine AS runner

WORKDIR /app

보안을 위해 비 root 사용자 생성

RUN addgroup --system --gid 1001 nodejs &&
adduser --system --uid 1001 nextjs USER nextjs

Standalone output 모드 사용: 빌드 산출물 중 필요한 부분만 복사

COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static COPY --from=builder --chown=nextjs:nodejs /app/public ./public COPY --from=builder --chown=nextjs:nodejs /app/package.json ./

EXPOSE 3000

컨테이너 시작 시 Standalone 서버 실행 (빌드 산출물에 server.js 포함)

CMD ["node", "server.js"]

참고:

next.config.ts 파일에 아래와 같이 설정되어 있어야 합니다.

B. Dockerfile.dev (개발/로컬용)

파일명: Dockerfile.dev

용도: 개발 및 내 로컬 Docker 테스트용 이미지 생성 특징: 전체 소스를 복사하여 hot-reload 가능한 개발 서버(예: npm run dev)를 실행   (볼륨 마운트를 통해 코드 변경을 바로 반영할 수 있음)

syntax=docker/dockerfile:1

FROM node:18-alpine

WORKDIR /app

의존성 파일 복사

COPY package.json package-lock.json* yarn.lock* pnpm-lock.yaml* ./

의존성 설치

RUN if [ -f yarn.lock ]; then yarn install;
elif [ -f package-lock.json ]; then npm install;
elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm install;
else echo "No lockfile found, installing via yarn" && yarn install; fi

소스 전체 복사 (개발 시 코드 수정 반영을 위해)

COPY . .

EXPOSE 3000

개발 모드 실행

CMD ["npm", "run", "dev"]

C. Docker Compose 파일들

  1. 프로덕션용 Compose

    파일명: docker-compose.prod.yml 용도: EC2 등 실제 운영 환경에서 프로덕션 빌드 이미지로 컨테이너 실행

version: '3.8'

services: next-app: container_name: next-app-prod build: context: . dockerfile: Dockerfile environment: NODE_ENV: production ports:

  • "3000:3000" restart: always networks:
  • app-network

networks: app-network: driver: bridge

  1. 개발/QA용 Compose (EC2 배포 – QA 검수용)

    파일명: docker-compose.dev.yml 용도: QA 검수를 위한 환경으로, 프로덕션 빌드(즉, Dockerfile 사용)를 그대로 사용하되 환경 변수나 컨테이너 이름 등으로 구분

version: '3.8'

services: next-app: container_name: next-app-dev build: context: . dockerfile: Dockerfile environment: NODE_ENV: development # QA 검수용으로 개발 환경 변수 사용 가능 (필요에 따라 "qa"로 설정) ports:

  • "3000:3000" restart: always networks:
  • app-network

networks: app-network: driver: bridge

  1. 로컬 테스트용 Compose (내 로컬 Docker에서 실행)

    파일명: docker-compose.local.yml 용도: EC2 없이 내 로컬 Docker 환경에서 개발 서버(Hot Reload) 실행 특징: Dockerfile.dev를 사용하며, 소스 코드를 볼륨으로 마운트하여 실시간 변경 반영

version: '3.8'

services: next-app: container_name: next-app-local build: context: . dockerfile: Dockerfile.dev environment: NODE_ENV: development ports:

  • "3000:3000" volumes:
  • ./:/app # 로컬 소스 전체를 컨테이너에 마운트
  • /app/node_modules # node_modules는 컨테이너 내부에서 관리 (호스트와의 충돌 방지) restart: always networks:
  • app-network

networks: app-network: driver: bridge

D. 배포 스크립트 (예: Production 배포용 deploy.sh)

프로덕션(또는 QA) 배포 시, 로컬에서 빌드한 후 Docker 이미지를 tar 파일로 저장하고, SCP로 EC2에 전송한 후 EC2에서 컨테이너를 재시작하는 방식입니다.

파일명: deploy.sh

#!/bin/bash set -e

-------------------------

변수 설정 (필요에 따라 수정)

-------------------------

APP_NAME="my-nextjs-app" VERSION="latest" # 또는 버전 파일에서 읽어올 수 있음. LOCAL_IMAGE_NAME="${APP_NAME}:${VERSION}" REMOTE_IMAGE_PATH="/home/ec2-user/${APP_NAME}.tar"

배포할 docker-compose 파일을 선택: 프로덕션은 docker-compose.prod.yml, QA는 docker-compose.dev.yml

DOCKER_COMPOSE_PATH="/home/ec2-user/docker-compose.prod.yml" PEM_FILE=".pem" # EC2 접속용 PEM 파일 DEPLOY_USER="ec2-user"

EC2 호스트 (예시: 운영 서버)

EC2_HOST=""

-------------------------

1. 로컬 빌드 및 Docker 이미지 생성

-------------------------

echo "==== Next.js 프로덕션 빌드 시작 ====" npm run build || { echo "Next.js 빌드 실패"; exit 1; } echo "==== Next.js 빌드 완료 ===="

echo "==== Docker 이미지 빌드 (프로덕션) ====" docker build -t "$LOCAL_IMAGE_NAME" -f Dockerfile . echo "==== Docker 이미지 빌드 완료 ===="

-------------------------

2. Docker 이미지 tar 파일로 저장

-------------------------

echo "==== Docker 이미지 tar 파일로 저장 중 ====" docker save -o "${APP_NAME}.tar" "$LOCAL_IMAGE_NAME" echo "==== 이미지 저장 완료: ${APP_NAME}.tar ===="

-------------------------

3. EC2에 파일 전송 (이미지 tar와 선택한 docker-compose 파일)

-------------------------

echo "==== EC2에 파일 전송 시작 ====" scp -i "$PEM_FILE" "${APP_NAME}.tar" "$DEPLOY_USER@$EC2_HOST:$REMOTE_IMAGE_PATH" scp -i "$PEM_FILE" "$(basename $DOCKER_COMPOSE_PATH)" "$DEPLOY_USER@$EC2_HOST:$DOCKER_COMPOSE_PATH" echo "==== 파일 전송 완료 ===="

로컬에 생성된 tar 파일 삭제 (선택 사항)

rm "${APP_NAME}.tar"

-------------------------

4. EC2에서 이미지 로드 및 컨테이너 재시작

-------------------------

echo "==== EC2에서 배포 실행 ====" ssh -i "$PEM_FILE" "$DEPLOY_USER@$EC2_HOST" << 'EOF' set -e echo "==== 기존 컨테이너 종료 ====" docker-compose -f docker-compose.prod.yml down || true

echo "==== 기존 이미지 삭제 ====" docker images --filter=reference='my-nextjs-app:*' --format "{{.ID}}" | xargs -r docker rmi -f

echo "==== Docker 이미지 로드 중 ====" docker load -i /home/ec2-user/my-nextjs-app.tar

echo "==== Docker Compose 실행 ====" docker-compose -f docker-compose.prod.yml up -d

echo "==== 불필요한 Docker 리소스 정리 ====" docker system prune -f || true EOF

echo "==== 배포 완료 ===="

참고:
	•	QA용 배포 시 DOCKER_COMPOSE_PATH 값을 docker-compose.dev.yml로 변경하여 사용하면 됩니다.
•	로컬에서 직접 테스트할 때는 docker-compose.local.yml을 이용하여 docker-compose -f docker-compose.local.yml up --build 명령어로 실행합니다.

배포 프로세스 요약

  1. 필요한 파일 생성 • Dockerfile (프로덕션용)와 Dockerfile.dev (개발/로컬용) • docker-compose.prod.yml (운영), docker-compose.dev.yml (QA 검수용), docker-compose.local.yml (내 로컬 테스트용) • deploy.sh 스크립트 (프로덕션/QA 배포 자동화)
  2. 로컬 빌드 • 프로덕션 배포 시: npm run build → docker build -t my-nextjs-app:latest -f Dockerfile . • 개발/로컬 테스트 시: docker-compose -f docker-compose.local.yml up --build
  3. EC2에 Docker 이미지 배포 (프로덕션/QA) • deploy.sh 스크립트로 이미지 tar 파일 생성 → SCP로 EC2 전송
  4. EC2에서 컨테이너 시작 • SSH 접속 후, 기존 컨테이너 종료, 이미지 로드, docker-compose up 명령으로 컨테이너 재시작

이와 같이 구성하면, 여러분은 프로덕션, QA(개발), 그리고 내 로컬 테스트 환경에 맞게 배포 프로세스를 분리하여 관리할 수 있습니다.