1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Next.js】Next.jsをFirebaseのAppHostingでデプロイする

Posted at

問題

Next.jsのプロジェクトをFirebaseのAppHostingでデプロイしたい。

前提として、一度FirebaseにAppHostingできたプロジェクトをローカルでコピーしている。
(Tailwindや、daishiUI、Jestなどはローカルでインストールし、npm run devで開発サーバーが立ち上げられる状態)
そちらに対して、新たにGitHubレポジトリ、Firebaseのプロジェクトを作成し、GitHub ActionsからCI/CDでApp Hostingへデプロイできるようにする。

GitHub ActionsからAppHostingへデプロイする手順

1. Firebaseプロジェクトの作成

ドキュメント
https://firebase.google.com/docs/app-hosting/get-started?hl=ja#before-you-begin

Firebase コンソールで [プロジェクトを追加] をクリックし、プロジェクトを作っておく。

image.png

2. ターミナルでコマンド入力

# 新規プロジェクト作成時のみ。既存プロジェクトには不要
% npm init @apphosting

※このコマンドはプロジェクトを初期化するため、既存プロジェクトには使わないよう注意。
誤って入力してしまい、コピーしてきたプロジェクトが全て初期化された。

% firebase apphosting:backends:create --project hogehogehoge
i  To create a new GitHub connection, Secret Manager Admin role (roles/secretmanager.admin) is required on the Developer Connect Service Agent.
? Grant the required role to the Developer Connect Service Agent? (Y/n) Y

GitHub連携のため、Secret Manager Admin権限が必要。
CLIが「自動で権限を付与するか?」と聞いてくるので、YでOK。

3. GitHub連携

http://localhost:9005/ が立ち上がるので、「Authorize the GitHub app」をクリック。
image.png

「理解した上で続行」を押す。
image.png

「既存のインストールを再利用する」にチェックを入れ、GitHubアカウントは自分のアカウントを設定。
image.png

Firebaseの対象に該当リポジトリが出てこない場合は、「Select repositories」から登録する。
(コマンドラインのどこかの質問でenterを押すと、以下のページに飛んだはず)
image.png

4. サービスアカウントの秘密鍵生成

image.png

5. GitHub ActionsのSecretsに追加

git hub Actions secrets and variablesに追加
(最初、末尾に空白行が入らないこと。エラーになる)
image.png

6. 権限エラー対策

Run export GOOGLE_APPLICATION_CREDENTIALS="/tmp/key.json" 
export GOOGLE_APPLICATION_CREDENTIALS="/tmp/key.json" echo "Y" | 
firebase deploy --project hogehogehoge --non-interactive 
shell: sh -e ***0*** === Deploying to 'hogehogehoge'... i deploying apphosting Error: Request to 
https://serviceusage.googleapis.com/v1/projects/hogehogehoge/services/firebaseapphosting.googleapis.com had HTTP 
Error: 403, Permission denied to get service [firebaseapphosting.googleapis.com] 
Help Token: yyyyyyy Error: Process completed with exit code 1.

サービスアカウントの新しい秘密鍵の、以下箇所でロールを追加するアドレスを確認する。
"client_email": "firebase-adminsdk-fbsvc@hogehogehoge.iam.gserviceaccount.com",

Google CloudのIAMの上記で確認したアドレスに、「編集者」、「Project IAM 管理者」のロールを追加
image.png

image.png

7. Secret Managerの設定

Secretが設定できておらずエラー

Error resolving secret version with name=projects/hogehogehoge/secrets/QIITA_TOKEN/versions/latest. 
Please ensure the secret exists in your project and that your App Hosting backend has access to it. 
If the secret already exists in your project, please grant your App Hosting backend access to it with the CLI command 'firebase apphosting:secrets:grantaccess'. 
See https://firebase.google.com/docs/app-hosting/configure#secret-parameters for more information.

それぞれ以下コマンドをうち、対話で「value、使用する環境、バックエンドサービスがアクセスすることの許可」を設定する

%  firebase apphosting:secrets:set QIITA_TOKEN
%  firebase apphosting:secrets:set QIITA_USER_ID

シークレットが設定されていることを確認

% gcloud secrets list --project=hogehogehoge

8. SSRでページ表示確認

image.png

image.png

注意

自動ロールアウトが有効になっている場合、GitHub Actions以外の経路でも自動的にデプロイが実行される。
そのため、GitHub Actionsでテストが失敗しても、別ルートからデプロイされてしまった。
「テストが通った場合のみデプロイしたい」ときは、自動ロールアウトの設定に注意する。

image.png

デプロイに関連するコード

.github/workflows/firebase.yml
name: Test App Hosting Deployment (Docker Container)

on:
  push:
    branches:
      - main

