問題
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 コンソールで [プロジェクトを追加] をクリックし、プロジェクトを作っておく。
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」をクリック。
「既存のインストールを再利用する」にチェックを入れ、GitHubアカウントは自分のアカウントを設定。
Firebaseの対象に該当リポジトリが出てこない場合は、「Select repositories」から登録する。
(コマンドラインのどこかの質問でenterを押すと、以下のページに飛んだはず)
4. サービスアカウントの秘密鍵生成
5. GitHub ActionsのSecretsに追加
git hub Actions secrets and variablesに追加
(最初、末尾に空白行が入らないこと。エラーになる)
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 管理者」のロールを追加
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でページ表示確認
注意
自動ロールアウトが有効になっている場合、GitHub Actions以外の経路でも自動的にデプロイが実行される。
そのため、GitHub Actionsでテストが失敗しても、別ルートからデプロイされてしまった。
「テストが通った場合のみデプロイしたい」ときは、自動ロールアウトの設定に注意する。
デプロイに関連するコード
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
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
{
"projects": {
// プロジェクトID
// ここが元のプロジェクトだとエラーになる
"default": "hogehogehoge"
}
}
ドキュメント・用語まとめ
firebaseのドキュメント
App Hosting バックエンドの構成と管理
Firebase 関連サービス アカウントの概要
プロジェクトに関連付けられたすべてのサービス アカウントは、Firebase コンソールの settings > [プロジェクトの設定] > [サービス アカウント] タブで表示できます。
システム連携の画像 ※firebaseのドキュメントから抜粋
主な用語解説
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に聞いたりドキュメントを読むことで、少し理解できるようになりました!