📝

Cloud Functions:CI/CDパイプラインの構築手順

2024/07/22に公開

はじめに

こんにちは、クラウドエースの岸本です。
今回は、Google Cloud 上で CI/CD パイプラインを構築し Cloud Functions を自動デプロイする手順を紹介します。
初心者の方にもわかりやすく解説していますので是非参考にしてみてください。

構成図

構成図は以下の通りです。
構成図

CI/CD パイプラインを構成する主要なサービスは以下の通りです。

  • Cloud Functions
    Cloud Functions は、Google Cloud のマネージド型サーバーレス関数プラットフォームであり、サーバーの管理やスケーリングを意識せずにコードを実行できます。
    HTTP リクエスト、Cloud Storage イベント、Pub/Sub メッセージなど、さまざまなトリガーに対応しています。
    また、Cloud Functions には第 1 世代と第 2 世代があり、第 2 世代は Cloud Run 上に構築されているため、構成図に Cloud Run が含まれます。
    詳しい比較については公式ドキュメントの表の表を参照してください。

  • Cloud Build
    Cloud Build は、Google Cloud のマネージド型のビルドサービスで、コードのビルド、テスト、デプロイを自動化することができます。
    Cloud Build から様々なプロダクトを対象としてデプロイすることができますが、今回のケースでは、Cloud Functions を対象としてデプロイします。
    Cloud Build のリポジトリは、第 1 世代と第 2 世代があり、今回は第 2 世代を使用します。
    世代の違いは、弊社のテックブログまたは、公式ドキュメントを参照してください。

構築手順

構築手順は以下の通りです。

    1. 環境変数設定と API 有効化
    1. Cloud Build の設定
    1. ソースコードの作成
    1. CI/CD のテスト

1. 環境変数設定と API 有効化

共通の値を環境変数として設定します。

export _project_id='Project ID'
export _region='us-central1'

次に今回使用する API を有効化します。

  • Cloud Build
  • Secret Manager
  • Cloud Functions
  • Cloud Run

コンソール画面で「Cloud Shell」を開き、上記の API を有効にする以下のコマンドを実行します。

// APIの有効化
gcloud services enable \
    cloudbuild.googleapis.com \
    secretmanager.googleapis.com \
    cloudfunctions.googleapis.com \
    run.googleapis.com \
    --project=${_project_id}

// APIの有効化確認
gcloud beta services list --enabled --project=${_project_id}
コンソール画面での手順

コンソール画面で「Cloud Build」と検索し、以下の画面「有効にする」をクリックします。
1

コンソール画面で「Secret Manager」と検索し、以下の画面「有効にする」をクリックします。
2

コンソール画面で「Cloud Functions」と検索し、以下の画面「有効にする」をクリックします。
2-1

コンソール画面で「API とサービス」と検索し、以下の赤枠をクリックします。
2-2
検索バーに「Cloud Run」と検索し、「有効にする」をクリックします。
2-3

2. Cloud Build の設定

GitHub リポジトリに対するPushをトリガーとする、Cloud Functions の自動デプロイのためのパイプラインを作成します。

Cloud Build の設定の手順は以下の通りです。
2-1. GitHub リポジトリの連携
2-2. サービスアカウントの作成
2-3. GCS バケットの作成
2-4. トリガーの作成

・ 2-1. GitHub リポジトリの連携

GitHub リポジトリを Cloud Build に連携を行います。
連携することで、GitHub リポジトリのイベントを検知することができます。
GitHub リポジトリの連携はコンソール画面での手順のみとなります。

コンソール画面での手順

コンソール画面で「Cloud Build」を開き、[リポジトリ]の[ホスト接続を作成]をクリックします。
3

以下のように入力し、[接続]をクリックします。
4

認証の画面が表示されます。「continue」をクリックします。
5

GitHub のアプリ認証を行います。赤枠をクリックします。
6

自身の GitHub アカウントを選択し、リポジトリへのアクセスを選択します。
7

リポジトリの選択を行い、[Save]をクリックします。
8

リポジトリが連携されました。
9