jobs:
  test_and_deploy:
    runs-on: ubuntu-latest
    timeout-minutes: 10
    # Google Cloudとの連携に特化したツールがプリインストールされているDockerコンテナを使う(gcloudというツールが最初から入っている)
    # → より堅牢で、効率的で、再現性の高いCI/CDパイプラインを構築できる
    container:
      image: google/cloud-sdk:latest
      # コンテナ内で権限エラーを避けるためにrootユーザーで実行
      options: --user root

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Configure Git safe directory
      # git config --global --add safe.directory ... で安全なディレクトリとして明示する必要がある
      # これがないと、Gitコマンドがエラーになることがある

      # issueによると、GitHub Actionsのコンテナ内でのgit config safe.directoryの設定が必要
      # https://github.com/actions/runner/issues/2033
      # https://github.com/actions/checkout/issues/1169
        run: git config --global --add safe.directory /__w/github_name/hogehogehoge

      - name: Set up Node.js
      # コンテナ内(特に google/cloud-sdk のようなベースイメージ)では、apt で手動インストールする方が確実
      # パッケージ情報を最新に更新
      # Node.js をインストール
        run: |
          curl -fsSL https://deb.nodesource.com/setup_20.x | bash -

          apt-get update
          apt-get install -y nodejs

      - name: Install dependencies
        run: npm ci

      - name: Run unit tests
        run: npm test

      - name: Install Firebase CLI (firebase-tools)
        run: npm install -g firebase-tools

      - name: Authenticate gcloud with Service Account
      # 内容を /tmp/key.json に書き込む(ヒアドキュメント)。
      # ${{ secrets.FIREBASE_SERVICE_ACCOUNT_HOGEHOGEHOGE }} にはGitHub Actionsのシークレット(サービスアカウントJSON)が展開される。

      # サービスアカウントを使って Google Cloud にログインする
      # デフォルトプロジェクトを設定
        run: |
          cat <<EOF > /tmp/key.json
          ${{ secrets.FIREBASE_SERVICE_ACCOUNT_THOGEHOGEHOGE }}
          EOF
          gcloud auth activate-service-account --key-file=/tmp/key.json \
            --project=hogehogehoge
          gcloud config set project hogehogehoge

      - name: Trigger Firebase App Hosting Deployment
        if: success()
        # GOOGLE_APPLICATION_CREDENTIALS 環境変数にサービスアカウントのJSONファイルのパス(/tmp/key.json)を指定することで、
        # Firebase CLI(firebase-tools)が、その認証情報を使ってGoogle Cloud/Firebaseにアクセスできるようになる

        # firebase deploy コマンドを実行すると、時々「本当にデプロイしますか?」などの確認プロンプトが表示される
        # echo "Y" で「Yes」と自動応答し、その内容をパイプ(|)で firebase deploy に渡すことで、手動入力なしで自動的にデプロイが進むようにしている
        # --non-interactive オプションは、対話モードを無効化し、CI/CD環境で自動実行できるようにする

        # non-interactiveについてドキュメントは以下しか確認できなかった
        # https://firebase.google.com/docs/data-connect/manage-schemas-and-connectors?hl=ja
        run: |
          export GOOGLE_APPLICATION_CREDENTIALS="/tmp/key.json"
          echo "Y" | firebase deploy --project hogehogehoge --non-interactive
apphosting.yaml
runConfig:
  minInstances: 0
  maxInstances: 1

env:
  - variable: QIITA_TOKEN
    secret: QIITA_TOKEN
    availability:
      - BUILD
      - RUNTIME

  - variable: QIITA_USER_ID
    secret: QIITA_USER_ID
    availability:
      - BUILD
      - RUNTIME
.firebaserc
{
  "projects": {
// プロジェクトID
// ここが元のプロジェクトだとエラーになる
    "default": "hogehogehoge"
  }
}

ドキュメント・用語まとめ

firebaseのドキュメント

App Hosting バックエンドの構成と管理

Firebase 関連サービス アカウントの概要

プロジェクトに関連付けられたすべてのサービス アカウントは、Firebase コンソールの settings > [プロジェクトの設定] > [サービス アカウント] タブで表示できます。

システム連携の画像 ※firebaseのドキュメントから抜粋

image.png

主な用語解説

Google Cloud Developer Connect

GitHubと Google Cloud(Firebase App Hosting など)を接続する

Secret Manager

管理者ロールを付与
専用の GitHub 認証トークンをプロジェクトのシークレット マネージャー リポジトリに保存

Artifact Registry

保存(置く)

Cloud Run

実行(動かす)

App Hosting バックエンド サービス アカウント

App Hosting を初めて有効化すると、自動でサービスアカウントが作られる
(→ firebase-app-hosting-compute@PROJECT-ID.iam.gserviceaccount.com)

このアカウントが ビルド・実行・モニタリング用のデフォルト権限 を持ち、
Firebase App Hosting が Google Cloud の各サービスにアクセスできるようになる。

Firebase Admin SDK

Firebase Admin SDK は、サーバーサイドのアプリケーションから Firebase の各種サービス(Firestore、Authentication、Realtime Database など)を操作するための公式ライブラリ

サービスアカウント

Firebase Admin SDK を使用する際、認証情報として「サービスアカウント」の秘密鍵を利用。これにより、サーバーサイドから Firebase サービスへのアクセスが可能となる。

終わりに

難しかったですが、AIに聞いたりドキュメントを読むことで、少し理解できるようになりました!

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?