☁️
Pub/SubでCloud Runをオーケストレーション
TL;DR
- サーバレスで複数のCloud RunをPub/Sub経由で実行します
はじめに
どうも、アニメマスターです。
生きていたら1つのトリガーで複数のCloud FunctionsやCloud Runを実行したくなることってありますよね?
ということで、それらを実装していく記事になります。
概観
SchedulerからPub/Subのトピックを呼び出して、Pub/SubからCloud RunをPushで実行します。
1. Artifact Registryにイメージを登録
公式のガイドなどを参考に、Cloud Runで利用するDockerイメージをArtifact Registryに登録しておきます。
2. Terraformでのリソース作成
今回作成するディレクトリは以下の様になります。
.
├── main.tf
├── modules
│ ├── cr
│ │ ├── main.tf
│ │ └── output.tf
│ ├── global
│ │ └── output.tf
│ └── pubsub
│ └── main.tf
2-1. globalモジュールに変数の設定
まずglobalモジュールにプロジェクトで利用する変数の設定ファイルを作ります。
<>書きのところは個人のものに置き換えてください。
modules/global/output.tf
output "project" {
description = "A name of a GCP project"
value = <YOUR_PROJECT>
}
output "region" {
description = "A name of a GCP region"
value = <YOUR_REGION>
}
output "service1_repository_path" {
description = "A path of a service1 container in GCP Artifact Registry repository"
value = <YOUR_REPOSITORY>
}
output "service2_repository_path" {
description = "A path of a service2 container in GCP Artifact Registry repository"
value = <YOUR_REPOSITORY>
}
output "sa_email" {
description = "A service account email"
value = <YOUR_SERVICE_ACCOUNT_EMAIL>
}
2-2. Cloud Runモジュールの作成
次にCloud Runのモジュールを作成していきます。
modules/cr/main.tf
module "global" {
source = "../global"
}
resource "google_cloud_run_v2_service" "service1" {
name = "service1"
project = module.global.project
location = module.global.region
template {
service_account = module.global.sa_email
scaling {
max_instance_count = 1
}
containers {
image = module.global.service1_repository_path
ports {
container_port = 8080
}
}
}
}
resource "google_cloud_run_v2_service" "service2" {
name = "service2"
project = module.global.project
location = module.global.region
template {
service_account = module.global.sa_email
scaling {
max_instance_count = 1
}
containers {
image = module.global.service2_repository_path
ports {
container_port = 8080
}
}
}
}
Cloud RunのモジュールはPub/Subのリソース作成時に利用するのでoutput.tf
で出力しておきます。
modules/cr/output.tf
output "service1_uri" {
value = google_cloud_run_v2_service.service1.uri
}
output "service2_uri" {
value = google_cloud_run_v2_service.service2.uri
}
2-3. Pub/Subモジュールの作成
最後にPub/Subのモジュールを作成していきます。
modules/pubsub/main.tf
module "global" {
source = "../global"
}
module "cr" {
source = "../cr"
}
resource "google_pubsub_topic" "default-topic" {
name = "default-topic"
}
resource "google_pubsub_subscription" "service1-subscription" {
name = "service1-subscription"
topic = google_pubsub_topic.default-topic.name
push_config {
push_endpoint = module.cr.service1_uri
oidc_token {
service_account_email = module.global.sa_email
}
attributes = {
x-goog-version = "v1"
}
}
retry_policy {
minimum_backoff = "60s"
maximum_backoff = "600s"
}
ack_deadline_seconds = 60
enable_message_ordering = true
depends_on = [module.cr.service1]
}
resource "google_pubsub_subscription" "service2-subscription" {
name = "service2-subscription"
topic = google_pubsub_topic.default-topic.name
push_config {
push_endpoint = module.cr.service2_uri
oidc_token {
service_account_email = module.global.sa_email
}
attributes = {
x-goog-version = "v1"
}
}
retry_policy {
minimum_backoff = "60s"
maximum_backoff = "600s"
}
ack_deadline_seconds = 60
enable_message_ordering = true
depends_on = [module.cr.service2]
}
resource "google_cloud_scheduler_job" "default-scheduler" {
project = module.global.project
region = module.global.region
name = "default-scheduler"
schedule = "0 6 * * *" # minute hour day-of-month month day-of-week
time_zone = "Asia/Tokyo"
pubsub_target {
topic_name = google_pubsub_topic.default-topic.id
data = base64encode("message")
}
retry_config {
retry_count = 1
}
depends_on = [google_pubsub_topic.default-topic]
}
おわりに
今回Cloud Runで実行しましたが、バッチ処理ならCloud Functionsで良い気もしますね。Cloud Runでも十分無料枠で賄えはしますが。
AWSならサーバレスコンポーネントのオーケストレーションはStep Functionsで行う気がしますが、GCPではWorkflowsではなくPub/Subを使う人が多い気がしています。
それでは、良きアニメライフを!
Discussion