terraform-google-cloud-run icon indicating copy to clipboard operation
terraform-google-cloud-run copied to clipboard

Cloud Run v2 module creating port for second container resulting in error

Open jeunii opened this issue 5 months ago • 1 comments

When deploying multiple containers in a cloud Run service using the resource, the ports assignment assigns a port to the second container.

Deploying a CloudRun service using the TF resource directly

resource "google_cloud_run_v2_service" "default" {
  name     = "cloudrun-service"
  project = "XXXXXXX"
  location = "us-central1"
  deletion_protection = false
  ingress = "INGRESS_TRAFFIC_ALL"
  template {
    containers {
      name = "hello-1"
      ports {
        container_port = 8080
      }
      image = "us-docker.pkg.dev/cloudrun/container/hello"
      depends_on = ["hello-2"]
    }
    containers {
      name = "hello-2"
      image = "us-docker.pkg.dev/cloudrun/container/hello"
      env {
        name = "PORT"
        value = "8081"
      }
      startup_probe {
        http_get {
          port = 8081
        }
      }
    }
  }
}

The plan in this case is

❯ tofu apply

OpenTofu used the selected providers to generate the following execution plan. Resource actions are indicated with
the following symbols:
  + create

OpenTofu will perform the following actions:

  # google_cloud_run_v2_service.default will be created
  + resource "google_cloud_run_v2_service" "default" {
      + conditions              = (known after apply)
      + create_time             = (known after apply)
      + creator                 = (known after apply)
      + delete_time             = (known after apply)
      + deletion_protection     = false
      + effective_annotations   = (known after apply)
      + effective_labels        = {
          + "goog-terraform-provisioned" = "true"
        }
      + etag                    = (known after apply)
      + expire_time             = (known after apply)
      + generation              = (known after apply)
      + id                      = (known after apply)
      + ingress                 = "INGRESS_TRAFFIC_ALL"
      + last_modifier           = (known after apply)
      + latest_created_revision = (known after apply)
      + latest_ready_revision   = (known after apply)
      + launch_stage            = (known after apply)
      + location                = "us-central1"
      + name                    = "cloudrun-service"
      + observed_generation     = (known after apply)
      + project                 = "XXXXXXXX"
      + reconciling             = (known after apply)
      + terminal_condition      = (known after apply)
      + terraform_labels        = {
          + "goog-terraform-provisioned" = "true"
        }
      + traffic_statuses        = (known after apply)
      + uid                     = (known after apply)
      + update_time             = (known after apply)
      + uri                     = (known after apply)
      + urls                    = (known after apply)

      + template {
          + max_instance_request_concurrency = (known after apply)
          + service_account                  = (known after apply)
          + timeout                          = (known after apply)

          + containers {
              + build_info = (known after apply)
              + depends_on = [
                  + "hello-2",
                ]
              + image      = "us-docker.pkg.dev/cloudrun/container/hello"
              + name       = "hello-1"

              + ports {
                  + container_port = 8080
                  + name           = (known after apply)
                }

              + resources (known after apply)

              + startup_probe (known after apply)
            }
          + containers {
              + build_info = (known after apply)
              + image      = "us-docker.pkg.dev/cloudrun/container/hello"
              + name       = "hello-2"

              + env {
                  + name  = "PORT"
                  + value = "8081"
                }

              + ports (known after apply)       # <----- Notice this 

              + resources (known after apply)

              + startup_probe {
                  + failure_threshold     = 3
                  + initial_delay_seconds = 0
                  + period_seconds        = 10
                  + timeout_seconds       = 1

                  + http_get {
                      + path = "/"
                      + port = 8081
                    }
                }
            }

          + scaling (known after apply)
        }

      + traffic (known after apply)
    }

Plan: 1 to add, 0 to change, 0 to destroy.

The resource is successfully created.

But when using the module

module "cloud_run_core" {
  source  = "GoogleCloudPlatform/cloud-run/google//modules/v2"
  version = "0.17.4"

  project_id      = "XXXXXX"
  service_name    = "hello-world"
  location        = "us-central1"
  containers      = [
    {
      container_image = "us-docker.pkg.dev/cloudrun/container/hello"
      container_name = "hello-world"
      ports = {
        name = "http1"
        container_port = 8080
      }
    },
    {
      container_image = "us-docker.pkg.dev/cloudrun/container/hello"
      container_name = "hello-world-2"
    }
  ]
}

The plan looks like this

❯ tofu apply

OpenTofu used the selected providers to generate the following execution plan. Resource actions are indicated with
the following symbols:
  + create

OpenTofu will perform the following actions:

  # module.cloud_run_core.google_cloud_run_v2_service.main will be created
  + resource "google_cloud_run_v2_service" "main" {
      + conditions              = (known after apply)
      + create_time             = (known after apply)
      + creator                 = (known after apply)
      + delete_time             = (known after apply)
      + deletion_protection     = true
      + effective_annotations   = (known after apply)
      + effective_labels        = {
          + "goog-terraform-provisioned" = "true"
        }
      + etag                    = (known after apply)
      + expire_time             = (known after apply)
      + generation              = (known after apply)
      + id                      = (known after apply)
      + ingress                 = "INGRESS_TRAFFIC_ALL"
      + last_modifier           = (known after apply)
      + latest_created_revision = (known after apply)
      + latest_ready_revision   = (known after apply)
      + launch_stage            = "GA"
      + location                = "us-central1"
      + name                    = "hello-world"
      + observed_generation     = (known after apply)
      + project                 = "XXXXXX
      + reconciling             = (known after apply)
      + terminal_condition      = (known after apply)
      + terraform_labels        = {
          + "goog-terraform-provisioned" = "true"
        }
      + traffic_statuses        = (known after apply)
      + uid                     = (known after apply)
      + update_time             = (known after apply)
      + uri                     = (known after apply)
      + urls                    = (known after apply)

      + template {
          + execution_environment            = "EXECUTION_ENVIRONMENT_GEN2"
          + max_instance_request_concurrency = (known after apply)
          + service_account                  = "hello-world-us-central1-sa@clx-nprd-apigee-x-44dd.iam.gserviceaccount.com"
          + timeout                          = (known after apply)

          + containers {
              + build_info = (known after apply)
              + image      = "us-docker.pkg.dev/cloudrun/container/hello"
              + name       = "hello-world"

              + ports {
                  + container_port = 8080
                  + name           = "http1"
                }

              + resources {
                  + cpu_idle          = true
                  + limits            = (known after apply)
                  + startup_cpu_boost = false
                }

              + startup_probe (known after apply)
            }
          + containers {
              + build_info = (known after apply)
              + image      = "us-docker.pkg.dev/cloudrun/container/hello"
              + name       = "hello-world-2"

              + ports {                                          # <-------- Ports being declared for second container
                  + container_port = 8080
                  + name           = "http1"
                }

              + resources {
                  + cpu_idle          = true
                  + limits            = (known after apply)
                  + startup_cpu_boost = false
                }

              + startup_probe (known after apply)
            }

          + scaling (known after apply)
        }

      + traffic (known after apply)
    }

  # module.cloud_run_core.google_service_account.sa[0] will be created
  + resource "google_service_account" "sa" {
      + account_id   = "hello-world-us-central1-sa"
      + disabled     = false
      + display_name = "Service account for hello-world in us-central1"
      + email        = "[email protected]"
      + id           = (known after apply)
      + member       = "serviceAccount:[email protected]"
      + name         = (known after apply)
      + project      = "XXXXX"
      + unique_id    = (known after apply)
    }

Plan: 2 to add, 0 to change, 0 to destroy.

This results in the below error

│ Error: Error creating Service: googleapi: Error 400: template.containers: Revision template should contain exactly one container with an exposed port.
│ Details:
│ [
│   {
│     "@type": "type.googleapis.com/google.rpc.BadRequest",
│     "fieldViolations": [
│       {
│         "description": "Revision template should contain exactly one container with an exposed port.",
│         "field": "template.containers"
│       }
│     ]
│   }
│ ]
│ 
│   with module.cloud_run_core.google_cloud_run_v2_service.main,
│   on .terraform/modules/cloud_run_core/main.tf line 96, in resource "google_cloud_run_v2_service" "main":
│   96: resource "google_cloud_run_v2_service" "main" {
│ 
╵

The module should not specify a port for the second container.

jeunii avatar Jun 19 '25 13:06 jeunii

I believe this is a dupe of #302 and maybe fixed in #381

krissrex avatar Aug 14 '25 13:08 krissrex