Skip to content

cstanislawski/terraform-gcp-cloud-run-deploy

Repository files navigation

terraform-gcp-cloud-run-deploy

A Terraform module to deploy a Cloud Run Service using a Kubernetes-like syntax.

This module provides a Kubernetes-like interface for deploying Cloud Run services, making it easier for teams familiar with Kubernetes to adopt Cloud Run.

Why use this?

If you're coming from Kubernetes and want to deploy to Cloud Run, this module bridges the gap by providing:

  • Familiar syntax - Use the same metadata, spec, and template structures you know from Kubernetes
  • Smooth migration path - Existing Kubernetes YAML manifests can be adapted with minimal changes
  • Reduced learning curve - No need to learn Cloud Run-specific Terraform syntax from scratch
  • Manifest-driven deployments - Keep your configuration in version-controlled YAML files
  • Environment flexibility - Use the same manifest across environments with parameter overrides
  • Team consistency - Standardize deployments using familiar Kubernetes patterns

Instead of learning Cloud Run's native Terraform syntax, you can leverage your existing Kubernetes knowledge while still getting all the benefits of Cloud Run's serverless platform.

Features

  • Kubernetes-like syntax - Use familiar metadata, spec, and template structures
  • Manifest file support - Load configuration from YAML files
  • Parameter overrides - Direct module parameters override manifest values
  • Multiple containers - Support for sidecar containers (similar to Kubernetes pods)
  • Volume management - Support for secrets, Cloud SQL instances, and empty directories
  • Health checks - Startup and liveness probes with HTTP, TCP, and gRPC support
  • Resource management - CPU and memory limits with Cloud Run-specific optimizations
  • Environment variables - Support for both static values and secret references
  • Traffic management - Blue-green and canary deployments
  • Auto-scaling - Configure min/max instances (equivalent to replicas)

Usage

Using Manifest Files (Recommended)

Create a deployment.yaml file:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-app
  location: us-central1
  project: my-gcp-project
spec:
  replicas: 2
  template:
    metadata:
      labels:
        app: hello-app
    spec:
      containers:
      - name: hello-app
        image: gcr.io/google-samples/hello-app:2.0
        ports:
        - containerPort: 8080
        resources:
          limits:
            cpu: 1000m
            memory: 512Mi

Then use it in Terraform:

module "hello_app" {
  source = "github.com/cstanislawski/terraform-gcp-cloud-run-deploy"

  manifest_path = "./deployment.yaml"
}

Using Manifest Files with Overrides

module "hello_app_staging" {
  source = "github.com/cstanislawski/terraform-gcp-cloud-run-deploy"

  manifest_path = "./deployment.yaml"

  # Override for staging environment
  metadata = {
    name     = "hello-app-staging"
    location = "us-west1"
  }

  template = {
    spec = {
      containers = [
        {
          name = "hello-app"
          env = [
            {
              name  = "ENV"
              value = "staging"
            }
          ]
        }
      ]
    }
  }
}

Direct Configuration (No Manifest)

module "hello_app" {
  source = "github.com/cstanislawski/terraform-gcp-cloud-run-deploy"

  # Kubernetes-like metadata
  metadata = {
    name     = "hello-app"
    location = "us-central1"
    project  = "my-gcp-project"
  }

  # Kubernetes-like spec (replicas equivalent)
  spec = {
    replicas = 2
  }

  # Kubernetes-like template
  template = {
    metadata = {
      labels = {
        app = "hello-app"
      }
    }
    spec = {
      containers = [
        {
          name  = "hello-app"
          image = "gcr.io/google-samples/hello-app:2.0"

          ports = [
            {
              containerPort = 8080
            }
          ]

          resources = {
            limits = {
              cpu    = "1000m"
              memory = "512Mi"
            }
          }
        }
      ]
    }
  }
}

Examples

See the examples/ directory for complete working examples:

Requirements

Name Version
terraform >= 1.3
google >= 4.84.0

Providers

Name Version
google >= 4.84.0

Modules

No modules.

Resources

Name Type
google_cloud_run_v2_service.cloudrun_service resource

Inputs

Name Description Type Default Required
binaryAuthorization Binary authorization configuration for the Cloud Run service
object({
useDefault = optional(bool, false)
breakglassJustification = optional(string)
})
null no
client Arbitrary identifier for the API client string null no
client_version Arbitrary version identifier for the API client string null no
deletion_protection Whether Terraform will be prevented from destroying the service. Defaults to true. bool true no
description User-provided description of the Cloud Run service string null no
ingress Ingress configuration for the Cloud Run service string null no
invoker_iam_disabled Whether to disable IAM for the invoker. Defaults to false. bool false no
launch_stage The launch stage as defined by Google Cloud Platform Launch Stages string null no
manifest_path Path to a Kubernetes-like YAML manifest file. Direct module parameters will override manifest values. string null no
metadata Metadata for the Cloud Run service (similar to Kubernetes metadata)
object({
name = string
location = string
project = optional(string)
})
null no
spec Specification for the Cloud Run service (similar to Kubernetes spec)
object({
replicas = optional(number, 1)
})
null no
template Template specification for the Cloud Run service (similar to Kubernetes template)
object({
metadata = optional(object({
labels = optional(map(string), {})
}), {})
spec = object({
serviceAccountName = optional(string)
executionEnvironment = optional(string, "EXECUTION_ENVIRONMENT_GEN2")

vpcAccess = optional(object({
connector = optional(string)
egress = optional(string, "PRIVATE_RANGES_ONLY")
}))

nodeSelector = optional(object({
accelerator = optional(string)
}))

volumes = optional(list(object({
name = string
secret = optional(object({
secretName = string
defaultMode = optional(number, 0644)
items = optional(list(object({
version = string
path = string
mode = optional(number, 0644)
})))
}))
cloudSqlInstance = optional(object({
instances = list(string)
}))
emptyDir = optional(object({
medium = optional(string, "MEMORY")
sizeLimit = optional(string)
}))
})), [])

containers = list(object({
name = string
image = optional(string)
command = optional(list(string))
args = optional(list(string))
workingDir = optional(string)

env = optional(list(object({
name = string
value = optional(string)
valueFrom = optional(object({
secretKeyRef = optional(object({
name = string
key = string
}))
}))
})), [])

resources = optional(object({
limits = object({
cpu = string
memory = string
})
cpuIdle = optional(bool, true)
startupCpuBoost = optional(bool, false)
}))

ports = optional(list(object({
name = optional(string)
containerPort = number
})), [])

volumeMounts = optional(list(object({
name = string
mountPath = string
})), [])

startupProbe = optional(object({
initialDelaySeconds = optional(number, 0)
timeoutSeconds = optional(number, 1)
periodSeconds = optional(number, 10)
failureThreshold = optional(number, 3)

httpGet = optional(object({
path = optional(string, "/")
port = optional(number, 8080)
httpHeaders = optional(list(object({
name = string
value = string
})))
}))

tcpSocket = optional(object({
port = number
}))

grpc = optional(object({
port = optional(number, 8080)
service = optional(string)
}))
}))

livenessProbe = optional(object({
initialDelaySeconds = optional(number, 0)
timeoutSeconds = optional(number, 1)
periodSeconds = optional(number, 10)
failureThreshold = optional(number, 3)

httpGet = optional(object({
path = optional(string, "/")
port = optional(number, 8080)
httpHeaders = optional(list(object({
name = string
value = string
})))
}))

tcpSocket = optional(object({
port = number
}))

grpc = optional(object({
port = optional(number, 8080)
service = optional(string)
}))
}))

readinessProbe = optional(object({
initialDelaySeconds = optional(number, 0)
timeoutSeconds = optional(number, 1)
periodSeconds = optional(number, 10)
failureThreshold = optional(number, 3)

httpGet = optional(object({
path = optional(string, "/")
port = optional(number, 8080)
httpHeaders = optional(list(object({
name = string
value = string
})))
}))

tcpSocket = optional(object({
port = number
}))

grpc = optional(object({
port = optional(number, 8080)
service = optional(string)
}))
}))
}))
})
})
null no
traffic Traffic allocation for the Cloud Run service
list(object({
type = optional(string, "TRAFFIC_TARGET_ALLOCATION_TYPE_LATEST")
revision = optional(string)
percent = optional(number, 100)
tag = optional(string)
}))
null no

Outputs

Name Description
conditions The conditions of the Cloud Run service
latest_created_revision The latest created revision of the Cloud Run service
latest_ready_revision The latest ready revision of the Cloud Run service
location The location where the Cloud Run service is deployed
observed_generation The observed generation of the Cloud Run service
project The project where the Cloud Run service is deployed
service_id The unique identifier of the Cloud Run service
service_name The name of the Cloud Run service
service_uri The URL of the Cloud Run service
terminal_condition The terminal condition of the Cloud Run service
traffic The traffic allocation for the Cloud Run service

License

Apache 2.0 - see LICENSE file for details.

About

A Terraform module to deploy a Cloud Run Service using a Kubernetes-like syntax.

Resources

License

Stars

Watchers

Forks

Languages