GCPサービスの1つ、Cloud BuildはいわゆるCI/CDツールです。 GithubなどGitレポジトリに紐づけてトリガーさせて使うのが普通だと思います。UIから設定できるトリガーとしても現状、リポジトリ経由しか選択できません。
しかし、業務のある都合でCloud Storage経由でデプロイしたいことがありまして。 やり方を模索してみてうまくいったので、メモっておきます。
ソース
こちらに置いてます。
abekoh/gcp-deploy-from-storage
全体像
今回はhello-funcというファンクションを、tar.gzに圧縮したソースからCloud Functionsにデプロイするというシナリオとします。 デプロイ対象はApp Engineとか、別のサービスでもいけるはず。
デプロイ対象
シンプルにHTTPリクエストおくるとHelloが返ってくるFunctionです。Node.jsで書きます。
// index.js
exports.hello = (req, res) => {
res.send('Hello, world!');
}
これと、npm init
で生成したpackage.jsonを含んだhello-func.tar.gzを作っておきます。
tar zcvf hello-func.tar.gz index.js package.json
ビルドファンクション実装
メインとなるビルド用ファンクションです。
Storageのイベントをトリガーとして発火させ、Cloud BuildのAPIを叩いてビルド、デプロイを実行します。
Node.js用のGoogle APIクライアントとして、普通はこちらを使いますが
googlespis/google-api-nodejs-client
READMEにも書かれている通り、GCP上で利用する場合は下記のライブラリのほうが使い勝手いいみたいです。
Cloud Buildの依存を追加します。
npm init
npm i -S @google-cloud/cloudbuild
ビルド用Functionsの実装はこちら。
// index.js
'use strict';
const {CloudBuildClient} = require('@google-cloud/cloudbuild');
exports.build = async file => {
// file.metageneration: メタ情報が更新されるとインクリメントされる値
// ファイル自体が更新されるときは'1'となる
if (file.metageneration !== '1') {
return;
}
// Promiseを返却することで、解決させてfunctionsが終了する
return new CloudBuildClient().createBuild({
projectId: process.env.GCP_PROJECT_ID,
build: {
source: {
storageSource: {
// バケット名
bucket: file.bucket,
// ファイル名
object: file.name
}
},
steps: [
{
"name": "gcr.io/cloud-builders/gcloud",
"args": [
"functions",
"deploy",
"hello-func",
"--entry-point=hello",
"--runtime=nodejs10",
"--memory=128MB",
"--region=us-central1",
"--trigger-http"
]
}
]
}
});
};
createBuildというメソッドで、任意のオプションからCloud Buildを起動させます。 このリクエストではリポジトリだけでなくCloud Storageを指定することでき、今回やりたかったことが達成できます。
また、リクエストにプロジェクトIDを含める必要があります。
Node.js 8系までは GCP_PROJECT
という環境変数で取得できたようですが、Node.js 10系では取得できなくなったようです。
環境変数の使用 | Google Cloud Functions に関するドキュメント
仕方ないので、デプロイ時のコマンドラインで指定することにしました。 以下のコマンドでbuild-funcをデプロイします。
gcloud functions deploy build-func \
--entry-point=build \
--runtime=nodejs10 \
--memory=256MB \
--region=us-central1 \
--trigger-bucket=src-func \
--set-env-vars GCP_PROJECT_ID={GCPプロジェクト名}
--trigger-bucket
には、デプロイしたいファイルを置くバケットを指定します。
Cloud Buildの権限設定
Cloud Buildを使って対象を初めてデプロイする場合、権限設定が必要です。 今回はCloud Functionsをデプロイするのでその開発者と、サービスアカウントユーザーが必要なので付与します。
動作確認
準備が整ったところで、Storageの対象バケットにアップロードしてみます。
gsutil cp hello-func.tar.gz gs://src-func/hello-func.tar.gz
このように、正常hello-funcがデプロイされました。
まとめ
ちょっと面倒ではありますが、ちょっと工夫するだけで実現できたので良かったです。 こんな感じで、トリガーに設定できなくてもAPIが存在すればFunctionsでなんとかなるってことは他にもあるかもですね。