Cloud Build を使ってCI/CDパイプラインを構築してみた

記事タイトルとURLをコピーする

G-gen エンジニアの又吉です。今回は、Google Cloud のビルドサービスであるCloud Build を使って、Cloud Functions のCD/CDパイプラインを構築してみました。

Cloud Build を用いた Cloud Functions のCI/CDパイプライン

Cloud Build の概要

Cloud Build とは

Cloud Build とは Google Cloud でビルドを実行するサーバレスかつマネージドなビルドサービスです。

Cloud Build は Github をはじめ様々なリポジトリサービスと連携し仕様に合わせてビルドを実行したり、Pub/Sub 等のイベントに応じてビルドを実行できます。

また、ビルドのみならず Cloud Run や Google Kubernetes Engine (GKE) 、 Cloud Functions へのデプロイにも Cloud Build が用いられます。

Cloud Build では ビルド構成ファイル と呼ばれる設定ファイルでビルドやデプロイの方法を指示します。構成ファイルの指示に基づき、コンテナが起動してタスクが自動的に実行される仕組みです。

実行方法

Cloud Build は、Google Cloud コンソールやgcloud CLI からも実行できますが、ビルドトリガーを使用してビルドを実行することも可能です。

ビルドトリガーとは、GithubなどのソースリポジトリとCloud Build を連携しておくことで、ソースリポジトリに変更があった際、 Cloud Build を実行してビルドを自動化できる機能です。

ライフサイクル

一般的な Cloud Build のライフサイクルを以下に記載します。

  1. Cloud Build の命令が含まれる YAML または JSON 形式のビルド構成ファイルを作成
  2. Cloud Build にビルドを送信(または、ビルドトリガーが起動)
  3. Cloud Build はビルド構成ファイルに基づいてビルドを実行

2つの利用パターン

Cloud Build には、デフォルトプールプライベートプールという2つの利用パターンがあります。

従来からあったデフォルトプールは、クラウド上でホスティングされたリソースにしか機能できないことが課題でした。 そこで、ユーザーのプライベートネットワーク内でもサーバレスのビルド環境を活用するためにプライベートプールがリリースされた背景があります。

プライベートプールではその他にも、マシンタイプを柔軟に選べたり、最大同時実行数が引き上げられたりと、デフォルトプールに比べカスタマイズ性が高いのも特徴です。

料金

Cloud Build はマシンタイプとビルドの実行時間(分単位)で料金が決まります。

デフォルトプールでは、以下のマシンタイプ毎に、1ビルド分あたりの料金が変わってきます。 また、e2-medium には無料枠があり、1日あたり120ビルド分が無料となります(2022年8月現在)。 ※クイックスタートとは、プロビジョニングの遅延なしにビルドを実行します。

プライベートプールでは、以下のマシンタイプ毎に、1ビルド分あたりの料金が変わってきます。

例として、デフォルトプールでマシンタイプがe2-medium の場合、1ヵ月での合計ビルド実行時間が4,500分 [1日あたり150分、1ヵ月は30日換算] だとすると 351円 / 月です(2022年8月時点、東京リージョン、130円/ドル)。

最新の利用料金は以下の公式ページでご確認ください。また、公式の見積もりツールで料金が試算できます。

作成するもの

今回は、Cloud Functions のコード管理をGithub 上で行い、Github のmain ブランチの更新をトリガーに Cloud Functions へデプロイを自動化してくれる仕組みを構築したいと思います。

Cloud Functions の作成

まずはCloud Functions を新規作成していきます。

Cloud Functions関数の作成 から、関数を新規作成します。 関数名は「cloud-build-demo」として、認証は「未認証の呼び出しを許可」にして、その他はそのままで次に進みます。

コードでは、ランタイムに「Pyrhon3.9」を選択し、その他はデフォルトのままデプロイします。

また、Github上にCloud Functions のデフォルトのソースコードを記述したcloud-build-demoリポジトリを作成しておきます。

Cloud Build の作成

ビルドトリガーの作成

Cloud Buildトリガー から、ビルドトリガーを作成します。

名前を「cloud-build-demo」とし、ソースのリポジトリから「新しいリポジトリに接続」を選択します。 Githubを選択すると認証画面に切り替わりますので認証を済ませると、Githubの「アカウント」と「リポジトリ」を選択できます。 対象のGithubアカウントとリポジトリを選択して接続します。

これでビルドトリガー の設定は完了です。

Github リポジトリを変更

Github からローカルにクローンを作成

ローカル環境にクローンを作成して、ローカルでファイルの追加や編集を行っていきます。 対象リポジトリのリモートURLをコピーして、ターミナルから以下を実行します。

matayuuu@penguin:~$ git clone https://github.com/ggen-matayuuu/cloud-build-demo.git
Cloning into 'cloud-build-demo'...
remote: Enumerating objects: 4, done.
remote: Counting objects: 100% (4/4), done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 4 (delta 0), reused 0 (delta 0), pack-reused 0
Receiving objects: 100% (4/4), done.

クローンが作成されたことを確認します。

matayuuu@penguin:~$ ls
cloud-build-demo 

開発用ブランチ(dev)を作成

次に、開発用ブランチを作成します。 まずは、クローンしたディレクトリへ移動します。

