포스트

[이제와서 시작하는 Next.js 마스터하기 #11] 배포 전략과 CI/CD

[이제와서 시작하는 Next.js 마스터하기 #11] 배포 전략과 CI/CD

“로컬에서 프로덕션까지!” - 클릭 몇 번으로 전 세계에 배포하세요!

🎯 이 글에서 배울 내용

  • Vercel로 빠른 배포
  • Docker 컨테이너화
  • GitHub Actions CI/CD
  • 환경 변수 관리
  • 성능 모니터링

예상 소요 시간: 45분


🚀 Vercel 배포 (가장 쉬움)

Next.js 앱은 Vercel, Node.js 서버, Docker 컨테이너, static export, 어댑터 기반 플랫폼 등 여러 방식으로 배포할 수 있습니다. 처음에는 Vercel Git 연동이 가장 단순하고, 인프라 제어가 더 필요해지면 Docker나 직접 호스팅을 검토하면 됩니다.

방식 장점 주의할 점
Vercel Git 연동 PR Preview, 자동 배포, Next.js 최적화 플랫폼 설정 의존
Node.js 서버 모든 Next.js 기능 사용 가능 서버 운영과 프로세스 관리 필요
Docker 실행 환경 재현성 높음 이미지 크기와 보안 패치 관리 필요
Static export CDN 배포 쉬움 서버 기능 제한

1. GitHub 연결

  1. vercel.com 가입
  2. “New Project” 클릭
  3. GitHub 레포지토리 선택
  4. “Deploy” 클릭
  5. 완료! 🎉

자동 배포:

  • main 브랜치 푸시 → 자동 배포
  • PR 생성 → 미리보기 URL 생성

Git 연동을 쓰면 보통 별도 GitHub Actions 배포 워크플로우가 필요 없습니다. PR마다 Preview Deployment가 생기고, Production Branch에 머지하면 프로덕션 도메인으로 반영됩니다.

2. 환경 변수 설정

Vercel 대시보드에서:

1
2
3
4
5
Settings → Environment Variables

DATABASE_URL=your-database-url
AUTH_SECRET=your-secret
AUTH_GOOGLE_ID=your-google-id

환경 변수는 Preview, Production, Development 범위를 구분해서 설정하세요. 로컬 .env.local 값과 Vercel 대시보드 값이 다르면 “로컬에서는 되는데 배포 후 실패”하는 일이 생깁니다.

3. 도메인 연결

1
2
3
4
Settings → Domains
→ Add Domain
→ 도메인 입력 (예: mysite.com)
→ DNS 설정 완료

배포가 성공했다고 바로 끝난 것은 아닙니다. Production 도메인에서 로그인, API, 이미지, 캐시 동작을 직접 확인해야 합니다.


🐳 Docker 배포

1. Dockerfile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# Dockerfile
FROM node:22-alpine AS base

# Dependencies
FROM base AS deps
RUN apk add --no-cache libc6-compat
WORKDIR /app

COPY package.json package-lock.json* ./
RUN npm ci

# Builder
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .

RUN npm run build

# Runner
FROM base AS runner
WORKDIR /app

ENV NODE_ENV production

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

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

USER nextjs

EXPOSE 3000

ENV PORT 3000
ENV HOSTNAME "0.0.0.0"

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

output: 'standalone'을 사용하면 Next.js가 실행에 필요한 파일을 .next/standalone에 모아줍니다. Docker 이미지 크기를 줄이는 데 유용하지만, public.next/static은 별도로 복사해야 합니다.

2. next.config.js

1
2
3
4
// next.config.js
module.exports = {
  output: 'standalone',
};

3. 빌드 및 실행

1
2
3
4
5
6
7
8
# 이미지 빌드
docker build -t my-nextjs-app .

# 컨테이너 실행
docker run -p 3000:3000 \
  -e DATABASE_URL="your-db-url" \
  -e AUTH_SECRET="your-secret" \
  my-nextjs-app

4. docker-compose.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
version: '3.8'

services:
  app:
    build: .
    ports:
      - "3000:3000"
    environment:
      - DATABASE_URL=postgresql://user:password@db:5432/mydb
      - AUTH_SECRET=your-secret
    depends_on:
      - db

  db:
    image: postgres:15-alpine
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: password
      POSTGRES_DB: mydb
    volumes:
      - postgres_data:/var/lib/postgresql/data

volumes:
  postgres_data:
1
2
# 실행
docker-compose up -d

운영 환경에서는 compose 파일에 비밀 값을 직접 쓰지 말고 .env나 배포 플랫폼의 secret manager를 사용하세요. 또한 컨테이너 이미지는 base image 보안 업데이트를 주기적으로 확인해야 합니다.


🔄 GitHub Actions CI/CD

1. 테스트 및 빌드

name: CI

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '22'
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Run linter
        run: npm run lint

      - name: Run tests
        run: npm test

      - name: Build
        run: npm run build

이 워크플로우는 배포 전 품질 게이트 역할을 합니다. Vercel Git 연동을 사용한다면 여기서 배포까지 하지 않아도 됩니다. CI가 실패하면 PR을 머지하지 않는 방식으로 운영하면 충분합니다.

2. Vercel CLI 배포

name: Deploy to Vercel

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '22'
          cache: 'npm'

      - name: Install Vercel CLI
        run: npm install --global vercel@latest

      - name: Pull Vercel Environment
        run: vercel pull --yes --environment=production --token=${{ secrets.VERCEL_TOKEN }}

      - name: Build
        run: vercel build --prod --token=${{ secrets.VERCEL_TOKEN }}

      - name: Deploy
        run: vercel deploy --prebuilt --prod --token=${{ secrets.VERCEL_TOKEN }}

Vercel 공식 흐름은 CLI로 환경을 pull하고, vercel build, vercel deploy --prebuilt를 나누는 방식입니다. GitHub Enterprise Server처럼 Vercel의 기본 Git 연동을 쓰기 어려운 환경이나, CI에서 빌드 산출물을 먼저 검증해야 하는 팀에 적합합니다.

일반 GitHub 저장소라면 먼저 Vercel Git 연동을 검토하세요. Actions 배포는 필요한 이유가 있을 때만 추가하는 편이 운영이 단순합니다.


🔐 환경 변수 관리

1. .env 파일 구조

1
2
3
.env                  # 로컬 개발 (git ignore)
.env.example          # 예시 파일 (git 포함)
.env.production       # 프로덕션 (git ignore)

2. .env.example

# Database
DATABASE_URL="postgresql://..."

# Authentication
AUTH_URL="http://localhost:3000"
AUTH_SECRET="generate-a-secret-key"

# OAuth
AUTH_GOOGLE_ID="your-client-id"
AUTH_GOOGLE_SECRET="your-client-secret"

브라우저에서 접근해야 하는 값만 NEXT_PUBLIC_ 접두사를 붙입니다.

NEXT_PUBLIC_APP_URL="https://example.com"

NEXT_PUBLIC_이 붙은 값은 클라이언트 번들에 포함될 수 있으므로 비밀 키를 넣으면 안 됩니다. DATABASE_URL, AUTH_SECRET, OAuth client secret은 서버 전용 환경 변수로 유지하세요.

3. 환경별 설정

1
2
3
4
5
6
7
8
9
10
11
// lib/config.ts
const config = {
  development: {
    apiUrl: 'http://localhost:3000/api',
  },
  production: {
    apiUrl: 'https://mysite.com/api',
  },
};

export default config[process.env.NODE_ENV || 'development'];

런타임마다 바뀌어야 하는 값은 서버 코드에서 process.env로 읽고, 빌드 시점에 고정되어도 되는 공개 값만 클라이언트에 노출하는 기준을 세우면 안전합니다.


📊 성능 모니터링

1. Vercel Analytics

1
2
3
4
5
6
7
8
9
10
11
12
13
// app/layout.js
import { Analytics } from '@vercel/analytics/react';

export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        {children}
        <Analytics />
      </body>
    </html>
  );
}