最後にリポジトリをリンクさせます。
以下の画面で[リポジトリをリンク]をクリックします。
10

以下のように入力し、[リンク]をクリックします。
11

・ 2-2. サービスアカウントの作成

サービスアカウントを 3 つ作成します。

  • Cloud Build 用
    Cloud Build 自身が使用するサービスアカウントで、ビルドステップを実行します。
    Cloud Storage のバケットにログを保存するために必要です。
  • Cloud Functions 用
    Cloud Functions が使用するサービスアカウントです。
  • Cloud Functions デプロイ用
    Cloud Build が Cloud Functions をデプロイする際に使用するサービスアカウントです。
    Artifacts Registry からイメージを取得するために必要です。

以下はサービスアカウントと各プロダクトの関係を示した図です。
サービスアカウント

各プロダクトのサービスアカウントを指定しない場合、Compute Engine のデフォルトのサービスアカウントが使用されます。
しかし、セキュリティ上の理由から、各プロダクトにはそれぞれのサービスアカウントを作成し、適切な権限を付与することが推奨されています。
今回は、①が Cloud Build 用、②が Cloud Functions 用、③が Cloud Functions のデプロイ用のサービスアカウントを作成し、それぞれのプロダクトに適切な権限を付与します。
後述のサービスアカウント作成手順で、各サービスアカウントに適切なロールを付与していきます。

コマンドラインでの手順
  • Cloud Build 用サービスアカウント
    以下のコマンドを実行します。
    名前は任意ですが、ここでは「sa-build」としています。
// サービスアカウントの作成
gcloud beta iam service-accounts create sa-build \
  --display-name="sa-build" \
  --project=${_project_id}

次にロールを付与します。

// ストレージ管理者のロール付与
gcloud beta projects add-iam-policy-binding ${_project_id} \
  --member="serviceAccount:sa-build@${_project_id}.iam.gserviceaccount.com" \
  --role="roles/storage.admin" \
  --condition None

// サービスアカウントユーザーのロール付与
gcloud beta projects add-iam-policy-binding ${_project_id} \
  --member="serviceAccount:sa-build@${_project_id}.iam.gserviceaccount.com" \
  --role="roles/iam.serviceAccountUser" \
  --condition None

// Cloud Functions管理者のロール付与
gcloud beta projects add-iam-policy-binding ${_project_id} \
  --member="serviceAccount:sa-build@${_project_id}.iam.gserviceaccount.com" \
  --role="roles/cloudfunctions.admin" \
  --condition None
  • Cloud Functions 用サービスアカウント
    以下のコマンドを実行します。
    名前は任意ですが、ここでは「sa-functions」としています。
    Cloud Functions からほかのサービスを呼び出さないため、ロールの付与は行いません。
// サービスアカウントの作成
gcloud beta iam service-accounts create sa-functions \
  --display-name="sa-functions" \
  --project=${_project_id}
  • Cloud Functions デプロイ用サービスアカウント
    以下のコマンドを実行します。
    名前は任意ですが、ここでは「sa-trigger」としています。
// サービスアカウントの作成
gcloud beta iam service-accounts create sa-trigger \
  --display-name="sa-trigger" \
  --project=${_project_id}

次にロールを付与します。

// ストレージ管理者のロール付与
gcloud beta projects add-iam-policy-binding ${_project_id} \
  --member="serviceAccount:sa-trigger@${_project_id}.iam.gserviceaccount.com" \
  --role="roles/storage.admin" \
  --condition None

// Artifact Registry 管理者ロール付与
gcloud beta projects add-iam-policy-binding ${_project_id} \
  --member="serviceAccount:sa-trigger@${_project_id}.iam.gserviceaccount.com" \
  --role="roles/artifactregistry.admin" \
  --condition None

// ログ書き込みのロール付与
gcloud beta projects add-iam-policy-binding ${_project_id} \
  --member="serviceAccount:sa-build@${_project_id}.iam.gserviceaccount.com" \
  --role="roles/logging.logWriter" \
  --condition None
コンソール画面での手順
コンソール画面での手順(Cloud Build 用サービスアカウントの作成)

