GitHub ActionsからGoogle Cloud Functionsにデプロイ
2022-03-24
Photo Credit: Alex Machado
仕事でGoogle Cloud Functions(以下GCF)を使っており、今まではコマンドラインから手動デプロイしていたのですが、流石に漏れが怖いし時間もかかるということで、GitHub Actionsの導入のために調査したメモです。
.github/workflow/deployment.yamlの作成
まずはyamlファイルの全体像です。
name: Deployment to GCF
on:
push:
branches:
- main
jobs:
job_id:
runs-on: ubuntu-latest
permissions:
contents: 'read'
id-token: 'write'
steps:
- uses: 'actions/checkout@v3'
- name: Node.js setup
uses: 'actions/setup-node@v2'
with:
node-version: 16.x
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn cache dir)"
- uses: actions/cache@v2
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- run: yarn install
- run: yarn build
- id: 'auth'
uses: 'google-github-actions/auth@v0'
with:
workload_identity_provider: "${{secrets.GCP_WORKLOAD_IDENTITY_PROVIDER}}"
service_account: "${{secrets.GCP_SERVICE_ACCOUNT}}"
- id: 'deploy'
uses: 'google-github-actions/deploy-cloud-functions@v0'
with:
name: "your-functions-name"
region: "asia-northeast1"
runtime: "nodejs16"
memory_mb: 512 #MB
entry_point: "main"
timeout: 300 #second
# event_trigger_typeはデフォルトでhttpなので、それ以外の場合指定する必要あり
# デフォルトでは認証を通っていない第三者のアクセスは拒否する設定になっている
前半部分は以前 GitHub ActionsでCI/CDパイプライン構築で記事を書いたのと同様なので、説明はそちらに譲ります。今回は主に後半部分、具体的には name:auth
以降の説明をしていけたらと思います。
全体
google-github-actionsを利用する
今回、GitHub Actionsを用いてCloud Functionsにデプロイしていくに際して、Googleが提供している2つのアクションを利用します。 それぞれ、認証とデプロイに活用していくので、分けて説明していきます。
https://github.com/google-github-actions/deploy-cloud-functions
https://github.com/google-github-actions/auth
APIの有効化
まずは、Cloud Functions APIを有効にする必要があります。
APIを有効にしたら、あとは認証とデプロイの2部構成です。
認証
認証には大きくWorkload Identity連携を使った認証とJSON service account keyを使った認証の2パターンがあります。
今回はセキュリティ的にも推奨されているWorkload Identityを利用した認証を利用します。
ドキュメントの手順に従って、コマンドラインから設定を行っていきます。
まずは環境変数にプロジェクトIDを登録しておきます。
export PROJECT_ID="your_project_id"
次にサービスアカウントの作成。
gcloud iam service-accounts create "my-service-account" \
--project "${PROJECT_ID}"
作成したサービスアカウントに対してCloud Functionsをデプロイする権限を付与。
gcloud projects add-iam-policy-binding "${PROJECT_ID}" \
--role="roles/cloudfunctions.developer" \
--member="serviceAccount:service-account-name@project-name.iam.gserviceaccount.com"
次に、Workload Identity Poolの作成
gcloud iam workload-identity-pools create "pool-name" \
--project="${PROJECT_ID}" \
--location="global" \
--display-name="This is test Pool"
次に、Workload Identity PoolのIDを取得します
gcloud iam workload-identity-pools describe "pool-name" \
--project="${PROJECT_ID}" \
--location="global" \
--format="value(name)"
projects/123456789012/locations/global/workloadIdentityPools/pool-name
環境変数に取得したIDを登録
export WORKLOAD_IDENTITY_POOL_ID="projects/123456789012/locations/global/workloadIdentityPools/pool-name"
Providerを作成
gcloud iam workload-identity-pools providers create-oidc "pool-provider" \
--project="${PROJECT_ID}" \
--location="global" \
--workload-identity-pool="pool-name" \
--display-name="Pool Provider" \
--attribute-mapping="google.subject=assertion.sub,attribute.actor=assertion.actor,attribute.repository=assertion.repository" \
--issuer-uri="https://token.actions.githubusercontent.com"
GitHub repositoryを環境変数に登録する
export REPO="username/name"
Workload identity Providerとサービスアカウントとの紐付けを行い、認証を通ることができるようにします。
gcloud iam service-accounts add-iam-policy-binding "my-service-account@${PROJECT_ID}.iam.gserviceaccount.com" \
--project="${PROJECT_ID}" \
--role="roles/iam.workloadIdentityUser" \
--member="principalSet://iam.googleapis.com/${WORKLOAD_IDENTITY_POOL_ID}/attribute.repository/${REPO}"
これだけだと、Permission 'iam.serviceaccounts.actAs' denied on service account ~~という感じでロールが足りないので付与します。
gcloud projects add-iam-policy-binding "${PROJECT_ID}" \
--role="roles/iam.serviceAccountUser" \
--member="serviceAccount:service-account-name@project-name.iam.gserviceaccount.com"
serviceAccountUserも足りていなかったので付与します。
gcloud projects add-iam-policy-binding "${PROJECT_ID}" \
--role="roles/iam.serviceAccountUser" \
--member="serviceAccount:service-account-name@project-name.iam.gserviceaccount.com"
最後に、Workload Identity Providerのresource nameを取得して完了です。
gcloud iam workload-identity-pools providers describe "my-provider" \
--project="${PROJECT_ID}" \
--location="global" \
--workload-identity-pool="my-pool" \
--format="value(name)"
projects/123456789012/locations/global/workloadIdentityPools/my-pool/providers/my-provider
recourse nameと最初に作成したサービスアカウントのメールアドレスを用いて、認証を通すことができます。
この際、Environment secretsに先ほど取得したWorkload identity providerの resource nameとサービスアカウントのメールアドレスを登録しておく必要があります。
https://github.com/username/repository_name/settings/secrets/actions から設定できます。
# .github/workflow/deployment.yaml抜粋
- id: 'auth'
uses: 'google-github-actions/auth@v0'
with:
workload_identity_provider: "${{secrets.GCP_WORKLOAD_IDENTITY_PROVIDER}}"
service_account: "${{secrets.GCP_SERVICE_ACCOUNT}}"
デプロイ
認証ができたら次はデプロイです。こっちはシンプルで、コマンドラインからgcloudを用いてデプロイしたことがある人ならとっつき易いかと思います。
- id: 'deploy'
uses: 'google-github-actions/deploy-cloud-functions@v0'
with:
name: "your-functions-name"
region: "asia-northeast1"
runtime: "nodejs16"
memory_mb: 512 #MB
entry_point: "main"
timeout: 300 #second
# event_trigger_typeはデフォルトでhttpなので、それ以外の場合指定する必要あり
# デフォルトでは認証を通っていない第三者のアクセスは拒否する設定になっている
with以下で、GCFにデプロイする際の設定を記述しています。これ以外にも追加可能なオプションはたくさんあるので、気になる方はこちらを参照してください。
今回私が活用した設定だけそれぞれ説 明しておきます。
コマンドラインからデプロイする際には文字列を""
で囲う必要がないのですが、yamlファイルを作成するときには ""
で囲わないと型が合わずエラーになるので注意です。
【name】
GCFのエンドポイントにも使われる名称です。
登録した名称が以下のようにエンドポイントの末に入ります。
https://asia-northeast1-project-name.cloudfunctions.net/function-name
【region】
デプロイするリージョンを選択します。
【runtime】
ランタイムを設定します。
【memory_mb】
メモリを設定します。gcloudコマンドでコマンドラインからデプロイを行う場合、-memory=512MB
というような書き方をしていると思うのですが、GitHub Actionsでは memory_mb=512
と書き方が少し異なるので注意が必要です。
【entry-point】
エントリーポイントを指定します。エンドポイントにリクエストが来たときに実行する関数です。
また、 package.json
にてエントリーポイントがあるファイルを指定してやる必要があり ます。そのため、TypeScriptなど、デプロイ前にビルドが必要な言語で開発している場合にはビルドファイルを package.json
で指定したファイルと合わせる必要があります。
"name": "function-name",
"version": "1.0.0",
"main": "dist/index.js",
"license": "MIT",
"types": "commonjs",
【timeout】
timeoutもgcloudコマンドでのデプロイとは少し異なるので注意です。
gcloudコマンドでは timeout=300s
だったところが、GitHub Actionsでは timeout: 300
と単位が不要になっています。