2. 성능 체크리스트

1
2
3
4
5
6
# Lighthouse 점수 확인
npm install -g lighthouse
lighthouse https://mysite.com --view

# Bundle 크기 분석
npm install -g @next/bundle-analyzer

✅ 배포 후 확인 체크리스트

배포 직후에는 아래 항목을 실제 Production URL에서 확인하세요.

  • 핵심 페이지가 200으로 응답하는가
  • 로그인, 로그아웃, 세션 만료가 정상인가
  • 서버 액션/API Route가 환경 변수를 제대로 읽는가
  • 이미지와 정적 파일이 깨지지 않는가
  • 새 배포 후 이전 클라이언트와 API가 충돌하지 않는가
  • 에러 로그와 성능 지표를 확인할 수 있는가

배포는 “빌드 성공”이 아니라 “사용자가 정상 흐름을 끝까지 수행할 수 있음”으로 판단해야 합니다.


🎯 오늘 배운 내용 정리

  1. Vercel 배포
    • GitHub 연결
    • 자동 배포
    • 환경 변수
  2. Docker
    • 컨테이너화
    • docker-compose
  3. CI/CD
    • GitHub Actions
    • 자동 테스트 및 배포
    • Vercel Git 연동과 CLI 배포 구분
  4. 운영 점검
    • 환경 변수 노출 범위 확인
    • Production URL에서 핵심 흐름 검증

📚 시리즈 네비게이션


“배포는 시작일 뿐입니다!” 🚀

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.