データエンジニアをしています。
運用しているデータパイプラインの一部にGoogle CloudのWorkflowsとCloud Functionsを用いておりますが、デプロイの俊敏性・正確性に課題があります。(コピペ・手動デプロイをやめたいです)
Terraformを使用してこれらを解消できないか、検証をしたことを共有します。
想定読者
- Terraform初心者
- Terraformを業務に導入してみたいと考えている人
- 既存のデプロイフローや手法に課題があると考えている人
試したことをかんたんに
- WorkflowsとCloud Functionsをterraformでデプロイした
- Cloud FunctionsはローカルのソースコードをZIP化してGCSにアップロードし、それをもとにCloudFunctionsをデプロイした
- 外部ファイル(ローカルのソースコードのファイル)を読み込む形でWorkflowsのソースコードを指定した
試した環境・構成
- Cloud Shell
work
└ archive
└ cloudfuncitons
└ test_function1
└ main.zip
└ cloudfunctions
└ test_function1
└ main.py
└ workflows
└ test_workflows
└ test_workflow.yml
└ main.tf
archive
Cloud FunctionsをデプロイするためにZIP化したソースコードを格納するディレクトリ。
実運用ではCloud FunctionsだけでなくLambdaも使用予定なので、サービス名別・関数名別にディレクトリを作成している。
cloudfunctions
デプロイするCloud Functionsのソースコードを格納するディレクトリ。
workflows
デプロイするWorkflowsのソースコードを格納するディレクトリ。
main.tf
Cloud FunctionsやWorkflowsとそれに関連するリソースの構成情報を記載したtfファイル。
Cloud Functionsのソースコード
Hello Worldを出力するシンプルなコードです。
def hello_world(request):
print('Hello World')
return 'Hello from Cloud Functions!'
Workflowsのソースコード
Cloud Functionsを呼び出すシンプルなコードです。
- invoke_test_function1:
call: http.get
args:
url: "Cloud FuncitonsのURL"
auth:
type: OIDC
result: response
- logResponse:
call: sys.log
args:
text: ${response.body}
severity: "INFO"
Terraformのソースコード
プロバイダの設定
provider "google" {
project = "プロジェクト名"
region = "asia-northeast1"
}
Cloud Functionsの構成情報
# CloudFunctionsのソースコードを格納するGoogle Cloud Storageバケット
resource "google_storage_bucket" "cloud_functions_bucket" {
name = "バケット名"
location = "asia-northeast1"
# アクセスレベルを均一化
uniform_bucket_level_access = true
# 公開アクセスを「非公開」に
public_access_prevention = "enforced"
}
# CloudFunctionsのソースコードをGCSのオブジェクトとしてアップロードする
resource "google_storage_bucket_object" "test_function1" {
name = data.archive_file.function_archive.output_path
bucket = google_storage_bucket.cloud_functions_bucket.name
source = data.archive_file.function_archive.output_path
}
# CloudFunctionsのローカルのソースコードをZIP化して、ローカルのarchiveディレクトリに格納する(このZIPファイルをGCSにアップロードする)
data "archive_file" "function_archive" {
type = "zip"
source_dir = "cloudfunctions/test_function1"
output_path = "archive/cloudfunctions/test_function1/main.zip"
}
# CloudFunctionsの構成情報
resource "google_cloudfunctions_function" "test_function1" {
name = "test_function1"
description = "An example Cloud Function"
runtime = "python310"
# GCSにアップロードしたソースコードをもとにデプロイする
source_archive_bucket = google_storage_bucket_object.test_function1.bucket
source_archive_object = google_storage_bucket_object.test_function1.source
available_memory_mb = 128
entry_point = "hello_world"
trigger_http = true
https_trigger_security_level = "SECURE_ALWAYS"
timeout = 60
}
Workflowsの構成情報
# Workflowsの構成情報
resource "google_workflows_workflow" "test_workflow" {
name = "test_workflow"
description = "An example workflow"
# ローカルのymlファイルをソースコードとしてデプロイする
# ${path.module}はTerraformファイルがあるディレクトリを表します
source_contents = file("${path.module}/workflows/test_workflows/test_workflow.yml")
# TODO: 既存サービスアカウントもTerraformで扱えるようにimportしたい
service_account = "既存のサービスアカウント"
}
ハマったポイント
結果としてterraform apply
でのデプロイは成功したのですが、それまでにいくつかハマったポイントがあったので、記録しておきます。
Workflowsのソースコードを外部から読み込む
TerraformやGoogle Cloudのドキュメントを見ていると、Workflowsのソースコードはtfファイルに直書きしている例が多かったです。
しかし、これだと保守性も悪くなりそうですし、テキスト容量の制限(32KB)もあったので、外部ファイルを読み込むことができないか模索しました。
結果、Terraformのfile
関数とpath.module
変数を用い、下記のように外部ファイルを読み込むことができました。
file("${path.module}/workflows/test_workflows/test_workflow.yml")
参考1:google_workflows_workflow
参考2:Terraform を使用してワークフローを作成する
WorkflowsからCloud Functionsを呼び出すとき
これはTerraform関連の話ではないのですが、WorkflowsからCloud Functionsを呼び出すとき、403エラーが出でしまいました。
Workflowsには十分な権限を付与していたのですが、エラーとなってしまいました。
ドキュメントをみるとauth
セクションを加えることで認証情報を付与してCloud Functionsを呼び出すことができるようでした。
Cloud Functions や Cloud Run にリクエストを送信するときは、OIDC を使用して認証します。
OIDC を使用して HTTP リクエストを行うには、URL を指定した後に、ワークフローの定義の args セクションに auth セクションを追加します。この例では、Cloud Functions を呼び出すために、リクエストが送信されます。
今後の展望
- 既存のリソースをTerraformで管理できるようにする
- すでに運用しているデータパイプラインをTerraformで扱えるようにする
- Step FunctionsとLambdaもTerraformで管理できるようにする
- すでに運用しているデータパイプラインはStep FuncitonsとLambdaも使用しているため
- Githubとクラウド環境のソースコードおよび構成情報を一致させるために、CI/CDパイプラインとTerraformを連携させる
- Github ActionsとTerraformを組み合わせてデプロイの俊敏性・正確性を上げる