Deploy and Manage Cloud Run Services

The gcp:cloudrun/service:Service resource, part of the Pulumi GCP provider, defines a Cloud Run service that runs containers with automatic scaling, HTTPS termination, and managed infrastructure. This guide focuses on four capabilities: container deployment with traffic routing, Cloud SQL integration, health probes and multi-container sidecars, and public access configuration. Note that this resource is maintained for backwards compatibility; for new projects, consider using gcp.cloudrunv2.Service, which provides improved developer experience and broader feature support.

Services require container images in a registry and may reference Cloud SQL instances or IAM policies that must exist separately. The examples are intentionally small and show how each capability is configured. Combine them with your own container images, databases, and access policies.

Deploy a container with automatic scaling

Most deployments start with a container image and traffic routing to the latest revision. Cloud Run handles HTTPS termination, autoscaling, and zero-downtime deployments.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const _default = new gcp.cloudrun.Service("default", {
    name: "cloudrun-srv",
    location: "us-central1",
    template: {
        spec: {
            containers: [{
                image: "us-docker.pkg.dev/cloudrun/container/hello",
            }],
        },
    },
    traffics: [{
        percent: 100,
        latestRevision: true,
    }],
});
import pulumi
import pulumi_gcp as gcp

default = gcp.cloudrun.Service("default",
    name="cloudrun-srv",
    location="us-central1",
    template={
        "spec": {
            "containers": [{
                "image": "us-docker.pkg.dev/cloudrun/container/hello",
            }],
        },
    },
    traffics=[{
        "percent": 100,
        "latest_revision": True,
    }])
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/cloudrun"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := cloudrun.NewService(ctx, "default", &cloudrun.ServiceArgs{
			Name:     pulumi.String("cloudrun-srv"),
			Location: pulumi.String("us-central1"),
			Template: &cloudrun.ServiceTemplateArgs{
				Spec: &cloudrun.ServiceTemplateSpecArgs{
					Containers: cloudrun.ServiceTemplateSpecContainerArray{
						&cloudrun.ServiceTemplateSpecContainerArgs{
							Image: pulumi.String("us-docker.pkg.dev/cloudrun/container/hello"),
						},
					},
				},
			},
			Traffics: cloudrun.ServiceTrafficArray{
				&cloudrun.ServiceTrafficArgs{
					Percent:        pulumi.Int(100),
					LatestRevision: pulumi.Bool(true),
				},
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var @default = new Gcp.CloudRun.Service("default", new()
    {
        Name = "cloudrun-srv",
        Location = "us-central1",
        Template = new Gcp.CloudRun.Inputs.ServiceTemplateArgs
        {
            Spec = new Gcp.CloudRun.Inputs.ServiceTemplateSpecArgs
            {
                Containers = new[]
                {
                    new Gcp.CloudRun.Inputs.ServiceTemplateSpecContainerArgs
                    {
                        Image = "us-docker.pkg.dev/cloudrun/container/hello",
                    },
                },
            },
        },
        Traffics = new[]
        {
            new Gcp.CloudRun.Inputs.ServiceTrafficArgs
            {
                Percent = 100,
                LatestRevision = true,
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.cloudrun.Service;
import com.pulumi.gcp.cloudrun.ServiceArgs;
import com.pulumi.gcp.cloudrun.inputs.ServiceTemplateArgs;
import com.pulumi.gcp.cloudrun.inputs.ServiceTemplateSpecArgs;
import com.pulumi.gcp.cloudrun.inputs.ServiceTrafficArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var default_ = new Service("default", ServiceArgs.builder()
            .name("cloudrun-srv")
            .location("us-central1")
            .template(ServiceTemplateArgs.builder()
                .spec(ServiceTemplateSpecArgs.builder()
                    .containers(ServiceTemplateSpecContainerArgs.builder()
                        .image("us-docker.pkg.dev/cloudrun/container/hello")
                        .build())
                    .build())
                .build())
            .traffics(ServiceTrafficArgs.builder()
                .percent(100)
                .latestRevision(true)
                .build())
            .build());

    }
}
resources:
  default:
    type: gcp:cloudrun:Service
    properties:
      name: cloudrun-srv
      location: us-central1
      template:
        spec:
          containers:
            - image: us-docker.pkg.dev/cloudrun/container/hello
      traffics:
        - percent: 100
          latestRevision: true

The template.spec.containers block specifies your container image. The traffics block routes 100% of requests to the latest revision. Cloud Run creates a unique HTTPS endpoint and scales from zero to many instances based on incoming traffic.

Connect to Cloud SQL from your service

Applications that need relational database access can connect to Cloud SQL instances through Cloud Run’s built-in proxy, avoiding manual VPC configuration.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const instance = new gcp.sql.DatabaseInstance("instance", {
    name: "cloudrun-sql",
    region: "us-east1",
    databaseVersion: "MYSQL_5_7",
    settings: {
        tier: "db-f1-micro",
    },
    deletionProtection: true,
});
const _default = new gcp.cloudrun.Service("default", {
    name: "cloudrun-srv",
    location: "us-central1",
    template: {
        spec: {
            containers: [{
                image: "us-docker.pkg.dev/cloudrun/container/hello",
            }],
        },
        metadata: {
            annotations: {
                "autoscaling.knative.dev/maxScale": "1000",
                "run.googleapis.com/cloudsql-instances": instance.connectionName,
                "run.googleapis.com/client-name": "demo",
            },
        },
    },
    autogenerateRevisionName: true,
});
import pulumi
import pulumi_gcp as gcp

instance = gcp.sql.DatabaseInstance("instance",
    name="cloudrun-sql",
    region="us-east1",
    database_version="MYSQL_5_7",
    settings={
        "tier": "db-f1-micro",
    },
    deletion_protection=True)
default = gcp.cloudrun.Service("default",
    name="cloudrun-srv",
    location="us-central1",
    template={
        "spec": {
            "containers": [{
                "image": "us-docker.pkg.dev/cloudrun/container/hello",
            }],
        },
        "metadata": {
            "annotations": {
                "autoscaling.knative.dev/maxScale": "1000",
                "run.googleapis.com/cloudsql-instances": instance.connection_name,
                "run.googleapis.com/client-name": "demo",
            },
        },
    },
    autogenerate_revision_name=True)
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/cloudrun"
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/sql"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		instance, err := sql.NewDatabaseInstance(ctx, "instance", &sql.DatabaseInstanceArgs{
			Name:            pulumi.String("cloudrun-sql"),
			Region:          pulumi.String("us-east1"),
			DatabaseVersion: pulumi.String("MYSQL_5_7"),
			Settings: &sql.DatabaseInstanceSettingsArgs{
				Tier: pulumi.String("db-f1-micro"),
			},
			DeletionProtection: pulumi.Bool(true),
		})
		if err != nil {
			return err
		}
		_, err = cloudrun.NewService(ctx, "default", &cloudrun.ServiceArgs{
			Name:     pulumi.String("cloudrun-srv"),
			Location: pulumi.String("us-central1"),
			Template: &cloudrun.ServiceTemplateArgs{
				Spec: &cloudrun.ServiceTemplateSpecArgs{
					Containers: cloudrun.ServiceTemplateSpecContainerArray{
						&cloudrun.ServiceTemplateSpecContainerArgs{
							Image: pulumi.String("us-docker.pkg.dev/cloudrun/container/hello"),
						},
					},
				},
				Metadata: &cloudrun.ServiceTemplateMetadataArgs{
					Annotations: pulumi.StringMap{
						"autoscaling.knative.dev/maxScale":      pulumi.String("1000"),
						"run.googleapis.com/cloudsql-instances": instance.ConnectionName,
						"run.googleapis.com/client-name":        pulumi.String("demo"),
					},
				},
			},
			AutogenerateRevisionName: pulumi.Bool(true),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var instance = new Gcp.Sql.DatabaseInstance("instance", new()
    {
        Name = "cloudrun-sql",
        Region = "us-east1",
        DatabaseVersion = "MYSQL_5_7",
        Settings = new Gcp.Sql.Inputs.DatabaseInstanceSettingsArgs
        {
            Tier = "db-f1-micro",
        },
        DeletionProtection = true,
    });

    var @default = new Gcp.CloudRun.Service("default", new()
    {
        Name = "cloudrun-srv",
        Location = "us-central1",
        Template = new Gcp.CloudRun.Inputs.ServiceTemplateArgs
        {
            Spec = new Gcp.CloudRun.Inputs.ServiceTemplateSpecArgs
            {
                Containers = new[]
                {
                    new Gcp.CloudRun.Inputs.ServiceTemplateSpecContainerArgs
                    {
                        Image = "us-docker.pkg.dev/cloudrun/container/hello",
                    },
                },
            },
            Metadata = new Gcp.CloudRun.Inputs.ServiceTemplateMetadataArgs
            {
                Annotations = 
                {
                    { "autoscaling.knative.dev/maxScale", "1000" },
                    { "run.googleapis.com/cloudsql-instances", instance.ConnectionName },
                    { "run.googleapis.com/client-name", "demo" },
                },
            },
        },
        AutogenerateRevisionName = true,
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.sql.DatabaseInstance;
import com.pulumi.gcp.sql.DatabaseInstanceArgs;
import com.pulumi.gcp.sql.inputs.DatabaseInstanceSettingsArgs;
import com.pulumi.gcp.cloudrun.Service;
import com.pulumi.gcp.cloudrun.ServiceArgs;
import com.pulumi.gcp.cloudrun.inputs.ServiceTemplateArgs;
import com.pulumi.gcp.cloudrun.inputs.ServiceTemplateSpecArgs;
import com.pulumi.gcp.cloudrun.inputs.ServiceTemplateMetadataArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var instance = new DatabaseInstance("instance", DatabaseInstanceArgs.builder()
            .name("cloudrun-sql")
            .region("us-east1")
            .databaseVersion("MYSQL_5_7")
            .settings(DatabaseInstanceSettingsArgs.builder()
                .tier("db-f1-micro")
                .build())
            .deletionProtection(true)
            .build());

        var default_ = new Service("default", ServiceArgs.builder()
            .name("cloudrun-srv")
            .location("us-central1")
            .template(ServiceTemplateArgs.builder()
                .spec(ServiceTemplateSpecArgs.builder()
                    .containers(ServiceTemplateSpecContainerArgs.builder()
                        .image("us-docker.pkg.dev/cloudrun/container/hello")
                        .build())
                    .build())
                .metadata(ServiceTemplateMetadataArgs.builder()
                    .annotations(Map.ofEntries(
                        Map.entry("autoscaling.knative.dev/maxScale", "1000"),
                        Map.entry("run.googleapis.com/cloudsql-instances", instance.connectionName()),
                        Map.entry("run.googleapis.com/client-name", "demo")
                    ))
                    .build())
                .build())
            .autogenerateRevisionName(true)
            .build());

    }
}
resources:
  default:
    type: gcp:cloudrun:Service
    properties:
      name: cloudrun-srv
      location: us-central1
      template:
        spec:
          containers:
            - image: us-docker.pkg.dev/cloudrun/container/hello
        metadata:
          annotations:
            autoscaling.knative.dev/maxScale: '1000'
            run.googleapis.com/cloudsql-instances: ${instance.connectionName}
            run.googleapis.com/client-name: demo
      autogenerateRevisionName: true
  instance:
    type: gcp:sql:DatabaseInstance
    properties:
      name: cloudrun-sql
      region: us-east1
      databaseVersion: MYSQL_5_7
      settings:
        tier: db-f1-micro
      deletionProtection: true

Cloud Run establishes a Unix socket connection to your Cloud SQL instance when you specify its connection name in the run.googleapis.com/cloudsql-instances annotation. The autogenerateRevisionName property tells Cloud Run to generate revision names automatically rather than requiring you to specify them in the template. Your container connects to the database via the standard Cloud SQL proxy path.

Configure health checks with startup and liveness probes

Services that need custom health check behavior can define startup probes to delay traffic during initialization and liveness probes to detect container failures.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const _default = new gcp.cloudrun.Service("default", {
    name: "cloudrun-srv",
    location: "us-central1",
    template: {
        spec: {
            containers: [{
                image: "us-docker.pkg.dev/cloudrun/container/hello",
                startupProbe: {
                    initialDelaySeconds: 0,
                    timeoutSeconds: 1,
                    periodSeconds: 3,
                    failureThreshold: 1,
                    tcpSocket: {
                        port: 8080,
                    },
                },
                livenessProbe: {
                    httpGet: {
                        path: "/",
                    },
                },
            }],
        },
    },
    traffics: [{
        percent: 100,
        latestRevision: true,
    }],
});
import pulumi
import pulumi_gcp as gcp

default = gcp.cloudrun.Service("default",
    name="cloudrun-srv",
    location="us-central1",
    template={
        "spec": {
            "containers": [{
                "image": "us-docker.pkg.dev/cloudrun/container/hello",
                "startup_probe": {
                    "initial_delay_seconds": 0,
                    "timeout_seconds": 1,
                    "period_seconds": 3,
                    "failure_threshold": 1,
                    "tcp_socket": {
                        "port": 8080,
                    },
                },
                "liveness_probe": {
                    "http_get": {
                        "path": "/",
                    },
                },
            }],
        },
    },
    traffics=[{
        "percent": 100,
        "latest_revision": True,
    }])
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/cloudrun"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := cloudrun.NewService(ctx, "default", &cloudrun.ServiceArgs{
			Name:     pulumi.String("cloudrun-srv"),
			Location: pulumi.String("us-central1"),
			Template: &cloudrun.ServiceTemplateArgs{
				Spec: &cloudrun.ServiceTemplateSpecArgs{
					Containers: cloudrun.ServiceTemplateSpecContainerArray{
						&cloudrun.ServiceTemplateSpecContainerArgs{
							Image: pulumi.String("us-docker.pkg.dev/cloudrun/container/hello"),
							StartupProbe: &cloudrun.ServiceTemplateSpecContainerStartupProbeArgs{
								InitialDelaySeconds: pulumi.Int(0),
								TimeoutSeconds:      pulumi.Int(1),
								PeriodSeconds:       pulumi.Int(3),
								FailureThreshold:    pulumi.Int(1),
								TcpSocket: &cloudrun.ServiceTemplateSpecContainerStartupProbeTcpSocketArgs{
									Port: pulumi.Int(8080),
								},
							},
							LivenessProbe: &cloudrun.ServiceTemplateSpecContainerLivenessProbeArgs{
								HttpGet: &cloudrun.ServiceTemplateSpecContainerLivenessProbeHttpGetArgs{
									Path: pulumi.String("/"),
								},
							},
						},
					},
				},
			},
			Traffics: cloudrun.ServiceTrafficArray{
				&cloudrun.ServiceTrafficArgs{
					Percent:        pulumi.Int(100),
					LatestRevision: pulumi.Bool(true),
				},
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var @default = new Gcp.CloudRun.Service("default", new()
    {
        Name = "cloudrun-srv",
        Location = "us-central1",
        Template = new Gcp.CloudRun.Inputs.ServiceTemplateArgs
        {
            Spec = new Gcp.CloudRun.Inputs.ServiceTemplateSpecArgs
            {
                Containers = new[]
                {
                    new Gcp.CloudRun.Inputs.ServiceTemplateSpecContainerArgs
                    {
                        Image = "us-docker.pkg.dev/cloudrun/container/hello",
                        StartupProbe = new Gcp.CloudRun.Inputs.ServiceTemplateSpecContainerStartupProbeArgs
                        {
                            InitialDelaySeconds = 0,
                            TimeoutSeconds = 1,
                            PeriodSeconds = 3,
                            FailureThreshold = 1,
                            TcpSocket = new Gcp.CloudRun.Inputs.ServiceTemplateSpecContainerStartupProbeTcpSocketArgs
                            {
                                Port = 8080,
                            },
                        },
                        LivenessProbe = new Gcp.CloudRun.Inputs.ServiceTemplateSpecContainerLivenessProbeArgs
                        {
                            HttpGet = new Gcp.CloudRun.Inputs.ServiceTemplateSpecContainerLivenessProbeHttpGetArgs
                            {
                                Path = "/",
                            },
                        },
                    },
                },
            },
        },
        Traffics = new[]
        {
            new Gcp.CloudRun.Inputs.ServiceTrafficArgs
            {
                Percent = 100,
                LatestRevision = true,
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.cloudrun.Service;
import com.pulumi.gcp.cloudrun.ServiceArgs;
import com.pulumi.gcp.cloudrun.inputs.ServiceTemplateArgs;
import com.pulumi.gcp.cloudrun.inputs.ServiceTemplateSpecArgs;
import com.pulumi.gcp.cloudrun.inputs.ServiceTrafficArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var default_ = new Service("default", ServiceArgs.builder()
            .name("cloudrun-srv")
            .location("us-central1")
            .template(ServiceTemplateArgs.builder()
                .spec(ServiceTemplateSpecArgs.builder()
                    .containers(ServiceTemplateSpecContainerArgs.builder()
                        .image("us-docker.pkg.dev/cloudrun/container/hello")
                        .startupProbe(ServiceTemplateSpecContainerStartupProbeArgs.builder()
                            .initialDelaySeconds(0)
                            .timeoutSeconds(1)
                            .periodSeconds(3)
                            .failureThreshold(1)
                            .tcpSocket(ServiceTemplateSpecContainerStartupProbeTcpSocketArgs.builder()
                                .port(8080)
                                .build())
                            .build())
                        .livenessProbe(ServiceTemplateSpecContainerLivenessProbeArgs.builder()
                            .httpGet(ServiceTemplateSpecContainerLivenessProbeHttpGetArgs.builder()
                                .path("/")
                                .build())
                            .build())
                        .build())
                    .build())
                .build())
            .traffics(ServiceTrafficArgs.builder()
                .percent(100)
                .latestRevision(true)
                .build())
            .build());

    }
}
resources:
  default:
    type: gcp:cloudrun:Service
    properties:
      name: cloudrun-srv
      location: us-central1
      template:
        spec:
          containers:
            - image: us-docker.pkg.dev/cloudrun/container/hello
              startupProbe:
                initialDelaySeconds: 0
                timeoutSeconds: 1
                periodSeconds: 3
                failureThreshold: 1
                tcpSocket:
                  port: 8080
              livenessProbe:
                httpGet:
                  path: /
      traffics:
        - percent: 100
          latestRevision: true

The startupProbe uses TCP socket checks to verify the container is ready before routing traffic, while the livenessProbe uses HTTP GET requests to detect runtime failures. The periodSeconds and failureThreshold properties control how often Cloud Run checks health and when to restart failed containers.

Deploy multiple containers with shared storage

Some applications benefit from sidecar patterns where multiple containers run in the same instance, sharing storage and coordinating startup order.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const _default = new gcp.cloudrun.Service("default", {
    name: "cloudrun-srv",
    location: "us-central1",
    template: {
        metadata: {
            annotations: {
                "run.googleapis.com/container-dependencies": JSON.stringify({
                    "hello-1": ["hello-2"],
                }),
            },
        },
        spec: {
            containers: [
                {
                    name: "hello-1",
                    ports: [{
                        containerPort: 8080,
                    }],
                    image: "us-docker.pkg.dev/cloudrun/container/hello",
                    volumeMounts: [{
                        name: "shared-volume",
                        mountPath: "/mnt/shared",
                    }],
                },
                {
                    name: "hello-2",
                    image: "us-docker.pkg.dev/cloudrun/container/hello",
                    envs: [{
                        name: "PORT",
                        value: "8081",
                    }],
                    startupProbe: {
                        httpGet: {
                            port: 8081,
                        },
                    },
                    volumeMounts: [{
                        name: "shared-volume",
                        mountPath: "/mnt/shared",
                    }],
                },
            ],
            volumes: [{
                name: "shared-volume",
                emptyDir: {
                    medium: "Memory",
                    sizeLimit: "128Mi",
                },
            }],
        },
    },
});
import pulumi
import json
import pulumi_gcp as gcp

default = gcp.cloudrun.Service("default",
    name="cloudrun-srv",
    location="us-central1",
    template={
        "metadata": {
            "annotations": {
                "run.googleapis.com/container-dependencies": json.dumps({
                    "hello-1": ["hello-2"],
                }),
            },
        },
        "spec": {
            "containers": [
                {
                    "name": "hello-1",
                    "ports": [{
                        "container_port": 8080,
                    }],
                    "image": "us-docker.pkg.dev/cloudrun/container/hello",
                    "volume_mounts": [{
                        "name": "shared-volume",
                        "mount_path": "/mnt/shared",
                    }],
                },
                {
                    "name": "hello-2",
                    "image": "us-docker.pkg.dev/cloudrun/container/hello",
                    "envs": [{
                        "name": "PORT",
                        "value": "8081",
                    }],
                    "startup_probe": {
                        "http_get": {
                            "port": 8081,
                        },
                    },
                    "volume_mounts": [{
                        "name": "shared-volume",
                        "mount_path": "/mnt/shared",
                    }],
                },
            ],
            "volumes": [{
                "name": "shared-volume",
                "empty_dir": {
                    "medium": "Memory",
                    "size_limit": "128Mi",
                },
            }],
        },
    })
package main

import (
	"encoding/json"

	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/cloudrun"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		tmpJSON0, err := json.Marshal(map[string]interface{}{
			"hello-1": []string{
				"hello-2",
			},
		})
		if err != nil {
			return err
		}
		json0 := string(tmpJSON0)
		_, err = cloudrun.NewService(ctx, "default", &cloudrun.ServiceArgs{
			Name:     pulumi.String("cloudrun-srv"),
			Location: pulumi.String("us-central1"),
			Template: &cloudrun.ServiceTemplateArgs{
				Metadata: &cloudrun.ServiceTemplateMetadataArgs{
					Annotations: pulumi.StringMap{
						"run.googleapis.com/container-dependencies": pulumi.String(json0),
					},
				},
				Spec: &cloudrun.ServiceTemplateSpecArgs{
					Containers: cloudrun.ServiceTemplateSpecContainerArray{
						&cloudrun.ServiceTemplateSpecContainerArgs{
							Name: pulumi.String("hello-1"),
							Ports: cloudrun.ServiceTemplateSpecContainerPortArray{
								&cloudrun.ServiceTemplateSpecContainerPortArgs{
									ContainerPort: pulumi.Int(8080),
								},
							},
							Image: pulumi.String("us-docker.pkg.dev/cloudrun/container/hello"),
							VolumeMounts: cloudrun.ServiceTemplateSpecContainerVolumeMountArray{
								&cloudrun.ServiceTemplateSpecContainerVolumeMountArgs{
									Name:      pulumi.String("shared-volume"),
									MountPath: pulumi.String("/mnt/shared"),
								},
							},
						},
						&cloudrun.ServiceTemplateSpecContainerArgs{
							Name:  pulumi.String("hello-2"),
							Image: pulumi.String("us-docker.pkg.dev/cloudrun/container/hello"),
							Envs: cloudrun.ServiceTemplateSpecContainerEnvArray{
								&cloudrun.ServiceTemplateSpecContainerEnvArgs{
									Name:  pulumi.String("PORT"),
									Value: pulumi.String("8081"),
								},
							},
							StartupProbe: &cloudrun.ServiceTemplateSpecContainerStartupProbeArgs{
								HttpGet: &cloudrun.ServiceTemplateSpecContainerStartupProbeHttpGetArgs{
									Port: pulumi.Int(8081),
								},
							},
							VolumeMounts: cloudrun.ServiceTemplateSpecContainerVolumeMountArray{
								&cloudrun.ServiceTemplateSpecContainerVolumeMountArgs{
									Name:      pulumi.String("shared-volume"),
									MountPath: pulumi.String("/mnt/shared"),
								},
							},
						},
					},
					Volumes: cloudrun.ServiceTemplateSpecVolumeArray{
						&cloudrun.ServiceTemplateSpecVolumeArgs{
							Name: pulumi.String("shared-volume"),
							EmptyDir: &cloudrun.ServiceTemplateSpecVolumeEmptyDirArgs{
								Medium:    pulumi.String("Memory"),
								SizeLimit: pulumi.String("128Mi"),
							},
						},
					},
				},
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var @default = new Gcp.CloudRun.Service("default", new()
    {
        Name = "cloudrun-srv",
        Location = "us-central1",
        Template = new Gcp.CloudRun.Inputs.ServiceTemplateArgs
        {
            Metadata = new Gcp.CloudRun.Inputs.ServiceTemplateMetadataArgs
            {
                Annotations = 
                {
                    { "run.googleapis.com/container-dependencies", JsonSerializer.Serialize(new Dictionary<string, object?>
                    {
                        ["hello-1"] = new[]
                        {
                            "hello-2",
                        },
                    }) },
                },
            },
            Spec = new Gcp.CloudRun.Inputs.ServiceTemplateSpecArgs
            {
                Containers = new[]
                {
                    new Gcp.CloudRun.Inputs.ServiceTemplateSpecContainerArgs
                    {
                        Name = "hello-1",
                        Ports = new[]
                        {
                            new Gcp.CloudRun.Inputs.ServiceTemplateSpecContainerPortArgs
                            {
                                ContainerPort = 8080,
                            },
                        },
                        Image = "us-docker.pkg.dev/cloudrun/container/hello",
                        VolumeMounts = new[]
                        {
                            new Gcp.CloudRun.Inputs.ServiceTemplateSpecContainerVolumeMountArgs
                            {
                                Name = "shared-volume",
                                MountPath = "/mnt/shared",
                            },
                        },
                    },
                    new Gcp.CloudRun.Inputs.ServiceTemplateSpecContainerArgs
                    {
                        Name = "hello-2",
                        Image = "us-docker.pkg.dev/cloudrun/container/hello",
                        Envs = new[]
                        {
                            new Gcp.CloudRun.Inputs.ServiceTemplateSpecContainerEnvArgs
                            {
                                Name = "PORT",
                                Value = "8081",
                            },
                        },
                        StartupProbe = new Gcp.CloudRun.Inputs.ServiceTemplateSpecContainerStartupProbeArgs
                        {
                            HttpGet = new Gcp.CloudRun.Inputs.ServiceTemplateSpecContainerStartupProbeHttpGetArgs
                            {
                                Port = 8081,
                            },
                        },
                        VolumeMounts = new[]
                        {
                            new Gcp.CloudRun.Inputs.ServiceTemplateSpecContainerVolumeMountArgs
                            {
                                Name = "shared-volume",
                                MountPath = "/mnt/shared",
                            },
                        },
                    },
                },
                Volumes = new[]
                {
                    new Gcp.CloudRun.Inputs.ServiceTemplateSpecVolumeArgs
                    {
                        Name = "shared-volume",
                        EmptyDir = new Gcp.CloudRun.Inputs.ServiceTemplateSpecVolumeEmptyDirArgs
                        {
                            Medium = "Memory",
                            SizeLimit = "128Mi",
                        },
                    },
                },
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.cloudrun.Service;
import com.pulumi.gcp.cloudrun.ServiceArgs;
import com.pulumi.gcp.cloudrun.inputs.ServiceTemplateArgs;
import com.pulumi.gcp.cloudrun.inputs.ServiceTemplateMetadataArgs;
import com.pulumi.gcp.cloudrun.inputs.ServiceTemplateSpecArgs;
import static com.pulumi.codegen.internal.Serialization.*;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var default_ = new Service("default", ServiceArgs.builder()
            .name("cloudrun-srv")
            .location("us-central1")
            .template(ServiceTemplateArgs.builder()
                .metadata(ServiceTemplateMetadataArgs.builder()
                    .annotations(Map.of("run.googleapis.com/container-dependencies", serializeJson(
                        jsonObject(
                            jsonProperty("hello-1", jsonArray("hello-2"))
                        ))))
                    .build())
                .spec(ServiceTemplateSpecArgs.builder()
                    .containers(                    
                        ServiceTemplateSpecContainerArgs.builder()
                            .name("hello-1")
                            .ports(ServiceTemplateSpecContainerPortArgs.builder()
                                .containerPort(8080)
                                .build())
                            .image("us-docker.pkg.dev/cloudrun/container/hello")
                            .volumeMounts(ServiceTemplateSpecContainerVolumeMountArgs.builder()
                                .name("shared-volume")
                                .mountPath("/mnt/shared")
                                .build())
                            .build(),
                        ServiceTemplateSpecContainerArgs.builder()
                            .name("hello-2")
                            .image("us-docker.pkg.dev/cloudrun/container/hello")
                            .envs(ServiceTemplateSpecContainerEnvArgs.builder()
                                .name("PORT")
                                .value("8081")
                                .build())
                            .startupProbe(ServiceTemplateSpecContainerStartupProbeArgs.builder()
                                .httpGet(ServiceTemplateSpecContainerStartupProbeHttpGetArgs.builder()
                                    .port(8081)
                                    .build())
                                .build())
                            .volumeMounts(ServiceTemplateSpecContainerVolumeMountArgs.builder()
                                .name("shared-volume")
                                .mountPath("/mnt/shared")
                                .build())
                            .build())
                    .volumes(ServiceTemplateSpecVolumeArgs.builder()
                        .name("shared-volume")
                        .emptyDir(ServiceTemplateSpecVolumeEmptyDirArgs.builder()
                            .medium("Memory")
                            .sizeLimit("128Mi")
                            .build())
                        .build())
                    .build())
                .build())
            .build());

    }
}
resources:
  default:
    type: gcp:cloudrun:Service
    properties:
      name: cloudrun-srv
      location: us-central1
      template:
        metadata:
          annotations:
            run.googleapis.com/container-dependencies:
              fn::toJSON:
                hello-1:
                  - hello-2
        spec:
          containers:
            - name: hello-1
              ports:
                - containerPort: 8080
              image: us-docker.pkg.dev/cloudrun/container/hello
              volumeMounts:
                - name: shared-volume
                  mountPath: /mnt/shared
            - name: hello-2
              image: us-docker.pkg.dev/cloudrun/container/hello
              envs:
                - name: PORT
                  value: '8081'
              startupProbe:
                httpGet:
                  port: 8081
              volumeMounts:
                - name: shared-volume
                  mountPath: /mnt/shared
          volumes:
            - name: shared-volume
              emptyDir:
                medium: Memory
                sizeLimit: 128Mi

The run.googleapis.com/container-dependencies annotation specifies that hello-1 depends on hello-2, ensuring Cloud Run starts them in order. Both containers mount the same emptyDir volume at /mnt/shared, providing ephemeral shared storage that persists for the instance lifetime. The ports block designates which container receives incoming HTTP requests.

Allow public access without authentication

Public-facing services that don’t require authentication need IAM bindings that grant the run.invoker role to allUsers.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const _default = new gcp.cloudrun.Service("default", {
    name: "cloudrun-srv",
    location: "us-central1",
    template: {
        spec: {
            containers: [{
                image: "us-docker.pkg.dev/cloudrun/container/hello",
            }],
        },
    },
});
const noauth = gcp.organizations.getIAMPolicy({
    bindings: [{
        role: "roles/run.invoker",
        members: ["allUsers"],
    }],
});
const noauthIamPolicy = new gcp.cloudrun.IamPolicy("noauth", {
    location: _default.location,
    project: _default.project,
    service: _default.name,
    policyData: noauth.then(noauth => noauth.policyData),
});
import pulumi
import pulumi_gcp as gcp

default = gcp.cloudrun.Service("default",
    name="cloudrun-srv",
    location="us-central1",
    template={
        "spec": {
            "containers": [{
                "image": "us-docker.pkg.dev/cloudrun/container/hello",
            }],
        },
    })
noauth = gcp.organizations.get_iam_policy(bindings=[{
    "role": "roles/run.invoker",
    "members": ["allUsers"],
}])
noauth_iam_policy = gcp.cloudrun.IamPolicy("noauth",
    location=default.location,
    project=default.project,
    service=default.name,
    policy_data=noauth.policy_data)
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/cloudrun"
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/organizations"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_default, err := cloudrun.NewService(ctx, "default", &cloudrun.ServiceArgs{
			Name:     pulumi.String("cloudrun-srv"),
			Location: pulumi.String("us-central1"),
			Template: &cloudrun.ServiceTemplateArgs{
				Spec: &cloudrun.ServiceTemplateSpecArgs{
					Containers: cloudrun.ServiceTemplateSpecContainerArray{
						&cloudrun.ServiceTemplateSpecContainerArgs{
							Image: pulumi.String("us-docker.pkg.dev/cloudrun/container/hello"),
						},
					},
				},
			},
		})
		if err != nil {
			return err
		}
		noauth, err := organizations.LookupIAMPolicy(ctx, &organizations.LookupIAMPolicyArgs{
			Bindings: []organizations.GetIAMPolicyBinding{
				{
					Role: "roles/run.invoker",
					Members: []string{
						"allUsers",
					},
				},
			},
		}, nil)
		if err != nil {
			return err
		}
		_, err = cloudrun.NewIamPolicy(ctx, "noauth", &cloudrun.IamPolicyArgs{
			Location:   _default.Location,
			Project:    _default.Project,
			Service:    _default.Name,
			PolicyData: pulumi.String(noauth.PolicyData),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var @default = new Gcp.CloudRun.Service("default", new()
    {
        Name = "cloudrun-srv",
        Location = "us-central1",
        Template = new Gcp.CloudRun.Inputs.ServiceTemplateArgs
        {
            Spec = new Gcp.CloudRun.Inputs.ServiceTemplateSpecArgs
            {
                Containers = new[]
                {
                    new Gcp.CloudRun.Inputs.ServiceTemplateSpecContainerArgs
                    {
                        Image = "us-docker.pkg.dev/cloudrun/container/hello",
                    },
                },
            },
        },
    });

    var noauth = Gcp.Organizations.GetIAMPolicy.Invoke(new()
    {
        Bindings = new[]
        {
            new Gcp.Organizations.Inputs.GetIAMPolicyBindingInputArgs
            {
                Role = "roles/run.invoker",
                Members = new[]
                {
                    "allUsers",
                },
            },
        },
    });

    var noauthIamPolicy = new Gcp.CloudRun.IamPolicy("noauth", new()
    {
        Location = @default.Location,
        Project = @default.Project,
        Service = @default.Name,
        PolicyData = noauth.Apply(getIAMPolicyResult => getIAMPolicyResult.PolicyData),
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.cloudrun.Service;
import com.pulumi.gcp.cloudrun.ServiceArgs;
import com.pulumi.gcp.cloudrun.inputs.ServiceTemplateArgs;
import com.pulumi.gcp.cloudrun.inputs.ServiceTemplateSpecArgs;
import com.pulumi.gcp.organizations.OrganizationsFunctions;
import com.pulumi.gcp.organizations.inputs.GetIAMPolicyArgs;
import com.pulumi.gcp.cloudrun.IamPolicy;
import com.pulumi.gcp.cloudrun.IamPolicyArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var default_ = new Service("default", ServiceArgs.builder()
            .name("cloudrun-srv")
            .location("us-central1")
            .template(ServiceTemplateArgs.builder()
                .spec(ServiceTemplateSpecArgs.builder()
                    .containers(ServiceTemplateSpecContainerArgs.builder()
                        .image("us-docker.pkg.dev/cloudrun/container/hello")
                        .build())
                    .build())
                .build())
            .build());

        final var noauth = OrganizationsFunctions.getIAMPolicy(GetIAMPolicyArgs.builder()
            .bindings(GetIAMPolicyBindingArgs.builder()
                .role("roles/run.invoker")
                .members("allUsers")
                .build())
            .build());

        var noauthIamPolicy = new IamPolicy("noauthIamPolicy", IamPolicyArgs.builder()
            .location(default_.location())
            .project(default_.project())
            .service(default_.name())
            .policyData(noauth.policyData())
            .build());

    }
}
resources:
  default:
    type: gcp:cloudrun:Service
    properties:
      name: cloudrun-srv
      location: us-central1
      template:
        spec:
          containers:
            - image: us-docker.pkg.dev/cloudrun/container/hello
  noauthIamPolicy:
    type: gcp:cloudrun:IamPolicy
    name: noauth
    properties:
      location: ${default.location}
      project: ${default.project}
      service: ${default.name}
      policyData: ${noauth.policyData}
variables:
  noauth:
    fn::invoke:
      function: gcp:organizations:getIAMPolicy
      arguments:
        bindings:
          - role: roles/run.invoker
            members:
              - allUsers

The IamPolicy resource applies an IAM policy that grants roles/run.invoker to allUsers, allowing anyone on the internet to invoke your service. This bypasses Cloud Run’s default authentication requirement. Be aware that public access means anyone can trigger requests and incur costs.

Beyond These Examples

These snippets focus on specific service-level features: container deployment and traffic routing, Cloud SQL integration via proxy, health probes and startup orchestration, multi-container sidecars with shared volumes, and public and authenticated access control. They’re intentionally minimal rather than full application deployments.

The examples may reference pre-existing infrastructure such as container images in registries (GCR, Artifact Registry), Cloud SQL instances for database connectivity, and IAM service accounts (implied but not created). They focus on configuring the service rather than provisioning everything around it.

To keep things focused, common service patterns are omitted, including:

  • Custom domains and SSL certificates
  • Environment variables and secrets (Secret Manager)
  • VPC connectors for private network access
  • Memory and CPU resource limits
  • Concurrency and request timeout tuning
  • Identity-Aware Proxy (IAP) for authentication
  • GPU acceleration for ML workloads

These omissions are intentional: the goal is to illustrate how each service feature is wired, not provide drop-in production modules. See the Cloud Run Service resource reference for all available configuration options.

Frequently Asked Questions

Version & Migration
Should I use the v1 or v2 Cloud Run API?
Use gcp.cloudrunv2.Service instead of gcp.cloudrun.Service. The v2 resource offers better developer experience and broader feature support.
Resource Configuration
What properties can't I change after creating my Cloud Run service?
The location, name, and project properties are immutable. Changing any of these requires recreating the service.
How do I control revision naming for my service?
Set autogenerateRevisionName to true to let Cloud Run generate names automatically, or set template.metadata.name explicitly. You cannot use both options simultaneously.
How do I distribute traffic across different revisions?
Configure the traffics property with percentage splits across revisions. Set latestRevision to true to route traffic to the newest revision.
Networking & Access Control
How do I make my Cloud Run service publicly accessible?
Grant the roles/run.invoker role to allUsers using an IAM policy binding on the service.
How do I enable Identity-Aware Proxy (IAP) for my service?
Set metadata.annotations['run.googleapis.com/iap-enabled'] to 'true' and metadata.annotations['run.googleapis.com/launch-stage'] to 'BETA'.
How do I integrate my service with Pub/Sub push subscriptions?
Create a Pub/Sub subscription with pushConfig pointing to your service’s URL (from statuses[0].url). Configure an OIDC token with a service account that has roles/run.invoker on your service and roles/iam.serviceAccountTokenCreator on the project.
Advanced Features
How do I connect my Cloud Run service to a Cloud SQL database?
Add the Cloud SQL instance connection name to template.metadata.annotations['run.googleapis.com/cloudsql-instances'].
How do I configure GPUs for my Cloud Run service?

You need four configurations:

  1. Set metadata.annotations['run.googleapis.com/launch-stage'] to 'BETA'
  2. Set template.metadata.annotations['run.googleapis.com/cpu-throttling'] to 'false'
  3. Add GPU to template.spec.containers[].resources.limits (e.g., 'nvidia.com/gpu': '1')
  4. Configure template.spec.nodeSelector['run.googleapis.com/accelerator'] with your GPU type (e.g., 'nvidia-l4')
Can I run multiple containers in a single Cloud Run service?
Yes. Define multiple containers in template.spec.containers and specify dependencies using template.metadata.annotations['run.googleapis.com/container-dependencies']. You can also configure shared volumes between containers.
How do I configure health checks for my containers?
Use startupProbe for initial readiness checks and livenessProbe for ongoing health monitoring. Both support HTTP GET requests and TCP socket checks.

Ready to get started?

Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.

Create free account