matayuuu@penguin:~$ cd cloud-build-demo
matayuuu@penguin:~/cloud-build-demo$
# ブランチ一覧を表示(*がついているのが現在いるブランチ)
matayuuu@penguin:~/cloud-build-demo$ git branch     
*main
# 開発用ブランチを作成
matayuuu@penguin:~/cloud-build-demo$ git branch dev
# ブランチ一覧を表示(確認)
matayuuu@penguin:~/cloud-build-demo$ git branch
 dev
*main
# 開発用ブランチに移動
matayuuu@penguin:~/cloud-build-demo$ git checkout dev     
Switched to branch ‘dev’
# ブランチ一覧を表示(確認)
matayuuu@penguin:~/cloud-build-demo$ git branch
*dev
 main

Cloud Buildの構成ファイルを作成

Cloud Functions のデプロイは gcloud functions deploy コマンドを使用して関数をデプロイできるため、Cloud Build から gcloud functions deploy コマンドを実行させるよう構成ファイルのビルドステップを作成します。

今回の構成ファイルは、main.py と同階層に、ファイル名を「cloudbuild.yaml」として作成します。 構成ファイルの記述方法は、こちらの公式リファレンスを参考にしました。

「cloudbuild.yaml」には以下のビルドステップを記述しました。

steps:
- name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
  args:
  - gcloud
  - functions
  - deploy
  - cloud-build-demo
  - --region=us-central1
  - --source=.
  - --trigger-http
  - --runtime=python39

また、変更箇所がわかるようにmain.py のreturn(戻り値)を「Hello World!matayuuu!」に修正しました。

def hello_world(request):
    """Responds to any HTTP request.
    Args:
        request (flask.Request): HTTP request object.
    Returns:
        The response text or any set of values that can be turned into a
        Response object using
        `make_response <http://flask.pocoo.org/docs/1.0/api/#flask.Flask.make_response>`.
    """
    request_json = request.get_json()
    if request.args and 'message' in request.args:
        return request.args.get('message')
    elif request_json and 'message' in request_json:
        return request_json['message']
    else:
        return f'Hello World!matayuuu!'

コミット

まずは今いるディレクトリ配下の全ての変更箇所を保存します。

# 追加・変更ファイルの保存
matayuuu@penguin:~/cloud-build-demo$ git add ./      
# 追加・変更したファイルをGitに登録
matayuuu@penguin:~/cloud-build-demo$ git commit -m"created cloudbuild.yaml and modified main.py"     
[dev bdf826f] created cloudbuild.yaml and modified main.py
 1 file changed, 11 insertions(+)
 create mode 100644 cloudbuild.yaml

プッシュ

# Githubへプッシュ
matayuuu@penguin:~/cloud-build-demo$ git push origin dev     
Enumerating objects: 4, done.
Counting objects: 100% (4/4), done.
Delta compression using up to 8 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 473 bytes | 157.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
remote: 
remote: Create a pull request for 'dev' on GitHub by visiting:
remote:      https://github.com/ggen-matayuuu/cloud-build-demo/pull/new/dev
remote: 
To https://github.com/ggen-matayuuu/cloud-build-demo.git
 * [new branch]      dev -> dev

mainブランチにdevブランチをマージ

# mainブランチに移動
matayuuu@penguin:~/cloud-build-demo$ git checkout main     
Switched to branch 'main'
Your branch is up to date with 'origin/main'.
# mainブランチにdevブランチをマージ
matayuuu@penguin:~/cloud-build-demo$ git merge dev     
Updating 9e27d6a..bdf826f
Fast-forward
 cloudbuild.yaml | 11 +++++++++++
 1 file changed, 11 insertions(+)
 create mode 100644 cloudbuild.yaml

無事、Githubのリポジトリが更新されました。

Cloud Build の確認

Github のmain ブランチが変更された為、Cloud Build のログを確認します。

ERROR: (gcloud.functions.deploy) ResponseError: status=[403], code=[Ok], message=[Permission 'cloudfunctions.functions.get' denied on resource 'projects/matayuuu/locations/us-central1/functions/cloud-build-demo' (or resource may not exist).]

ビルドトリガーは実行されていましたが、ビルドステップ中にエラーが発生しました。 エラーログによると、Cloud Build サービス アカウントに「cloudfunctions.functions.get 」という権限が不足しているとのことでした。

Cloud Build設定 より、Cloud Functions のステータスを「有効にする」に変更し、「すべてのサービスアカウントにアクセス権を付与」を選択すると Cloud Build のサービスアカウントに Cloud Functions 開発者 の権限が付与されます。

再度、Githubのリポジトリを変更し、Cloud Build をトリガーしたいと思います。

ローカル側のmain.py の戻り値を「Hello World!matayuuu!g-gen!」に変更して、先程の要領で Github にプッシュしました。 Github 上のmain ブランチの変更により、Cloud Build が実行されます。

再度、ログを確認すると、ビルド成功です。

念の為、Cloud Functions のソースも確認すると変更箇所も反映されてました。

Cloud Build を用いると、リポジトリの変更をトリガーにデプロイの自動化を実現できるため、デプロイ工数が削減できました。 Cloud Functionsだけでなく、Google Cloud のさまざまなサービスと容易に連携ができるので、今後は積極的に活用していきたいです。

又吉 佑樹(記事一覧)

クラウドソリューション部

はいさい、沖縄出身のクラウドエンジニア!

セールスからエンジニアへ転身。Google Cloud 全 11 資格保有。Google Cloud Champion Innovator (AI/ML)。Google Cloud Partner Top Engineer 2024。Google Cloud 公式ユーザー会 Jagu'e'r でエバンジェリストとして活動中。好きな分野は AI/ML。