Google Cloud Build で CI/CD! ~ Firebase Hosting 編 ~

Yuki Iwanari
google-cloud-jp
Published in
9 min readJul 29, 2018

CI/CD してますか?

Google Cloud Build (以下、Cloud Build)は、フルマネージドなCI/CD platformです。Google Cloud Next ‘18でContainer Builderから名称が変更されましたが、コンテナイメージをビルドするサービスというイメージを持たれている方も多いのでは無いでしょうか?

Cloud Build を利用することで、コンテナイメージやアーティファクトのビルドから、VM、サーバレス、Kubernetes、Firebaseなどの複数環境へのデプロイまで、カスタムワークフローを定義して管理することが可能です。

本記事では、カスタムビルドステップを利用して、Firebase HostingへのContinuous Delivery を実現してみましょう。
(その他のユースケースについては、概要ページをご参照ください。また、Cloud Functionsへのデプロイもご参考ください。)

Goals

今回は、以下の流れを実現してみたいと思います。

  1. Cloud Source Repositories へソースをプッシュ
  2. 静的サイトジェネレータHugoによりウェブページを自動生成
  3. Firebase Hostingにウェブページを自動デプロイ

今回は、より実践的な内容になるように、Cloud Buildでトークンを使う手順も含めています。

Step0. ビルドで利用するコンテナイメージを作成

事前準備として、Cloud Buildで利用するコンテナイメージを作成しましょう。まず、関連するサービスのAPIを有効化します。

  1. Cloud Build API を有効化
  2. Cloud Source Repositories API を有効化

さて、次はコンテナイメージをビルドしましょう。GitHub上に、様々なビルドで利用できるビルダーイメージが公開されています。

今回は、community imagesのfirebaseを利用します。以下の手順により、利用中のプロジェクトで、firebaseのイメージが利用可能になります。

$ git clone https://github.com/GoogleCloudPlatform/cloud-builders-community.git
$ cd firebase
$ gcloud builds submit --config cloudbuild.yaml .

20180729 注
上記のコードに一部バグがあるようです。もし動作しない場合は、以下をお試しください。
- cloudbuild.yaml から secretEnv 行を削除
- firebase.bash に実行権限を付与( chmod +x firebase.bash

Step1. Firebase Hostingでサイト作成

まず、静的サイトジェネレータHugoを用いて、htmlファイルを作成しましょう。今回は、Quick Startの”Step 4: Add Some Content”まで実施してください。

最後に、hugoコマンドで、publicフォルダを作成しておきましょう。最終的には、以下のディレクトリ構成となります。

.
├── quickstart
│ ├── archetypes
│ ├── ...
│ ├── public --- このディレクトリにウェブページが生成されます
│ ├── index.html
...

デプロイするウェブページを生成したあとは、Firebase Hostingにサイトをデプロイします。Firebase Hostingへの初回デプロイは、Hosting を使ってみる を参考にしてください。コマンド3つで、非常に簡単にデプロイできます!

Step2. Firebaseへのデプロイ用のキーを取得

手動でデプロイする際は firebase loginで認証していましたが、Cloud Buildからデプロイするためにfirebase login:ciコマンドで、トークンを取得しましょう。
下から二行目がトークンです(URL、トークンは変更しています)。

$ firebase login:ci Visit this URL on any device to log in:
https://accounts.google.com/o/oauth2/auth?client_id=hogefuga
Waiting for authentication...✔ Success! Use this token to login on a CI server:1/*****************Example: firebase deploy --token "hoge"
ログイン後に表示される画面

Step3. Cloud KMSでトークンを暗号化

暗号化されたリソースの使用」の手順に従って、Cloud Buildで利用できるようにトークンを暗号化しましょう。

  1. Cloud KMS のキーリングと暗号鍵を作成
  2. Cloud Buildサービス アカウントに暗号鍵へのアクセス権を付与
  3. 暗号鍵を使用して、環境変数を暗号化

という手順で、準備完了です。以下のようにスクリプト化しておくと簡単です。

# ここは自由に変更してください。
KEYRING_NAME="test-keyring"
KEY_NAME="test-key"
MY_SECRET="***" # Step2で取得したトークン
SERVICE_ACCOUNT="********" # ****@cloudbuild.gserviceaccount.com
gcloud kms keyrings create ${KEYRING_NAME} --location=globalgcloud kms keys create ${KEY_NAME} --location=global --keyring=${KEYRING_NAME} --purpose=encryptiongcloud kms keys add-iam-policy-binding \
${KEY_NAME} --location=global --keyring=${KEYRING_NAME} \
--member=serviceAccount:${SERVICE_ACCOUNT}@cloudbuild.gserviceaccount.com \
--role=roles/cloudkms.cryptoKeyEncrypterDecrypter
echo -n ${MY_SECRET} | gcloud kms encrypt --plaintext-file=- --ciphertext-file=- \
--location=global \
--keyring=${KEYRING_NAME} \
--key=${KEY_NAME} | base64

最後のコマンドの実行結果を、Cloud Buildに記載します。

Step4. Cloud Buildでビルド

最後に、./quickstart/cloudbuild.yaml というファイルを作成し、ワークフローを記述します(太字の部分は、適宜書き換えてください)

secrets:
- kmsKeyName: projects/<PROJECT_NAME>/locations/global/keyRings/<KEYRING-NAME>/cryptoKeys/<KEY-NAME>
secretEnv:
FIREBASE_TOKEN: <Step3で取得した値>
steps:
- id: 'Generate html'
name: 'publysher/hugo'
args: ['hugo']
- id: "Deploy to Firebase Hosting"
name: 'gcr.io/$PROJECT_ID/firebase'
args: ['deploy']
secretEnv: ['FIREBASE_TOKEN']

上記が正しく動作するかどうか、以下のコマンドで手動のビルドを確認してみましょう。

$ gcloud builds submit --config cloudbuild.yaml .

問題無ければ、Cloud Source Repositories にリポジトリ(ここではtestという名前にします)を作成し、全てのコードをpushします。
最後に、以下のようにCloud Buildでトリガーを作成すれば完成です!

ソースを選択
リポジトリを選択
トリガー設定

リポジトリにプッシュすれば、ビルドが実行されることを確認できます。ビルドを実行した際の結果は、以下のようになります。

ビルドの詳細

まとめ

いかがだったでしょうか?
Google Cloud Buildを利用することで、CI/CDツールを自前で構築、運用することなく、フルマネージドなCI/CDを実現することができました。

マネージドサービスを用いることで、ビルド環境によって結果が変わってしまうというCI/CDのアンチパターンを防ぐことができます。

ぜひ、ご活用ください!

--

--

Yuki Iwanari
google-cloud-jp

Customer Engineer in Google Cloud. All views and opinions are my own.