言語を切り替える
テーマを切り替える

Next.js CI/CD 実践ガイド:GitHub Actions で実現する自動テストとデプロイ

ターミナルに流れるログを見つめながら、機械的に git pull && npm install && npm run build && pm2 restart と打っていた。今日だけで3回目のデプロイだ——午前は小さなバグ修正、昼は API の最適化、今はスタイルを少し直しただけ。サーバーは3台あり、どれも同じ作業を繰り返す。

最後の1台を終えたとき、時計はすでに7時を回っていた。

その日の帰り道で考えていた。もっと良い方法があるはずだ。コードを直すたびにサーバーで同じ作業を繰り返したくないし、再起動し忘れたサーバーが本番に残る心配もしたくない。テストを忘れてデプロイし、後からバグを見つけてやり直す——そんなこともよくあった。

その後 CI/CD と GitHub Actions に出会い、ワークフローは一変した。GitHub に push するだけで、テスト・ビルド・デプロイまで全部自動だ。コーヒーを淹れているあいだに、新バージョンが公開される。

手動デプロイに苦しんでいるなら、次に GitHub Actions で Next.js の自動デプロイをどう組むかを共有します。基本設定から実践例、私が踏んだ坑と対処まで全部書きます。

なぜ CI/CD が必要なのか

手動デプロイの苦しみ

私が Next.js プロジェクトを始めたばかりの頃、デプロイの手順はこんな感じでした:ローカルでコードを書き、テストし、SSH でサーバーにログインし、git pull でコードを引っぱり、npm install で依存関係を入れ、npm run build でビルドし、最後に pm2 restart でサービスを再起動。順調にいっても十数分はかかります。

しかし、現実はそう順調ではありません。

ある時、3台のサーバーにデプロイしていたのですが、最初の2台は成功したものの、3台目は SSH 接続が切れていて更新されていないことに気づきませんでした。翌日、ユーザーから「サイトが新しいバージョンだったり古いバージョンだったりする」というフィードバックが来ました。ロードバランサーが更新されていないサーバーにリクエストを振り分けていたのです。またある時は、コード修正に興奮してテストをすっ飛ばしてデプロイし、致命的なバグを本番環境に送り込んでしまい、冷や汗をかきながら緊急ロールバックしたこともあります。

さらに厄介なのが、複数サーバーでのビルド問題です。Next.js はビルドごとに新しい build ID を生成します。3台のサーバーでそれぞれビルドすると、ID がバラバラになってしまいます。ロードバランサーがユーザーのリクエストを異なるサーバーに振り分けると、Next.js は ID の変化を検知してハードリフレッシュ(完全な再読み込み)をトリガーしてしまいます。ユーザー体験は最悪です。

CI/CD は何を解決するのか

要するに、CI/CD はこれらの反復的でエラーが発生しやすいプロセスを自動化します。

**CI(継続的インテグレーション)**はテストを担当します。コードをプッシュするたびに、自動的にテスト(単体テスト、型チェック、コード規約チェック)を実行します。テストが通らなければデプロイされません。これにより、バグのあるコードが本番環境に出るのを防げます。

**CD(継続的デプロイ)**はビルドとデプロイを担当します。テストが通れば、自動的にビルドを開始し、完了したらサーバーにデプロイします。この間、指一本動かす必要はありません。

実際の効果は? 私の現在のワークフローはこうです:ローカルでコードを書く → GitHub にプッシュ → 自動テスト → 自動ビルド → 自動デプロイ。プッシュしてから公開まで約5分。その間監視する必要もありません。水を飲みに行って戻ってくれば、新バージョンが公開されています。

もう一つの利点は追跡可能性です。各デプロイには完全なログが残り、どのコミットがトリガーしたか、テスト結果はどうだったか、どのサーバーにデプロイされたかが一目瞭然です。問題が起きてもすぐに原因を特定でき、手探りで調べる必要がありません。

GitHub Actions 基礎設定

仕組みを理解する

GitHub Actions に初めて触れた時、workflow、job、step といった用語に混乱しました。でも実はシンプルです。

**Workflow(ワークフロー)**は一連の自動化プロセス全体を指します。例えば「テスト+ビルド+デプロイ」が1つのワークフローです。これは .github/workflows ディレクトリ内の YAML ファイルで定義します。

**Job(ジョブ)**はワークフロー内の独立したタスクです。例えば「テスト」ジョブと「デプロイ」ジョブを作れます。ジョブは並列実行したり、依存関係を設定して順番に実行したりできます。

**Step(ステップ)**はジョブ内の具体的な操作です。「コードをプルする」「依存関係をインストールする」「テストを実行する」などがステップにあたります。

トリガー条件も柔軟です。main ブランチへのプッシュで実行したり、Pull Request 作成時のみ実行したり、あるいは毎日深夜に自動実行するようスケジュールすることも可能です。

最初の Workflow を作成

まずプロジェクトのルートディレクトリに .github/workflows フォルダを作成し、ci-cd.yml というファイルを作ります。最も基本的な設定は以下のようになります:

name: CI/CD Pipeline

# トリガー条件: main ブランチへの push で実行
on:
  push:
    branches: [main]

jobs:
  build:
    # 最新の Ubuntu 環境で実行
    runs-on: ubuntu-latest

    steps:
      # ステップ1: コードを取得
      - uses: actions/checkout@v4

      # ステップ2: Node.js 環境をセットアップ
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '18'

      # ステップ3: 依存関係をインストール
      - name: Install dependencies
        run: npm ci

      # ステップ4: プロジェクトをビルド
      - name: Build
        run: npm run build

この設定は、「main ブランチにコードがプッシュされるたびに、Ubuntu システム上でコード取得、Node.js 導入、依存インストール、ビルドを実行する」という意味です。

このファイルを GitHub にコミットすると、リポジトリの “Actions” タブでワークフローの実行状況を確認できます。初めてあの緑色のチェックマーク(成功)を見た時は、ちょっとした達成感がありました。

Secrets で機密情報を守る

サーバーへのデプロイには、サーバーの IP、SSH キー、API トークンなどの機密情報が必要です。これらを YAML ファイルに直接書いてはいけません。GitHub にコミットすると世界中に公開されてしまいます。

正しい方法は GitHub の Secrets 機能を使うことです。リポジトリの Settings → Secrets and variables → Actions で “New repository secret” をクリックしてキーを追加します。例えば SERVER_HOST という名前でサーバーの IP アドレスを保存します。

そしてワークフロー内で ${{ secrets.SERVER_HOST }} のように参照します。GitHub は実行時にこれを実際の値に置き換えます。ログ上では伏せ字(***)になり、漏洩することはありません。

自動テストフローの構築

テスト環境の設定

テストに関して私の考えは「自動化できるものは手動でやるな」です。ESLint(コード規約)、TypeScript(型チェック)、Jest(単体テスト)を含むテストフローを構成し、大半の問題をここで食い止めます。

完全なテスト job の設定を見てみましょう:

jobs:
  test:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '18'
          cache: 'npm'  # npm 依存関係をキャッシュして次回以降を高速化

      - name: Install dependencies
        run: npm ci

      - name: Lint check
        run: npm run lint

      - name: Type check
        run: npm run type-check

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

ここで小技:cache: 'npm' を設定すると自動的に node_modules をキャッシュしてくれるので、2回目以降の実行時に依存関係のダウンロード時間が短縮され、数分の節約になります。

テストフロー高速化のコツ

最初はテストに10分以上かかり、コミットのたびに待つのが苦痛でした。最適化の結果、今では3分で終わります。

コツ1:キャッシュ
npm キャッシュに加え、Next.js のビルドキャッシュも保存します:

- name: Cache Next.js build
  uses: actions/cache@v3
  with:
    path: |
      ~/.npm
      .next/cache
    key: ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}

これで Next.js は変更されたページだけを再ビルドすればよくなり、大幅に速くなります。

コツ2:並列実行
テスト間に依存関係がなければ、複数の job に分割して並列実行できます:

jobs:
  lint:
    runs-on: ubuntu-latest
    steps: [...]  # lint だけ実行

  test:
    runs-on: ubuntu-latest
    steps: [...]  # 単体テストだけ実行

  type-check:
    runs-on: ubuntu-latest
    steps: [...]  # 型チェックだけ実行

これら3つの job は同時に開始されるので、総所要時間は3つの合計ではなく、一番遅い job の時間だけで済みます。

私が踏んだ「地雷」

一度、ローカルではテストが通るのに GitHub Actions では失敗するという事態に陥りました。半日デバッグして分かったのは、GitHub Actions が Pull Request のコードを取得する際、デフォルトで PR ブランチをターゲットブランチにマージした「仮想的なコミット」を作成してチェックアウトするため、ローカルとは微妙に異なる状態になっていたことでした。

解決策は、checkout 時にパラメータを追加することです:

- uses: actions/checkout@v4
  with:
    ref: ${{ github.head_ref }}  # PR ブランチの元のコードを使用

もう一つはテストのタイムアウトです。E2E テストなどは時間がかかるため、デフォルトのタイムアウトでは足りないことがあります。job に長めのタイムアウトを設定しましょう:

jobs:
  test:
    runs-on: ubuntu-latest
    timeout-minutes: 15  # デフォルトは 6 分

自動デプロイフローの構築

Vercel へのデプロイ:最も簡単な方法

プロジェクトが Vercel にあるなら簡単です。Vercel と GitHub はネイティブに統合されているので、リポジトリを連携するだけで push 時に自動デプロイされます。

しかし、「テストが通った場合のみデプロイしたい」といった細かい制御が必要な場合は、Vercel 公式の GitHub Action を使います:

jobs:
  deploy:
    runs-on: ubuntu-latest
    needs: test  # テスト job が完了してから実行
    if: github.ref == 'refs/heads/main'  # main ブランチのみデプロイ

    steps:
      - uses: actions/checkout@v4

      - name: Deploy to Vercel
        uses: amondnet/vercel-action@v25
        with:
          vercel-token: ${{ secrets.VERCEL_TOKEN }}
          vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
          vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
          vercel-args: '--prod'  # 本番環境へデプロイ

Vercel の管理画面で Token を生成し、プロジェクト設定から Org ID と Project ID を取得して GitHub Secrets に保存します。

Vercel の良いところは、PR ごとにプレビュー環境を自動作成してくれる点です。PR を出すと、一時的な環境にデプロイされ、プレビューリンクが発行されるので、変更内容をすぐに確認できて便利です。

自前サーバーへのデプロイ:柔軟だが少し複雑

私自身のプロジェクトは、より自由な制御を求めて自前サーバーに配置しています。この場合、SSH 接続を構成し、GitHub Actions からサーバーコマンドを実行させる必要があります。

まずローカルで SSH キーペアを生成します:

ssh-keygen -t ed25519 -C "github-actions"

公開鍵をサーバーの ~/.ssh/authorized_keys に追加し、秘密鍵を GitHub Secrets(例:SSH_PRIVATE_KEY)に追加します。

そしてデプロイ job を設定します:

jobs:
  deploy:
    runs-on: ubuntu-latest
    needs: test
    if: github.ref == 'refs/heads/main'

    steps:
      - name: Deploy to server
        uses: appleboy/ssh-action@master
        with:
          host: ${{ secrets.SERVER_HOST }}
          username: ${{ secrets.SERVER_USER }}
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          script: |
            cd /var/www/my-nextjs-app
            git pull origin main
            npm install
            npm run build
            pm2 restart nextjs-app

この設定は、SSH でサーバーに入り、最新コードを取得し、依存関係を入れ、ビルドし、アプリを再起動します。完全に自動化されており、手動ログインは不要です。

複数サーバーでの Build ID 不一致問題の解決

ロードバランシングのために複数台のサーバーにデプロイする場合、重要な問題があります。各サーバーで個別にビルドすると build ID が異なり、ユーザーがアクセスするたびにページがリフレッシュされる問題が発生します。

解決策は「一箇所でビルドし、成果物を配布する」ことです。以下のように設定します:

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '18'
      - run: npm ci
      - run: npm run build

      # ビルド成果物をアップロード
      - name: Upload build artifacts
        uses: actions/upload-artifact@v3
        with:
          name: next-build
          path: |
            .next
            public

  deploy:
    runs-on: ubuntu-latest
    needs: build
    strategy:
      matrix:
        server: [server1, server2, server3]  # 複数サーバー

    steps:
      # ビルド成果物をダウンロード
      - name: Download build artifacts
        uses: actions/download-artifact@v3
        with:
          name: next-build

      # 各サーバーへデプロイ
      - name: Deploy to ${{ matrix.server }}
        uses: appleboy/scp-action@master
        with:
          host: ${{ secrets[format('{0}_HOST', matrix.server)] }}
          username: ${{ secrets.SERVER_USER }}
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          source: ".next,public"
          target: "/var/www/my-nextjs-app"

これで一度だけビルドを行い、同じ成果物を3台のサーバーに配布するため、build ID が完全に一致します。

最適化とベストプラクティス

ビルドが失敗したらどうするか

自動化は便利ですが、たまに失敗します。ビルドやデプロイが失敗したのに気づかないと、コードはコミットしたのに本番は古いまま、という状態になります。

私は失敗通知を設定しています。メールでも、Slack や DingTalk でも構いません。Slack の例:

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      [...デプロイ手順...]

      # 失敗時に Slack 通知
      - name: Notify on failure
        if: failure()
        uses: 8398a7/action-slack@v3
        with:
          status: ${{ job.status }}
          text: 'デプロイ失敗!確認してください。'
          webhook_url: ${{ secrets.SLACK_WEBHOOK }}
          channel: '#deploy-notifications'

これで失敗したら即座に通知が飛んできます。

ブランチ戦略:開発と本番の分離

実際のプロジェクトでは、ブランチごとに環境を分けます。develop はテスト環境、main は本番環境へデプロイする、という構成です。

on:
  push:
    branches:
      - main      # 本番環境
      - develop   # テスト環境

jobs:
  deploy-staging:
    if: github.ref == 'refs/heads/develop'
    runs-on: ubuntu-latest
    steps:
      - [...テスト環境へのデプロイ...]

  deploy-production:
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    steps:
      - [...本番環境へのデプロイ...]

普段の開発は develop に push してテスト環境で検証し、問題なければ main にマージして本番へ自動デプロイします。

本番デプロイの前に手動承認を求めるチームもあります。GitHub Actions は job に environment を足し、リポジトリ設定で承認者を指定できます:

jobs:
  deploy-production:
    runs-on: ubuntu-latest
    environment:
      name: production  # 承認が必要な環境
    steps: [...]

本番へデプロイするたびに一度止まり、承認者が「Approve」を押すまで進みません。重要なプロジェクトでは、もう一層の保護になります。

ロールバックの仕組み

テストや承認があっても、本番で問題が出ることはあります。そのときは、すぐ前のバージョンへ戻せる必要があります。

シンプルな案は、デプロイごとに tag を打ち、直近数バージョンのビルド成果物を残しておくことです。戻すときは手動トリガーの workflow で tag を指定します:

on:
  workflow_dispatch:  # 手動トリガー
    inputs:
      tag:
        description: 'ロールバック先のタグ'
        required: true

jobs:
  rollback:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          ref: ${{ github.event.inputs.tag }}  # 指定タグを使用

      - name: Deploy
        [...通常のデプロイフロー...]

GitHub Actions の画面から “Run workflow” をクリックし、タグを入力すれば即座にロールバックできます。

環境変数の管理

Next.js プロジェクトでは API URL や DB 接続情報などの環境変数が必要です。これらを Git に入れてはいけません。

  1. GitHub Secrets に機密情報を保存
  2. ワークフロー内で環境変数として注入
  3. Next.js ビルド時に読み込む
- name: Build
  run: npm run build
  env:
    NEXT_PUBLIC_API_URL: ${{ secrets.API_URL }}
    DATABASE_URL: ${{ secrets.DATABASE_URL }}

これで環境ごとに異なる変数を適用でき、コードの修正は不要です。

実践ケース:完全な設定例

ここまでの話を、ひとつの完全な設定例にまとめます。テスト・ビルド・デプロイの流れを含み、プロジェクトにそのまま流用できる形です:

name: Next.js CI/CD

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

jobs:
  # Job 1: コードチェックとテスト
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

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

      - name: Install dependencies
        run: npm ci

      - name: Lint check
        run: npm run lint

      - name: Type check
        run: npm run type-check

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

  # Job 2: ビルド
  build:
    runs-on: ubuntu-latest
    needs: test  # テスト通過後のみ実行
    if: github.event_name == 'push'  # PR時はビルドしない

    steps:
      - uses: actions/checkout@v4

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

      - name: Cache dependencies and build
        uses: actions/cache@v3
        with:
          path: |
            ~/.npm
            .next/cache
          key: ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}

      - name: Install dependencies
        run: npm ci

      - name: Build
        run: npm run build
        env:
          NEXT_PUBLIC_API_URL: ${{ secrets.API_URL }}

      # デプロイ用に成果物をアップロード
      - name: Upload build artifacts
        uses: actions/upload-artifact@v3
        with:
          name: next-build
          path: |
            .next
            public
            package.json

  # Job 3: テスト環境デプロイ
  deploy-staging:
    runs-on: ubuntu-latest
    needs: build
    if: github.ref == 'refs/heads/develop'

    steps:
      - name: Download build artifacts
        uses: actions/download-artifact@v3
        with:
          name: next-build

      - name: Deploy to staging server
        uses: appleboy/ssh-action@master
        with:
          host: ${{ secrets.STAGING_HOST }}
          username: ${{ secrets.SERVER_USER }}
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          script: |
            cd /var/www/staging
            pm2 stop nextjs-app || true
            rm -rf .next public
            pm2 start npm --name "nextjs-app" -- start
            pm2 save

      - name: Notify Slack
        if: always()
        uses: 8398a7/action-slack@v3
        with:
          status: ${{ job.status }}
          text: 'テスト環境デプロイ ${{ job.status == "success" && "成功" || "失敗" }}'
          webhook_url: ${{ secrets.SLACK_WEBHOOK }}

  # Job 4: 本番環境デプロイ
  deploy-production:
    runs-on: ubuntu-latest
    needs: build
    if: github.ref == 'refs/heads/main'
    environment:
      name: production  # 手動承認が必要

    steps:
      - name: Download build artifacts
        uses: actions/download-artifact@v3
        with:
          name: next-build

      - name: Deploy to production server
        uses: appleboy/ssh-action@master
        with:
          host: ${{ secrets.PROD_HOST }}
          username: ${{ secrets.SERVER_USER }}
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          script: |
            cd /var/www/production
            pm2 stop nextjs-app || true
            rm -rf .next public
            pm2 start npm --name "nextjs-app" -- start
            pm2 save

      - name: Notify Slack
        if: always()
        uses: 8398a7/action-slack@v3
        with:
          status: ${{ job.status }}
          text: '本番環境デプロイ ${{ job.status == "success" && "成功" || "失敗" }}'
          webhook_url: ${{ secrets.SLACK_WEBHOOK }}

この設定では、PR はテストのみ。develop への push でテスト環境へ自動デプロイ、main への push で本番へデプロイ(手動承認あり)。デプロイのたびに Slack へ通知し、失敗もすぐ分かります。

実際に使うときは、GitHub リポジトリの Settings で次の Secrets を用意します:

  • API_URL: API の URL
  • STAGING_HOST / PROD_HOST: テスト/本番サーバーのホスト
  • SERVER_USER: SSH ユーザー名
  • SSH_PRIVATE_KEY: SSH 秘密鍵
  • SLACK_WEBHOOK: Slack Webhook URL(任意)

設定が終われば、あとはコードを書いて push するだけです。

まとめ

手動デプロイから自動化へ移ると、開発体験は本当に変わります。コードを直すたびにサーバーで同じコマンドを打つ必要も、テスト忘れの不安も、ターミナルを眺めてビルド完了を待つ時間もなくなります。

GitHub Actions で CI/CD を組むには、最初は試行錯誤が要りますが、十分に元が取れます。一度動けば、その後ずっと効いてきます。まずはいちばんシンプルな設定でテストとビルドを通し、デプロイ・通知・ロールバックは少しずつ足していくのがよいです。

振り返ると、以前はどうやって手動デプロイしていたのか、自分でも不思議なほどです。まだ手動の人には、自動化に時間を使う価値があります。push してコーヒーを飲み、戻ったら新バージョンが公開されている——一度味わうと、戻れません。

さっそく試してみてください。Next.js プロジェクトで最初の workflow ファイルを作り、GitHub Actions が緑のチェックを付けた瞬間、言いたいことは伝わるはずです。

Next.js CI/CD 完全設定フロー

GitHub Actions ワークフロー作成からテスト・ビルド・デプロイ設定までの完全な手順

⏱️ 目安時間: 2 時間

  1. 1

    ステップ1: GitHub Actions ワークフロー作成

    .github/workflows/deploy.yml を作成:
    ```yaml
    name: Deploy

    on:
    push:
    branches: [main]

    jobs:
    build-and-deploy:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - uses: actions/setup-node@v3
    with:
    node-version: '18'
    - run: npm install
    - run: npm run build
    - run: npm test
    ```

    ポイント:
    • トリガー条件:main ブランチへの push
    • 実行環境:ubuntu-latest
    • ステップ:checkout → setup-node → install → build → test
  2. 2

    ステップ2: テスト手順の設定

    テストステップを追加:
    ```yaml
    - name: Run tests
    run: npm test

    - name: Type check
    run: npm run type-check

    - name: Lint
    run: npm run lint
    ```

    ポイント:
    • テスト失敗でデプロイを阻止
    • 型チェックで安全性を確保
    • Lint でコード品質を維持

    メリット:
    • バグのあるコードのデプロイを防止
    • 自動実行によりテスト忘れを回避
  3. 3

    ステップ3: ビルド手順の設定

    ビルド構成:
    ```yaml
    - name: Build
    run: npm run build
    env:
    NEXT_PUBLIC_API_URL: ${{ secrets.NEXT_PUBLIC_API_URL }}
    ```

    キャッシュ最適化:
    ```yaml
    - name: Cache dependencies
    uses: actions/cache@v3
    with:
    path: ~/.npm
    key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
    ```

    ポイント:
    • 環境変数の設定
    • キャッシュでビルドを高速化
    • ビルド出力を確認
  4. 4

    ステップ4: デプロイ手順の設定

    SSH デプロイ:
    ```yaml
    - name: Deploy to server
    uses: appleboy/ssh-action@master
    with:
    host: ${{ secrets.HOST }}
    username: ${{ secrets.USERNAME }}
    key: ${{ secrets.SSH_KEY }}
    script: |
    cd /path/to/app
    git pull
    npm install
    npm run build
    pm2 restart app
    ```

    複数サーバーデプロイ:
    ```yaml
    - name: Deploy to servers
    uses: appleboy/ssh-action@master
    with:
    host: ${{ secrets.HOSTS }}
    username: ${{ secrets.USERNAME }}
    key: ${{ secrets.SSH_KEY }}
    script: |
    cd /path/to/app
    git pull
    npm install
    # GitHub Actions でビルドした成果物を使用
    pm2 restart app
    ```

    ポイント:
    • SSH キー認証を使う
    • ビルド ID を統一(GitHub Actions でビルド)
    • 複数サーバーでのビルド ID 不一致を避ける

FAQ

なぜ CI/CD が必要なのですか?
手動デプロイの課題:
• コードを直すたびにサーバーで同じ作業を繰り返す
• サーバーの再起動を忘れやすい
• テストを忘れやすい
• 複数サーバーでのデプロイミス
• ビルド ID の不一致によるハードリフレッシュ

CI/CD の利点:
• テスト・ビルド・デプロイの自動化
• push するだけで公開
• 手動デプロイのミスを防ぐ
• ビルド ID を統一
• 開発効率の向上

実例:
• 3台デプロイで2台成功、3台目は SSH 切断に気づかず未更新
• ロードバランサーが未更新サーバーへ振り分け、ユーザーが旧版を見る
• テストを忘れてデプロイし、本番で致命的バグを発見

解決策:GitHub Actions でフロー全体を自動化する。
GitHub Actions はどう設定しますか?
.github/workflows/deploy.yml を作成:
```yaml
name: Deploy

on:
push:
branches: [main]

jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '18'
- run: npm install
- run: npm run build
- run: npm test
```

ポイント:
• トリガー:main への push
• 実行環境:ubuntu-latest
• ステップ:checkout → setup-node → install → build → test

Secrets の設定:
• リポジトリ Settings → Secrets
• HOST、USERNAME、SSH_KEY など
• SSH デプロイに使用

提案:まずはシンプルな設定でテストとビルドを通し、デプロイは後から足す。
複数サーバーでビルド ID の不一致をどう防ぎますか?
問題:サーバーごとにビルドすると ID が異なり、ロードバランシング時にハードリフレッシュが起きる。

解決策:ビルド ID を統一する。

GitHub Actions でビルド:
```yaml
- name: Build
run: npm run build

- name: Deploy to servers
uses: appleboy/ssh-action@master
with:
script: |
cd /path/to/app
git pull
# GitHub Actions でビルドした成果物を使う
pm2 restart app
```

または成果物を配布:
```yaml
- name: Upload build artifacts
uses: actions/upload-artifact@v3
with:
name: build
path: .next

- name: Deploy to servers
uses: appleboy/ssh-action@master
with:
script: |
# 成果物をダウンロードして配置
```

ポイント:
• GitHub Actions 上で一度だけビルド
• 同じ成果物を各サーバーへ配布
• サーバーごとの個別ビルドを避ける

利点:
• ビルド ID が一致
• ハードリフレッシュを回避
• UX が安定
テストステップはどう設定しますか?
テストを追加:
```yaml
- name: Run tests
run: npm test

- name: Type check
run: npm run type-check

- name: Lint
run: npm run lint
```

ポイント:
• テスト失敗でデプロイを止める
• 型チェックで型安全性を確保
• Lint でコード品質を維持

利点:
• 問題のあるコードの本番投入を防ぐ
• 自動実行でテスト忘れを防ぐ
• コード品質の向上

提案:
• まずは最小限のテストから
• カバレッジを段階的に上げる
• テスト品質を継続的に改善
デプロイ通知はどう設定しますか?
Slack 通知:
```yaml
- name: Notify Slack
uses: 8398a7/action-slack@v3
with:
status: ${{ job.status }}
text: 'Deployment completed'
webhook_url: ${{ secrets.SLACK_WEBHOOK }}
```

メール通知:
```yaml
- name: Send email
uses: dawidd6/action-send-mail@v3
with:
to: team@example.com
subject: 'Deployment completed'
body: 'Deployment to production completed successfully'
```

ポイント:
• 成功・失敗の両方を通知
• バージョンや時刻などの情報を含める
• チームへ素早く共有

提案:
• Slack(リアルタイム)
• メール(バックアップ)
• デプロイ詳細を本文に含める
CI/CD のベストプラクティスは?
段階的導入:
1. まずテストとビルドを通す
2. 次にデプロイを足す
3. 最後に通知・ロールバック

最初から完璧を目指さず、基本フローを動かしてから拡張する。

継続的改善:
• デプロイ後にログを確認
• 設定を実運用に合わせて調整
• ビルド時間の最適化
• テストカバレッジの向上

主要指標:
• ビルド時間
• テスト合格率
• デプロイ成功率
• ロールバック回数

提案:
• シンプルな設定から始める
• 継続的に改善
• チームで運用

覚えておくこと:CI/CD は一度きりの作業ではなく、継続的なプロセスです。

5分で読めます · 公開日: 2025年12月20日 · 更新日: 2026年6月8日

関連記事

コメント

GitHubアカウントでログインしてコメントできます