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 FREEFrequently Asked Questions
Migration & Deprecation
gcp.cloudrunv2.Service instead. The v2 resource offers better developer experience and broader support for Cloud Run features.Resource Configuration & Immutability
location, name, and project properties are immutable. Changing any of these requires destroying and recreating the service.You have two options:
- Auto-generate - Set
autogenerateRevisionNametotrueand omittemplate.metadata.name - Manual naming - Set
autogenerateRevisionNametofalseand providetemplate.metadata.name
You cannot set both autogenerateRevisionName to true and provide template.metadata.name.
Integrations & Features
template.metadata.annotations with key run.googleapis.com/cloudsql-instances.roles/run.invoker and member allUsers using gcp.cloudrun.IamPolicy or gcp.cloudrun.IamBinding.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.run.googleapis.com/iap-enabled to true in metadata.annotations.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
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.
Using a different cloud?
Explore serverless guides for other cloud providers: