Deploy Google Cloud Run Services

The gcp:cloudrun/service:Service resource, part of the Pulumi GCP provider, defines a Cloud Run service that deploys containers with automatic HTTPS endpoints and request-based autoscaling. This guide focuses on four capabilities: container deployment with traffic routing, Cloud SQL connections, GPU acceleration, and health probes and multi-container patterns. Note that Google recommends using gcp.cloudrunv2.Service for new projects, which offers broader feature support.

Services require container images in GCR or Artifact Registry and may reference Cloud SQL instances or IAM service accounts. The examples are intentionally small. Combine them with your own IAM roles, networking, and monitoring.

Deploy a container with traffic routing

Most deployments start with a container image and traffic configuration that creates an HTTPS endpoint.

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 array defines which images to run. The traffics property controls how requests are distributed across revisions; setting latestRevision to true routes all traffic to the newest deployment. Cloud Run generates a unique URL and autoscales containers based on incoming requests.

Connect to Cloud SQL databases

Applications needing persistent data connect to Cloud SQL through managed Unix sockets.

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

The run.googleapis.com/cloudsql-instances annotation in template.metadata tells Cloud Run to establish a connection to your database instance. Your container accesses the database via Unix socket at /cloudsql/[CONNECTION_NAME] without managing credentials directly. The autogenerateRevisionName property lets Cloud Run create revision names automatically.

Attach GPUs for accelerated workloads

Machine learning inference and compute-intensive tasks benefit from GPU acceleration.

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",
    metadata: {
        annotations: {
            "run.googleapis.com/launch-stage": "BETA",
        },
    },
    template: {
        metadata: {
            annotations: {
                "autoscaling.knative.dev/maxScale": "1",
                "run.googleapis.com/cpu-throttling": "false",
            },
        },
        spec: {
            containers: [{
                image: "gcr.io/cloudrun/hello",
                resources: {
                    limits: {
                        cpu: "4",
                        memory: "16Gi",
                        "nvidia.com/gpu": "1",
                    },
                },
            }],
            nodeSelector: {
                "run.googleapis.com/accelerator": "nvidia-l4",
            },
        },
    },
});
import pulumi
import pulumi_gcp as gcp

default = gcp.cloudrun.Service("default",
    name="cloudrun-srv",
    location="us-central1",
    metadata={
        "annotations": {
            "run.googleapis.com/launch-stage": "BETA",
        },
    },
    template={
        "metadata": {
            "annotations": {
                "autoscaling.knative.dev/maxScale": "1",
                "run.googleapis.com/cpu-throttling": "false",
            },
        },
        "spec": {
            "containers": [{
                "image": "gcr.io/cloudrun/hello",
                "resources": {
                    "limits": {
                        "cpu": "4",
                        "memory": "16Gi",
                        "nvidia.com/gpu": "1",
                    },
                },
            }],
            "node_selector": {
                "run.googleapis.com/accelerator": "nvidia-l4",
            },
        },
    })
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"),
			Metadata: &cloudrun.ServiceMetadataArgs{
				Annotations: pulumi.StringMap{
					"run.googleapis.com/launch-stage": pulumi.String("BETA"),
				},
			},
			Template: &cloudrun.ServiceTemplateArgs{
				Metadata: &cloudrun.ServiceTemplateMetadataArgs{
					Annotations: pulumi.StringMap{
						"autoscaling.knative.dev/maxScale":  pulumi.String("1"),
						"run.googleapis.com/cpu-throttling": pulumi.String("false"),
					},
				},
				Spec: &cloudrun.ServiceTemplateSpecArgs{
					Containers: cloudrun.ServiceTemplateSpecContainerArray{
						&cloudrun.ServiceTemplateSpecContainerArgs{
							Image: pulumi.String("gcr.io/cloudrun/hello"),
							Resources: &cloudrun.ServiceTemplateSpecContainerResourcesArgs{
								Limits: pulumi.StringMap{
									"cpu":            pulumi.String("4"),
									"memory":         pulumi.String("16Gi"),
									"nvidia.com/gpu": pulumi.String("1"),
								},
							},
						},
					},
					NodeSelector: pulumi.StringMap{
						"run.googleapis.com/accelerator": pulumi.String("nvidia-l4"),
					},
				},
			},
		})
		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",
        Metadata = new Gcp.CloudRun.Inputs.ServiceMetadataArgs
        {
            Annotations = 
            {
                { "run.googleapis.com/launch-stage", "BETA" },
            },
        },
        Template = new Gcp.CloudRun.Inputs.ServiceTemplateArgs
        {
            Metadata = new Gcp.CloudRun.Inputs.ServiceTemplateMetadataArgs
            {
                Annotations = 
                {
                    { "autoscaling.knative.dev/maxScale", "1" },
                    { "run.googleapis.com/cpu-throttling", "false" },
                },
            },
            Spec = new Gcp.CloudRun.Inputs.ServiceTemplateSpecArgs
            {
                Containers = new[]
                {
                    new Gcp.CloudRun.Inputs.ServiceTemplateSpecContainerArgs
                    {
                        Image = "gcr.io/cloudrun/hello",
                        Resources = new Gcp.CloudRun.Inputs.ServiceTemplateSpecContainerResourcesArgs
                        {
                            Limits = 
                            {
                                { "cpu", "4" },
                                { "memory", "16Gi" },
                                { "nvidia.com/gpu", "1" },
                            },
                        },
                    },
                },
                NodeSelector = 
                {
                    { "run.googleapis.com/accelerator", "nvidia-l4" },
                },
            },
        },
    });

});
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.ServiceMetadataArgs;
import com.pulumi.gcp.cloudrun.inputs.ServiceTemplateArgs;
import com.pulumi.gcp.cloudrun.inputs.ServiceTemplateMetadataArgs;
import com.pulumi.gcp.cloudrun.inputs.ServiceTemplateSpecArgs;
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")
            .metadata(ServiceMetadataArgs.builder()
                .annotations(Map.of("run.googleapis.com/launch-stage", "BETA"))
                .build())
            .template(ServiceTemplateArgs.builder()
                .metadata(ServiceTemplateMetadataArgs.builder()
                    .annotations(Map.ofEntries(
                        Map.entry("autoscaling.knative.dev/maxScale", "1"),
                        Map.entry("run.googleapis.com/cpu-throttling", "false")
                    ))
                    .build())
                .spec(ServiceTemplateSpecArgs.builder()
                    .containers(ServiceTemplateSpecContainerArgs.builder()
                        .image("gcr.io/cloudrun/hello")
                        .resources(ServiceTemplateSpecContainerResourcesArgs.builder()
                            .limits(Map.ofEntries(
                                Map.entry("cpu", "4"),
                                Map.entry("memory", "16Gi"),
                                Map.entry("nvidia.com/gpu", "1")
                            ))
                            .build())
                        .build())
                    .nodeSelector(Map.of("run.googleapis.com/accelerator", "nvidia-l4"))
                    .build())
                .build())
            .build());

    }
}
resources:
  default:
    type: gcp:cloudrun:Service
    properties:
      name: cloudrun-srv
      location: us-central1
      metadata:
        annotations:
          run.googleapis.com/launch-stage: BETA
      template:
        metadata:
          annotations:
            autoscaling.knative.dev/maxScale: '1'
            run.googleapis.com/cpu-throttling: 'false'
        spec:
          containers:
            - image: gcr.io/cloudrun/hello
              resources:
                limits:
                  cpu: '4'
                  memory: 16Gi
                  nvidia.com/gpu: '1'
          nodeSelector:
            run.googleapis.com/accelerator: nvidia-l4

The resources.limits property requests GPU resources using the nvidia.com/gpu key. The nodeSelector specifies which GPU type to use (here, nvidia-l4). The run.googleapis.com/cpu-throttling annotation set to false prevents CPU throttling during GPU operations. This configuration requires the BETA launch stage annotation.

