<CodeLearn/>
デプロイ レッスン5

デプロイ総合演習

Next.jsアプリをDocker化し、CI/CDパイプラインを構築してVercelにデプロイしよう

演習の概要

この総合演習では、Next.jsアプリケーションを本番環境にデプロイするまでの一連の流れを実践します。 Docker環境の構築、GitHub ActionsによるCI/CDパイプライン、Vercelへの本番デプロイ、 環境変数の設定、カスタムドメインの接続まで行います。

1Docker環境のセットアップ
2GitHub Actions CIパイプラインの構築
3Vercelへのデプロイ
4環境変数とドメインの設定

Step 1: Docker環境のセットアップ

まず、Next.jsアプリの開発環境をDockerで統一します。 Dockerfileとdocker-compose.ymlを作成しましょう。

# Dockerfile
FROM node:20-alpine AS base

# 依存関係のインストール
FROM base AS deps
RUN apk add --no-cache libc6-compat
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci

# ビルド
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .

# 環境変数(ビルド時に必要なもの)
ENV NEXT_TELEMETRY_DISABLED=1

RUN npm run build

# 本番イメージ
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 --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"]
# next.config.js にstandalone出力を追加
/** @type {import('next').NextConfig} */
const nextConfig = {
  output: "standalone",
};

module.exports = nextConfig;
# docker-compose.yml(開発環境用)
version: "3.8"

services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "3000:3000"
    environment:
      - DATABASE_URL=postgresql://postgres:postgres@db:5432/myapp
      - NEXT_PUBLIC_APP_URL=http://localhost:3000
    depends_on:
      db:
        condition: service_healthy

  db:
    image: postgres:16-alpine
    ports:
      - "5432:5432"
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
      POSTGRES_DB: myapp
    volumes:
      - db_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s
      timeout: 5s
      retries: 5

volumes:
  db_data:
# .dockerignore
node_modules
.next
.git
.gitignore
*.md
.env.local
.env*.local
docker-compose*.yml
.dockerignore
Dockerfile

# ビルドして起動
docker compose up --build
# http://localhost:3000 で確認

Step 2: GitHub Actions CIパイプライン

PRが作成されたら自動でリント・型チェック・テスト・ビルドを実行するCIワークフローを作成します。

# .github/workflows/ci.yml
name: CI

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

env:
  NODE_VERSION: "20"

jobs:
  lint-and-typecheck:
    name: Lint & Type Check
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: ${{ env.NODE_VERSION }}
          cache: "npm"

      - name: Install dependencies
        run: npm ci

      - name: Lint
        run: npm run lint

      - name: Type check
        run: npx tsc --noEmit

  test:
    name: Test
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: ${{ env.NODE_VERSION }}
          cache: "npm"

      - name: Install dependencies
        run: npm ci

      - name: Run tests
        run: npm test -- --coverage

      - name: Upload coverage
        uses: actions/upload-artifact@v4
        with:
          name: coverage
          path: coverage/
          retention-days: 7

  build:
    name: Build
    needs: [lint-and-typecheck, test]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: ${{ env.NODE_VERSION }}
          cache: "npm"

      - name: Install dependencies
        run: npm ci

      - name: Build
        run: npm run build

  docker:
    name: Docker Build
    needs: [lint-and-typecheck, test]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Build Docker image
        run: docker build -t my-nextjs-app .

      - name: Test Docker image
        run: |
          docker run -d -p 3000:3000 --name test-app my-nextjs-app
          sleep 5
          curl -f http://localhost:3000 || exit 1
          docker stop test-app

lint-and-typechecktestは並列実行され、 両方が成功した後にbuilddockerが実行されます。

Step 3: Vercelへのデプロイ

VercelにNext.jsアプリをデプロイする手順です。 GitHubリポジトリとの連携により、pushするだけで自動デプロイが動作します。

# 手順1: Vercel CLIのインストールとログイン
npm install -g vercel
vercel login

# 手順2: プロジェクトの初期設定
vercel link
# ? Set up "~/my-nextjs-app"? → Yes
# ? Which scope? → 自分のアカウントを選択
# ? Link to existing project? → No (新規作成)
# ? What's your project's name? → my-nextjs-app
# ? In which directory is your code located? → ./

# 手順3: 環境変数の設定
vercel env add DATABASE_URL production
# 値を入力: postgresql://user:password@host:5432/dbname

vercel env add NEXT_PUBLIC_APP_URL production
# 値を入力: https://my-nextjs-app.vercel.app

# 手順4: 本番デプロイ
vercel --prod

または、Vercelダッシュボード(vercel.com)からGitHubリポジトリをインポートすることもできます。 この方法が最も簡単で推奨されます。

# Vercel ダッシュボードからの設定手順

1. vercel.com にログイン
2. "Add New..." → "Project" をクリック
3. GitHubリポジトリを選択して "Import"
4. Framework Preset: Next.js(自動検出)
5. Environment Variables:
   - DATABASE_URL = postgresql://...
   - NEXT_PUBLIC_APP_URL = https://...
6. "Deploy" をクリック

# 以降、mainブランチへのpushで自動デプロイ
# PRを作成するとプレビューURLが自動生成

# プレビューデプロイのURL例:
# https://my-nextjs-app-abc123-username.vercel.app

Step 4: 環境変数とカスタムドメイン

本番環境の環境変数を適切に管理し、カスタムドメインを接続して公開しましょう。

# 環境変数の管理(環境ごとに分離)

# .env.local(開発環境 - Gitに含めない)
DATABASE_URL=postgresql://localhost:5432/myapp_dev
NEXT_PUBLIC_APP_URL=http://localhost:3000
API_SECRET_KEY=dev_secret_key

# Vercel(本番環境 - ダッシュボードで管理)
# Settings → Environment Variables で設定
#
# Production環境:
#   DATABASE_URL = postgresql://prod-host/myapp
#   API_SECRET_KEY = prod_secret_key_xxxxx
#
# Preview環境:
#   DATABASE_URL = postgresql://staging-host/myapp_staging
#   API_SECRET_KEY = staging_secret_key_xxxxx

# GitHub Actions(CI環境 - Secretsで管理)
# Settings → Secrets → Actions で設定
#   VERCEL_TOKEN
#   VERCEL_ORG_ID
#   VERCEL_PROJECT_ID
# カスタムドメインの設定

# 手順1: Vercelにドメインを追加
vercel domains add example.com

# 手順2: DNSレコードを設定
# ドメインレジストラ(お名前.com、Cloudflare等)で設定:
#
# Aレコード:
#   @ → 76.76.21.21
#
# CNAMEレコード:
#   www → cname.vercel-dns.com
#
# または、ネームサーバーをVercelに向ける:
#   ns1.vercel-dns.com
#   ns2.vercel-dns.com

# 手順3: SSL証明書(自動発行)
# Vercelがドメイン確認後、自動的にLet's Encrypt証明書を発行

# 手順4: 確認
vercel domains inspect example.com
# DNS: 設定済み
# SSL: 有効

DNSの反映には通常数分〜数時間かかります。vercel domains inspectコマンドで設定状態を確認できます。

本番運用チェックリスト

アプリを本番公開する前に、以下の項目を確認しましょう。

セキュリティ

  • 環境変数に秘密情報を格納(コードにハードコードしない)
  • HTTPSが有効であること
  • 不要なAPIエンドポイントに認証をかける
  • .env.localが.gitignoreに含まれている

パフォーマンス

  • 画像の最適化(next/imageを使用)
  • 不要なバンドルサイズの削除
  • 適切なキャッシュヘッダーの設定
  • Lighthouse スコアの確認

監視・ログ

  • エラー監視サービスの導入(Sentry等)
  • アクセスログの確認手段
  • アップタイム監視の設定

CI/CD

  • テストが自動実行されること
  • mainブランチへの直接pushを禁止(ブランチ保護)
  • PRレビューを必須に設定
  • デプロイの通知設定(Slack等)

まとめ

  • Dockerfileでマルチステージビルドを行い、軽量な本番イメージを作成する
  • docker-compose.ymlでアプリとDBを一括管理し、開発環境を統一する
  • GitHub Actionsでリント・テスト・ビルド・Docker確認を自動化する
  • VercelはGitHubと連携するだけでNext.jsの自動デプロイが完了する
  • 環境変数は環境ごとに分離し、秘密情報はコードに含めない
  • 本番公開前にセキュリティ・パフォーマンス・監視のチェックリストを確認する