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
gcp.cloudrunv2.Service instead of gcp.cloudrun.Service. The v2 resource offers better developer experience and broader feature support.Resource Configuration
location, name, and project properties are immutable. Changing any of these requires recreating the service.autogenerateRevisionName to true to let Cloud Run generate names automatically, or set template.metadata.name explicitly. You cannot use both options simultaneously.traffics property with percentage splits across revisions. Set latestRevision to true to route traffic to the newest revision.Networking & Access Control
roles/run.invoker role to allUsers using an IAM policy binding on the service.metadata.annotations['run.googleapis.com/iap-enabled'] to 'true' and metadata.annotations['run.googleapis.com/launch-stage'] to 'BETA'.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
template.metadata.annotations['run.googleapis.com/cloudsql-instances'].You need four configurations:
- Set
metadata.annotations['run.googleapis.com/launch-stage']to'BETA' - Set
template.metadata.annotations['run.googleapis.com/cpu-throttling']to'false' - Add GPU to
template.spec.containers[].resources.limits(e.g.,'nvidia.com/gpu': '1') - Configure
template.spec.nodeSelector['run.googleapis.com/accelerator']with your GPU type (e.g.,'nvidia-l4')
template.spec.containers and specify dependencies using template.metadata.annotations['run.googleapis.com/container-dependencies']. You can also configure shared volumes between containers.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