Configure health checks with startup and liveness probes

Production services use health checks to detect container readiness and ongoing health.

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 a TCP socket check to determine when the container is ready to accept traffic. The livenessProbe uses HTTP GET requests to verify the container remains healthy during operation. Cloud Run restarts containers that fail liveness checks after the configured failureThreshold.

Run multiple containers with shared volumes

Some applications split responsibilities across containers that share data through volumes.

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 containers array defines multiple containers within a single service. The run.googleapis.com/container-dependencies annotation controls startup order (hello-1 waits for hello-2). The volumes and volumeMounts properties create shared storage using an in-memory emptyDir volume that both containers can access.

Beyond these examples

These snippets focus on specific Cloud Run service features: container deployment and traffic routing, Cloud SQL connections and GPU acceleration, and health probes and multi-container sidecars. They’re intentionally minimal rather than full application deployments.

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

To keep things focused, common Cloud Run patterns are omitted, including:

  • Service account configuration (serviceAccountName)
  • Environment variables and secrets (envs, secrets)
  • Resource limits for CPU and memory (resources.limits)
  • VPC connector for private networking (run.googleapis.com/vpc-access-connector)
  • Custom domains and SSL certificates
  • Revision naming and traffic splitting strategies

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

Let's deploy Google Cloud Run Services

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

Try Pulumi Cloud for FREE

Frequently Asked Questions

Migration & Deprecation
Should I use this resource or cloudrunv2.Service?
Use gcp.cloudrunv2.Service instead. The v2 resource offers better developer experience and broader support for Cloud Run features.
Resource Configuration & Immutability
What properties can't I change after creating a Cloud Run service?
The location, name, and project properties are immutable. Changing any of these requires destroying and recreating the service.
How do I handle revision naming in Cloud Run?

You have two options:

  1. Auto-generate - Set autogenerateRevisionName to true and omit template.metadata.name
  2. Manual naming - Set autogenerateRevisionName to false and provide template.metadata.name

You cannot set both autogenerateRevisionName to true and provide template.metadata.name.

Integrations & Features
How do I connect my Cloud Run service to Cloud SQL?
Add the Cloud SQL instance connection name to template.metadata.annotations with key run.googleapis.com/cloudsql-instances.
How do I make my Cloud Run service publicly accessible?
Create an IAM policy binding with role roles/run.invoker and member allUsers using gcp.cloudrun.IamPolicy or gcp.cloudrun.IamBinding.
Can I use GPUs with Cloud Run?
Yes, specify GPU limits in container.resources.limits (e.g., nvidia.com/gpu: "1") and set spec.nodeSelector to your accelerator type (e.g., run.googleapis.com/accelerator: "nvidia-l4"). Also set the annotation run.googleapis.com/launch-stage: "BETA" in metadata.
How do I enable Identity-Aware Proxy for my service?
Set the annotation run.googleapis.com/iap-enabled to true in metadata.annotations.
Can I run multiple containers in a single Cloud Run service?
Yes, define multiple containers in template.spec.containers and use the run.googleapis.com/container-dependencies annotation in template.metadata.annotations to specify startup order and dependencies between containers.
Health Checks & Probes
How do I configure health checks for my Cloud Run service?

Configure probes in your container spec:

  • startupProbe - Checks if container has started (supports HTTP, TCP, gRPC)
  • livenessProbe - Checks if container is running (supports HTTP, TCP, gRPC)
  • readinessProbe - Checks if container is ready to serve traffic (supports HTTP, TCP, gRPC)

Each probe can specify timeoutSeconds, periodSeconds, failureThreshold, and successThreshold.

What's the difference between startup, liveness, and readiness probes?
Startup probes verify the container has started successfully. Liveness probes check if the container is still running and restart it if it fails. Readiness probes determine if the container is ready to accept traffic (used for beta features).

Using a different cloud?

Explore serverless guides for other cloud providers: