Terraformで簡単なNode.jsアプリケーションをCloud Run作ってみた
表題の通りです。
Cloud RunでのNode.jsのアプリケーションのサンプルはあったり、
Terraformでのサンプルとかはあったりしたのですが、上の2つの組み合わせがあまりなかったので試してみました。
Terraform
# main.tf terraform { required_providers { google = { source = "hashicorp/google" version = "5.40.0" } } } resource "google_artifact_registry_repository" "example_repository" { project = var.project_id location = var.location repository_id = "example" format = "DOCKER" } resource "google_cloud_run_v2_service" "example_cloud_run_service" { project = var.project_id location = var.location name = "example" ingress = "INGRESS_TRAFFIC_ALL" template { scaling { min_instance_count = 0 max_instance_count = 1 } containers { image = "${google_artifact_registry_repository.example_repository.location}-docker.pkg.dev/${var.project_id}/${google_artifact_registry_repository.example_repository.repository_id}/init" } } } resource "google_cloud_run_v2_service_iam_member" "example_cloud_run_service_iam_member" { location = var.location project = var.project_id role = "roles/run.invoker" member = "allUsers" service = google_cloud_run_v2_service.example_cloud_run_service.name }
#variables.tf variable "project_id" { type = string } variable "location" { default = "asia-northeast1" }
Artifact RegistryとCloud Runをつなぐ
Google Cloudによせたかったので、imageのregistryにはArtifact Registryを利用しました。
Artifact Registryで作ったものをCloud Runのimage部分に参照させます。
今回試している間は上のコードをterraform applyして毎回当てていましたが、長期的なことを考えると初回の適用だけterraform apply経由で行い、その後は別の形でimageをupし、そのupsしたイメージをCloud Runにあてるよう修正する必要があると思いました。
Cloud RunのAPIを利用したい場合
Cloud Runは作成したタイミングで独自のURLを持っています。
あまりそれ自身をそのまま使うことはないでしょうが、今回はそこまでかしこまったアプリケーションを作りたかったわけではなかったので、動作確認にそのURLを叩く形を取りました。
いざ作成が完了したあとにそのURLを叩いてみたところ
Your client does not have permission to get URL / from this server.
という表示がでました。
なにも意識せずCloud Runのスタックを作った場合、認証部分は「認証が必要」な状態で作られていました。
画面上から切り替えてもよかったのですが、せっかくなのでそちらもTerraformに起こしてみました。
その結果は上にあるコードの以下の部分です
resource "google_cloud_run_v2_service_iam_member" "example_cloud_run_service_iam_member" { location = var.location project = var.project_id role = "roles/run.invoker" member = "allUsers" service = google_cloud_run_v2_service.example_cloud_run_service.name }
こちらのiam_memberの設定を上のようにすると未認証で叩ける状態を実現できます。
他のパターンで疎通を試したい場合以下の記事が参考にできるかと思います。
困ったポイント
実際にdeployした際にこのような表示に悩まされました。
Error: Error waiting to create Service: Error waiting for Creating Service: Error code 13, message: Revision 'example-00001-9b8' is not ready and cannot serve traffic. The user-provided container failed to start and listen on the port defined provided by the PORT=8080 environment variable. Logs for this revision might contain more information. Logs URL: https://console.cloud.google.com/logs/viewer?project=xxx&resource=cloud_run_revision/service_name/example/revision_name/example-00001-9b8&advancedFilter=resource.type%3D%22cloud_run_revision%22%0Aresource.labels.service_name%3D%22example%22%0Aresource.labels.revision_name%3D%example-00001-9b8%22 For more troubleshooting guidance, see https://cloud.google.com/run/docs/troubleshooting#container-failed-to-start
Cloud Runのアプリケーションが外とうまくつながっていないようでした。
環境変数の PORT は基本的に 8080 で設定されているようなので、自分の場合はDockerfile内で EXPOSE をするのを忘れていたのが一つ目の原因でした。
そしてEXPOSEしても動かないなと思い改めて以下の記事を眺めていました。
コンテナ ランタイムの契約に従って、コンテナ イメージを 64 ビット Linux 用にコンパイルされていることを確認します。
結論から申し上げるとdocker buildの際にplatformの指定をする必要があった、ということでした
docker build --platform linux/amd64 -t asia-northeast1-docker.pkg.dev/${PROJECT_ID}/example/${IMAGE_TAG}:latest .
気軽にCloud Runを試せるようになったので、もっといろいろ試していきたいと思います。