コンソール画面で「IAM と管理」に移動し、[サービスアカウントを作成]を選択します。
以下の赤枠をクリックします。
12

「サービスアカウントの詳細」は以下の通りに入力し、[続行]をクリックします。

項目
サービスアカウント名 sa-build
サービスアカウント ID sa-build

13

次の「このサービス アカウントにプロジェクトへのアクセスを許可する」では、以下のロールを選択し、[続行]をクリックします。

  • ストレージ管理者
  • サービスアカウントユーザー
  • Cloud Functions 管理者

最後に「完了」します。

コンソール画面での手順(Cloud Functions 用サービスアカウントの作成)

コンソール画面で「IAM と管理」に移動し、[サービスアカウント]を選択します。
Cloud Build 用のサービスアカウントを作成した際と同様の手順を行います。

「サービスアカウントの詳細」は以下の通りに入力し、[続行]をクリックします。

項目
サービスアカウント名 sa-functions
サービスアカウント ID sa-functions

Cloud Functions 用サービスアカウントは、他のサービスとの連携がないため、ロールの付与は不要です。

最後に「完了」します。

コンソール画面での手順(Cloud Functions デプロイ用サービスアカウントの作成)

コンソール画面で「IAM と管理」に移動し、[サービスアカウント]を選択します。
Cloud Build 用のサービスアカウントを作成した際と同様の手順を行います。

「サービスアカウントの詳細」は以下の通りに入力し、[続行]をクリックします。

項目
サービスアカウント名 sa-trigger
サービスアカウント ID sa-trigger

次の「このサービス アカウントにプロジェクトへのアクセスを許可する」では、以下のロールを選択し、[続行]をクリックします。

  • ストレージ管理者
  • Artifact Registry 管理者
  • ログ書き込み

最後に「完了」します。

・ 2-3. GCS バケットの作成

Cloud Build のログを保存するための GCS バケットを作成します。
以下のコマンドを実行します。
バケット名はユニークなものを指定してください。
それを以下のgs://以下に記述してください。

gcloud storage buckets create gs://Unique_ID \
  --location ${_region} \
  --project ${_project_id}
コンソール画面での手順(GCS バケットの作成)

コンソール画面で「Cloud Storage」に移動し、[バケットを作成]をクリックします。
以下の赤枠で囲っている名前だけユニークなものを指定し後はデフォルトのままで[作成]をクリックします。
14

・ 2-4. トリガーの作成

GitHub のイベントを検知するトリガーの作成を行います。

イベントは以下の 3 つがあります。

  • ブランチに push する
  • 新しいタグを push する
  • pull リクエスト

今回は「ブランチに push する」を選択します。
このイベントは、GitHub リポジトリの指定したブランチにソースコードがプッシュされた際、Cloud Build が実行されるようになります。
実行される内容は、後ほど記述するcloudbuild.yamlに記述します。

トリガーを作成します。

gcloud beta builds triggers create github \
  --name="functions-cicd" \
  --region=${_region} \
  --build-config=cloudbuild.yaml \
  --repository="projects/${_project_id}/locations/${_region}/connections/functions-cicd/repositories/Antonnion-functions-cicd" \
  --branch-pattern=^main$ \
  --service-account="projects/${_project_id}/serviceAccounts/sa-build@${_project_id}.iam.gserviceaccount.com" \
  --project=${_project_id}
コンソール画面での手順

以下の赤枠をクリックします。
15

次に、設定値を以下のように設定し、そのほかはデフォルトのままにして[作成]をクリックします。

項目
名前 任意
リージョン us-central1
イベント ブランチに push する
ソース 第 2 世代
リポジトリ リポジトリを選択
ブランチ ^main$

3. ソースコードの作成

ここでは、Cloud Build の設定ファイルであるcloudbuild.yamlを作成します。また、Google Cloud Functions にデプロイするソースコードも作成します。

ディレクトリ構成は以下の通りです。

.
├── cloudbuild.yaml
└── src
    ├── main.py
    └── requirements.txt

・ 3-1. ディレクトリの作成

ローカル環境で上記のディレクトリ構成を作成します。
GitHub からクローンしたリポジトリのルートディレクトリに移動し、以下のコマンドを実行します。

// ディレクトリの作成
mkdir src

// ファイルの作成
touch cloudbuild.yaml
touch src/main.py
touch src/requirements.txt

・ 3-2. cloudbuild.yaml の作成

cloudbuild.yaml ファイルには、Cloud Functions のデプロイ設定を記述します。
Cloud Build のトリガーで設定したように、cloudbuild.yamlはルートディレクトリに配置します。

cloudbuild.yamlの内容は以下の通りです。

cloudbuild.yaml の作成
steps:
  - id: "CICD"
    name: "gcr.io/google.com/cloudsdktool/cloud-sdk"
    entrypoint: bash
    args:
      - -c
      - |
        gcloud beta functions deploy ${_FUNCTIONS_NAME} \
          --region=${_REGION} \
          --source=src/ \
          --runtime=${_RUN_TIME} \
          --trigger-http \
          --project=${PROJECT_ID} \
          --service-account=${_SERVICE_ACCOUNT_FUNCTIONS} \
          --build-service-account=projects/${PROJECT_ID}/serviceAccounts/${_SERVICE_ACCOUNT_TRIGGER} \
          --allow-unauthenticated

substitutions:
  _FUNCTIONS_NAME: "functions_cicd"
  _REGION: "us-central1"
  _SERVICE_ACCOUNT_FUNCTIONS: "sa-functions@${PROJECT_ID}.iam.gserviceaccount.com"
  _SERVICE_ACCOUNT_TRIGGER: "sa-trigger@${PROJECT_ID}.iam.gserviceaccount.com"
  _RUN_TIME: "python312"

logsBucket: "UNIQUE_ID"
serviceAccount: "projects/${PROJECT_ID}/serviceAccounts/sa-build@${PROJECT_ID}.iam.gserviceaccount.com"
options:
  logging: GCS_ONLY

・ 3-3. Cloud Functions のソースコードの作成

次に、Cloud Functions にデプロイするソースコードを作成します。
ここでは、HTTP リクエストを受け取り、レスポンスを返す簡単な関数を作成します。

main.py の作成
import functions_framework

@functions_framework.http
def functions_cicd(request):
    """HTTP Cloud Function.
    Args:
        request (flask.Request): The request object.
        <https://flask.palletsprojects.com/en/1.1.x/api/#incoming-request-data>
    Returns:
        The response text, or any set of values that can be turned into a
        Response object using `make_response`
        <https://flask.palletsprojects.com/en/1.1.x/api/#flask.make_response>.
    """
    request_json = request.get_json(silent=True)
    request_args = request.args

    if request_json and 'name' in request_json:
        name = request_json['name']
    elif request_args and 'name' in request_args:
        name = request_args['name']
    else:
        name = 'World'
    return 'Hello {}!'.format(name)

また、requirements.txt ファイルを作成し、必要なライブラリを記述します。

requirements.txt の作成
functions-framework==3.*

以上で、ソースコードの作成が完了しました。

4. CI/CD のテスト

最後に、GitHub リポジトリにソースコードをプッシュして CI/CD のテストを行います。
GitHub リポジトリにソースコードをプッシュすると、Cloud Build が自動的に実行され、Cloud Functions がデプロイされます。
さきほど作成したソースコードを GitHub リポジトリにプッシュしてみましょう。

git add .
git commit -m "first commit"
git push origin main

ログは Cloud Build のコンソール画面、「履歴」で確認できます。
以下の画面でビルドが完了していることを確認します。

16

最後に、Cloud Functions のコンソール画面でデプロイされていることを確認します。
17

URL をクリックし、Cloud Functions が正常に動作していることを確認します。
18

まとめ

以上で、Cloud Functions を用いて CI/CD パイプラインを構築する手順を紹介しました。
CI/CD パイプラインを構築することで、コードの変更が自動的にデプロイされるようになります。
この記事を参考に、Google Cloud のサービスを使用して CI/CD パイプラインを構築してみてください。

Discussion