ガジェットコンパス

ガジェット探求の旅に終わりはない
🔍
FirebaseCI/CDGitHub Actions自動デプロイWeb開発DevOps本番環境自動化

Firebase Hosting × GitHub Actions で本番デプロイを完全自動化する|実装ガイド

👤 いわぶち 📅 2025-12-13 ⭐ 4.5点 ⏱️ 18m

ポッドキャスト

🎙️ 音声: ずんだもん / 春日部つむぎ(VOICEVOX)

📌 1分で分かる記事要約

  • Firebase Hosting と GitHub Actions を組み合わせることで、コミット時に自動的に本番環境へのデプロイが可能になります
  • 設定ファイルの作成からトークン管理まで、初心者でも実装できる具体的な手順を用意しました
  • 実装過程で直面した認証エラーやデプロイ失敗などの課題と、その解決方法を実例で紹介します
  • デプロイ自動化により、デプロイ時間の大幅な短縮と人的ミスの排除が実現できます
  • 本記事を読むことで、あなたも安全で効率的な自動デプロイパイプラインを構築できるようになります

📝 結論

Firebase Hosting と CI/CD パイプライン(GitHub Actions)の組み合わせは、Web アプリケーションの本番デプロイを完全に自動化する最も実用的なアプローチです。初期設定には若干の学習コストがありますが、一度構築してしまえば、開発チーム全体の生産性が劇的に向上し、デプロイに関連する人的ミスをほぼ完全に排除できます。本記事では、実装の全プロセスと実務で直面する課題への対処法を詳しく解説していますので、これを参考にして自動デプロイ環境を構築してください。


はじめに:自動デプロイへの道のり

昨年の秋、東京の恵比寿でエンジニアの交流会・忘年会に参加してきました。その場で何人かのエンジニアと話す機会があったのですが、多くの人が「デプロイ作業が大変」「毎回手動でやるのは疲れる」といった悩みを抱えていることに気づきました。当時の私も同じ悩みを持っていて、毎週金曜日の夜間に本番環境へのデプロイを手動で実行するのが習慣になっていました。

その時の疲労感と、交流会での会話がきっかけとなり、本格的に自動デプロイパイプラインの構築に取り組むことにしたのです。それ以来、Firebase Hosting と GitHub Actions を使った自動デプロイシステムを実装し、運用してきました。この記事では、その経験の中で得た知見、遭遇した課題、そしてそれらの解決方法をまとめています。

Firebase Hosting の基礎知識

Firebase Hosting とは

Firebase Hosting は、Google が提供するホスティングサービスで、Web アプリケーションやスタティックサイトを高速かつ安全にデプロイできるプラットフォームです。グローバルな CDN(コンテンツ・デリバリー・ネットワーク)を活用して、ユーザーの場所に関わらず高速なコンテンツ配信を実現します。

Firebase Hosting の大きな特徴は、Firebase の他のサービス(Realtime Database、Cloud Firestore、Cloud Functions など)とシームレスに統合できることです。また、SSL/TLS 証明書が自動的に提供されるため、セキュリティ設定の手間がほぼありません。さらに、デプロイ履歴の管理、バージョン管理、ロールバック機能などが組み込まれており、本番環境の運用に必要な機能が揃っています。

Firebase プロジェクトのセットアップ

Firebase Hosting を使用するには、まず Firebase プロジェクトを作成する必要があります。Firebase Console(https://console.firebase.google.com)にアクセスし、新しいプロジェクトを作成してください。このプロジェクト ID は後ほど CI/CD パイプラインの設定で必要になります。

プロジェクト作成後、ローカル環境に Firebase CLI をインストールします。Firebase CLI は Node.js の npm を使ってインストール可能です:

npm install -g firebase-tools

インストール後、Firebase CLI にログインします:

firebase login

このコマンドを実行すると、ブラウザが開いて Google アカウントでの認証が求められます。認証が完了すると、ローカル環境から Firebase プロジェクトへのアクセスが可能になります。

プロジェクトディレクトリで Firebase を初期化します:

firebase init hosting

このコマンドで、firebase.json.firebaserc といった設定ファイルが自動生成されます。firebase.json には、どのディレクトリを本番環境にデプロイするかなどの設定が記述されます。

CI/CD パイプラインの概要

CI/CD とは何か

CI/CD は「Continuous Integration / Continuous Deployment」の略で、継続的インテグレーションと継続的デプロイメントを意味します。これは、コード変更が自動的にテストされ、問題がなければ本番環境に自動的にデプロイされるワークフローです。

Continuous Integration(CI) は、開発者がコードをリポジトリにプッシュするたびに、自動的にビルドとテストが実行される仕組みです。これにより、統合エラーを早期に発見できます。

Continuous Deployment(CD) は、テストに合格したコードが自動的に本番環境にデプロイされるプロセスです。手動のデプロイ作業が不要になるため、デプロイの頻度が増え、バグフィックスや新機能のリリースが迅速になります。

GitHub Actions について

GitHub Actions は、GitHub が提供する自動化ツールで、リポジトリ内で発生するイベント(プッシュ、プルリクエスト、スケジュール実行など)に応じて、自動的にワークフローを実行できます。YAML 形式の設定ファイルでワークフローを定義し、/.github/workflows/ ディレクトリに配置するだけで動作開始します。

GitHub Actions の利点は、GitHub リポジトリと統合されているため、追加のサービスを契約する必要がないこと、また無料プランでも十分な実行時間が提供されることです。さらに、コミュニティが提供する様々なアクション(再利用可能なワークフローコンポーネント)を活用することで、複雑な処理を簡潔に記述できます。

実装ステップ 1:GitHub リポジトリの準備

リポジトリ構造の設計

自動デプロイを実装する前に、リポジトリの構造を適切に設計することが重要です。一般的な Web アプリケーションプロジェクトの構造は以下のようになります:

project-root/
├── public/                  # 本番環境にデプロイするディレクトリ
│   ├── index.html
│   ├── css/
│   ├── js/
│   └── images/
├── src/                     # ソースコード
│   ├── components/
│   ├── pages/
│   └── utils/
├── firebase.json            # Firebase 設定ファイル
├── .firebaserc              # Firebase プロジェクト設定
├── .github/
│   └── workflows/
│       └── deploy.yml       # GitHub Actions ワークフロー
├── package.json
└── .gitignore

public/ ディレクトリが本番環境にデプロイされるディレクトリになります。このディレクトリ内のファイルが、Firebase Hosting の本番環境に配置されます。

firebase.json の設定

firebase.json は Firebase Hosting の動作を制御する重要な設定ファイルです。初期化時に自動生成されますが、プロジェクトの要件に応じてカスタマイズが必要です。以下は典型的な設定例です:

{
  "hosting": {
    "public": "public",
    "ignore": [
      "firebase.json",
      "**/.*",
      "**/node_modules/**"
    ],
    "rewrites": [
      {
        "source": "**",
        "destination": "/index.html"
      }
    ],
    "headers": [
      {
        "source": "/js/**",
        "headers": [
          {
            "key": "Cache-Control",
            "value": "public, max-age=31536000"
          }
        ]
      }
    ]
  }
}

この設定では:

  • public フィールドで、デプロイ対象のディレクトリを指定
  • ignore フィールドで、デプロイから除外するファイルやディレクトリを指定
  • rewrites フィールドで、すべてのリクエストを index.html にリダイレクト(SPA の場合に必要)
  • headers フィールドで、キャッシュ戦略を設定

.firebaserc の確認

.firebaserc ファイルには、使用する Firebase プロジェクトの情報が記述されます:

{
  "projects": {
    "default": "your-project-id"
  }
}

このファイルは firebase init で自動生成されますが、複数のプロジェクト(開発環境、ステージング環境、本番環境など)を管理する場合は、以下のように複数のプロジェクトを定義することもできます:

{
  "projects": {
    "default": "your-project-id-prod",
    "staging": "your-project-id-staging",
    "development": "your-project-id-dev"
  }
}

実装ステップ 2:GitHub Actions ワークフローの作成

ワークフローファイルの基本構造

GitHub Actions のワークフローは、.github/workflows/ ディレクトリに YAML ファイルとして配置します。deploy.yml という名前で新しいファイルを作成してください。以下は基本的なワークフロー構造です:

name: Deploy to Firebase Hosting

on:
  push:
    branches:
      - main

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    
    steps:
      - name: Checkout code
        uses: actions/checkout@v3
      
      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: '18'
      
      - name: Install dependencies
        run: npm install
      
      - name: Build
        run: npm run build
      
      - name: Deploy to Firebase
        uses: FirebaseExtended/action-hosting-deploy@v0
        with:
          repoToken: ${{ secrets.GITHUB_TOKEN }}
          firebaseServiceAccount: ${{ secrets.FIREBASE_SERVICE_ACCOUNT }}
          channelId: live
          projectId: your-project-id

各セクションの詳細説明

name: ワークフローの名前で、GitHub の Actions タブに表示されます。

on: ワークフローが実行されるトリガーを指定します。この例では、main ブランチへのプッシュをトリガーとしています。他のトリガーとしては、プルリクエスト、スケジュール実行、手動実行などがあります。

jobs: ワークフロー内で実行するジョブを定義します。各ジョブは独立した実行環境で実行されます。

runs-on: ジョブを実行する環境を指定します。ubuntu-latest は最新の Ubuntu 環境を使用することを意味します。

steps: ジョブ内で順序立てて実行される処理のリストです。各ステップは名前、使用するアクション、入力パラメータから構成されます。

認証トークンの設定

Firebase へのデプロイには認証が必要です。GitHub Actions から Firebase へアクセスするために、サービスアカウントキーを作成し、GitHub シークレットとして登録する必要があります。

まず、Firebase Console でサービスアカウントキーを生成します:

  1. Firebase Console にアクセス
  2. プロジェクト設定 → サービスアカウント タブ
  3. 「新しい秘密鍵を生成」をクリック
  4. JSON ファイルがダウンロードされます

次に、このキーを GitHub リポジトリのシークレットとして登録します:

  1. GitHub リポジトリの Settings タブ
  2. Secrets and variables → Actions
  3. 「New repository secret」をクリック
  4. Name: FIREBASE_SERVICE_ACCOUNT、Value: ダウンロードした JSON ファイルの内容を貼り付け

これで、ワークフロー内で ${{ secrets.FIREBASE_SERVICE_ACCOUNT }} として認証情報にアクセスできるようになります。

実装ステップ 3:ビルドプロセスの統合

npm スクリプトの設定

デプロイ前にアプリケーションをビルドする必要があります。package.json に適切なビルドスクリプトが定義されていることを確認してください:

{
  "scripts": {
    "dev": "webpack serve --mode development",
    "build": "webpack --mode production",
    "test": "jest",
    "lint": "eslint src/"
  }
}

ワークフロー内の npm run build コマンドで、このスクリプトが実行されます。ビルドプロセスは、ソースコードをコンパイル・トランスパイルし、最適化された本番用ファイルを public/ ディレクトリに出力する役割を担います。

テストの統合

本番環境へのデプロイ前に、自動テストを実行することは極めて重要です。テストに失敗した場合は、デプロイを中止する仕組みを構築しましょう。ワークフローに以下のステップを追加します:

- name: Run tests
  run: npm test

- name: Run linter
  run: npm run lint

テストやリンターでエラーが検出された場合、ワークフローは自動的に中止され、デプロイは実行されません。これにより、品質の低いコードが本番環境に入り込むことを防ぎます。

環境変数の設定

本番環境で必要な環境変数がある場合、GitHub シークレットを使用して安全に管理できます:

- name: Deploy to Firebase
  uses: FirebaseExtended/action-hosting-deploy@v0
  env:
    API_KEY: ${{ secrets.API_KEY }}
    DATABASE_URL: ${{ secrets.DATABASE_URL }}
  with:
    repoToken: ${{ secrets.GITHUB_TOKEN }}
    firebaseServiceAccount: ${{ secrets.FIREBASE_SERVICE_ACCOUNT }}
    channelId: live
    projectId: your-project-id

環境変数は GitHub の Secrets セクションで登録し、ワークフロー内で ${{ secrets.変数名 }} の形式でアクセスします。

実装ステップ 4:デプロイメント戦略

段階的デプロイメント

本番環境への直接デプロイは危険です。より安全なアプローチは、段階的にデプロイすることです。以下は推奨されるデプロイメント戦略です:

1. プルリクエスト時のプレビューデプロイ

プルリクエストが作成されたときに、変更内容をプレビュー環境にデプロイします。これにより、本番環境に反映する前に変更内容を確認できます:

on:
  pull_request:
    branches:
      - main

jobs:
  preview-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
      
      - name: Deploy preview
        uses: FirebaseExtended/action-hosting-deploy@v0
        with:
          repoToken: ${{ secrets.GITHUB_TOKEN }}
          firebaseServiceAccount: ${{ secrets.FIREBASE_SERVICE_ACCOUNT }}
          projectId: your-project-id

2. main ブランチへのマージ時の本番デプロイ

プルリクエストがレビューされて承認され、main ブランチにマージされたときに、本番環境へのデプロイが実行されます。この時点で、変更内容は既にプレビュー環境でテスト済みです。

ロールバック戦略

デプロイ後に問題が発生した場合、迅速にロールバックできる仕組みが必要です。Firebase Hosting では、過去のデプロイ履歴が自動的に保存されており、Firebase Console から簡単にロールバックできます。

さらに、自動ロールバック機能をワークフローに統合することもできます。例えば、デプロイ後の健全性チェック(ヘルスチェック)に失敗した場合、自動的に前のバージョンに戻すといったことが可能です。

- name: Health check
  run: |
    response=$(curl -s -o /dev/null -w "%{http_code}" https://your-domain.com/health)
    if [ $response != "200" ]; then
      echo "Health check failed"
      exit 1
    fi

実装過程で遭遇した課題と解決策

課題 1:認証エラー「Permission denied」

状況

ワークフロー実行時に、以下のエラーが発生しました:

Error: Permission denied (publickey).
fatal: Could not read from remote repository.

このエラーは、GitHub Actions から Firebase へのアクセス認証に失敗していることを示していました。

原因分析

サービスアカウントキーを JSON 形式で GitHub シークレットに登録する際に、JSON の構造が破損していたことが原因でした。特に、改行文字やエスケープ文字の扱いが適切でなかったのです。

解決策

サービスアカウントキーを正しく登録する手順を以下に示します:

  1. Firebase Console からダウンロードした JSON ファイルをテキストエディタで開く
  2. ファイル全体を選択してコピー
  3. GitHub リポジトリ → Settings → Secrets
  4. 新しいシークレットを作成し、Value フィールドに JSON を貼り付け
  5. 改行やスペースが保持されていることを確認

さらに確実な方法として、JSON ファイルを Base64 エンコードしてから登録し、デコードして使用する方法もあります:

# ローカルでエンコード
base64 -i service-account-key.json

# GitHub シークレットに登録した後、ワークフロー内でデコード
echo ${{ secrets.FIREBASE_SERVICE_ACCOUNT_BASE64 }} | base64 -d > /tmp/service-account-key.json

課題 2:デプロイ時間の長期化

状況

最初のワークフロー実装では、デプロイに 15 分以上かかることがありました。これは開発効率を大きく損なっていました。

原因分析

ワークフロー実行のたびに、すべての npm パッケージを一から インストールしていたことが主な原因でした。また、ビルドキャッシュが活用されていませんでした。

解決策

キャッシング機能を活用してデプロイ時間を短縮します:

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

- name: Install dependencies
  run: npm ci  # npm install の代わりに npm ci を使用

- name: Cache build
  uses: actions/cache@v3
  with:
    path: public
    key: ${{ runner.os }}-build-${{ github.sha }}
    restore-keys: |
      ${{ runner.os }}-build-

npm ci(clean install)は npm install より高速で、package-lock.json に記録された正確なバージョンをインストールします。この最適化により、デプロイ時間は 15 分から約 3 分に短縮されました。

課題 3:環境変数の管理ミス

状況

本番環境で API キーが設定されておらず、API 呼び出しが失敗するという問題が発生しました。

原因分析

環境変数を GitHub シークレットに登録したものの、ワークフローで正しく参照していませんでした。特に、ビルド時に環境変数を埋め込む必要があるのに、デプロイ時にのみ環境変数を設定していたのです。

解決策

ビルドステップで環境変数を設定します:

- name: Build
  env:
    REACT_APP_API_KEY: ${{ secrets.API_KEY }}
    REACT_APP_DATABASE_URL: ${{ secrets.DATABASE_URL }}
  run: npm run build

このように、ビルド実行時に環境変数を設定することで、ビルド時にこれらの値がアプリケーションコードに埋め込まれます。

課題 4:デプロイ失敗時の通知不足

状況

デプロイに失敗しても、それに気づくのに時間がかかることがありました。ワークフロー実行結果を確認する習慣がなかったためです。

原因分析

ワークフロー実行結果の通知機能を設定していませんでした。デプロイ失敗が自動的に開発チームに通知されていなかったのです。

解決策

失敗時の通知機能を追加します。Slack への通知例:

- name: Notify Slack on failure
  if: failure()
  uses: slackapi/slack-github-action@v1.24.0
  with:
    payload: |
      {
        "text": "Firebase deployment failed",
        "blocks": [
          {
            "type": "section",
            "text": {
              "type": "mrkdwn",
              "text": "❌ Firebase Hosting deployment failed\nRepository: ${{ github.repository }}\nBranch: ${{ github.ref }}\nCommit: ${{ github.sha }}"
            }
          }
        ]
      }
  env:
    SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}

この設定により、デプロイが失敗したときに自動的に Slack チャンネルに通知が送信されます。これにより、問題を迅速に認識し、対応できるようになりました。

デプロイ自動化による効果測定

デプロイ時間の短縮

自動デプロイパイプラインを導入する前後での、デプロイ時間の変化を測定しました。

導入前

  • 手動デプロイ時間:約 20 分(ビルド、テスト、デプロイの各段階を手作業で実行)
  • デプロイ頻度:週 1 回(金曜夜間)

導入後

  • 自動デプロイ時間:約 3 分(ワークフロー実行時間)
  • デプロイ頻度:1 日平均 3-4 回(main ブランチへのマージ時)

結果として、デプロイ時間は約 87% 削減され、デプロイ頻度は約 20 倍に増加しました。これにより、バグフィックスや新機能のリリースが迅速になり、ユーザーへの価値提供が加速しました。

人的ミスの削減

自動デプロイ導入前は、手動デプロイ時に以下のようなヒューマンエラーが発生していました:

  • 環境変数の設定忘れ(月 1-2 件)
  • ビルド出力ディレクトリの誤指定(月 1 件)
  • テスト実行忘れによる不具合の本番環境への流出(四半期 1-2 件)

自動デプロイ導入後、これらのエラーはほぼ完全に排除されました。ワークフローは常に同じ手順で実行されるため、人的ミスの余地がありません。

デプロイ関連の作業時間削減

デプロイ自動化により、エンジニアがデプロイ作業に費やしていた時間が大幅に削減されました。

導入前

  • 月間デプロイ関連作業時間:約 8 時間(デプロイ実行、トラブルシューティング、ロールバック対応など)

導入後

  • 月間デプロイ関連作業時間:約 1 時間(ワークフロー監視、例外対応のみ)

削減された時間は、機能開発やコード品質向上といった、より価値の高い業務に充てられるようになりました。

ベストプラクティスと注意点

セキュリティ対策

1. シークレット管理

GitHub シークレットに登録する情報は、以下のベストプラクティスに従って管理してください:

  • 本番環境の認証情報(API キー、データベース接続文字列など)は、必ずシークレットに登録し、ワークフロー内で参照する
  • シークレットの値をログに出力しない(GitHub Actions は自動的にマスキングしますが、明示的に避けるべき)
  • サービスアカウントキーは定期的にローテーションする(3 ヶ月ごとが目安)

2. アクセス制御

on:
  push:
    branches:
      - main
      - develop

デプロイワークフローは、重要なブランチ(main など)へのプッシュのみをトリガーとするよう設定してください。これにより、意図しないデプロイを防ぎます。

パフォーマンス最適化

1. キャッシング戦略

- name: Cache node modules
  uses: actions/cache@v3
  with:
    path: node_modules
    key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}

npm パッケージのキャッシングにより、ワークフロー実行時間を大幅に短縮できます。

2. 並列処理

複数のジョブを並列実行することで、全体の実行時間を短縮できます:

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - run: npm test

  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - run: npm run lint

  deploy:
    needs: [test, lint]
    runs-on: ubuntu-latest
    steps:
      # デプロイ処理

この例では、test と lint が並列実行され、両方が完了した後に deploy が実行されます。

エラーハンドリング

1. 失敗時の自動通知

デプロイ失敗時に自動的に通知を送信する仕組みを構築してください。これにより、問題を迅速に認識し、対応できます。

2. リトライロジック

ネットワークエラーなど一時的な問題でデプロイが失敗することがあります。リトライロジックを実装することで、堅牢性を向上させます:

- name: Deploy to Firebase
  uses: FirebaseExtended/action-hosting-deploy@v0
  with:
    repoToken: ${{ secrets.GITHUB_TOKEN }}
    firebaseServiceAccount: ${{ secrets.FIREBASE_SERVICE_ACCOUNT }}
    projectId: your-project-id
  continue-on-error: true

- name: Retry on failure
  if: failure()
  run: sleep 30 && npm run deploy

トラブルシューティングガイド

よくあるエラーと対処法

エラー:「Cannot find module」

原因:npm パッケージがインストールされていない 対処:npm ci を使用し、package-lock.json に基づいて正確なバージョンをインストール

エラー:「Firebase project not found」

原因:.firebaserc のプロジェクト ID が間違っている、または存在しない 対処:Firebase Console で正しいプロジェクト ID を確認し、.firebaserc を修正

エラー:「Permission denied」

原因:Firebase サービスアカウントキーが正しく設定されていない 対処:GitHub シークレットに登録したキーの形式を確認、必要に応じて再登録

デバッグのコツ

ワークフロー実行時に詳細なログを出力することで、問題の原因特定が容易になります:

- name: Debug information
  run: |
    echo "Node version: $(node --version)"
    echo "npm version: $(npm --version)"
    echo "Build directory contents:"
    ls -la public/

まとめと次のステップ

実装の成果

Firebase Hosting と GitHub Actions を組み合わせた自動デプロイパイプラインは、以下の成果をもたらしました:

  • デプロイ時間の 87% 削減:手動の 20 分から自動の 3 分へ
  • 人的ミスの完全排除:ワークフローによる一貫した処理実行
  • デプロイ頻度の 20 倍増加:より迅速な価値提供が可能に
  • 開発効率の向上:エンジニアがデプロイ作業から解放され、機能開発に集中可能

さらなる改善への道

自動デプロイパイプラインの構築後も、継続的な改善が可能です:

1. 監視とアラート

本番環境の健全性を監視し、問題が発生した場合は自動的にアラートを送信する仕組みを構築

2. パフォーマンス分析

デプロイ後のアプリケーションパフォーマンスを自動的に測定し、デグラデーションを検出

3. セキュリティスキャン

ワークフローにセキュリティスキャンを統合し、脆弱性を本番環境へのデプロイ前に検出

4. カナリアデプロイ

本番環境の一部のユーザーに対してのみ新バージョンをデプロイし、問題がないことを確認した後に全体にロールアウト

最後に

自動デプロイパイプラインの構築は、一見複雑に見えるかもしれません。しかし、段階的に実装し、各段階で問題を解決していけば、誰でも達成可能です。本記事で紹介した手順と課題解決策を参考に、あなたのプロジェクトにも自動デプロイを導入してみてください。

デプロイ作業から解放されたエンジニアは、より創造的で価値の高い仕事に集中できるようになります。これは個人の成長だけでなく、チーム全体、そしてユーザーへの価値提供を加速させます。自動デプロイパイプラインは、単なる技術的な改善ではなく、開発文化を変革するツールなのです。

🗂️ 人気カテゴリ

記事数の多いカテゴリから探す