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 and public access policies, health probes and GPU acceleration, and multi-container deployments.
Cloud Run services reference container images from Artifact Registry or Container Registry and may connect to Cloud SQL instances or use service accounts for IAM permissions. The examples are intentionally small. Combine them with your own images, databases, and access policies.
Note: Google recommends using
gcp.cloudrunv2.Servicefor new projects, which offers broader feature support. This resource is maintained for compatibility with existing deployments.
Deploy a container with traffic routing
Most deployments start with a container image and traffic configuration that creates an HTTPS endpoint and autoscales based on requests.
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 assigns a unique URL and scales containers from zero to match demand.
Connect to Cloud SQL databases
Applications needing persistent data connect to Cloud SQL through secure Unix sockets without exposing credentials.
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 establishes a socket connection using the instance’s connectionName. Cloud Run mounts the socket at /cloudsql, allowing your application to connect without managing credentials. Setting autogenerateRevisionName to true lets Cloud Run generate revision names automatically.
Allow unauthenticated public access
Public services like webhooks accept requests from any caller by granting 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
By default, Cloud Run requires authentication. The IamPolicy resource grants roles/run.invoker to allUsers, making the service publicly accessible. This bypasses Cloud Run’s authentication layer; use it only for services designed for public access.
Configure health checks with startup and liveness probes
Services with slow initialization use probes to signal readiness and detect 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 delays traffic until the container passes its first check, preventing requests from reaching unready containers. The livenessProbe monitors ongoing health; failures trigger container restarts. Configure periodSeconds and failureThreshold to balance responsiveness against false positives.
Attach GPUs for ML inference workloads
Machine learning inference leverages GPUs to reduce latency and increase throughput.
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 allocation using nvidia.com/gpu. The nodeSelector specifies which GPU type to use (here, nvidia-l4). Setting run.googleapis.com/cpu-throttling to false prevents CPU throttling during GPU operations. GPU features require the BETA launch stage annotation.
Run multiple containers with shared volumes
Applications can split responsibilities across containers, such as a main service and a logging sidecar.
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 one service. The run.googleapis.com/container-dependencies annotation controls startup order. The volumes property creates shared storage; emptyDir provides in-memory storage that both containers can access through volumeMounts.
Beyond these examples
These snippets focus on specific Cloud Run service features: container deployment and traffic routing, Cloud SQL integration and IAM policies, health probes and GPU acceleration, and multi-container sidecars. They’re intentionally minimal rather than full application deployments.
The examples may reference pre-existing infrastructure such as Cloud SQL instances, container images in Artifact Registry or Container Registry, and service accounts with appropriate IAM roles. They focus on configuring the service rather than provisioning everything around it.
To keep things focused, common service patterns are omitted, including:
- Environment variables and secrets (env, envFrom)
- Custom domains and SSL certificates
- VPC connectors for private networking
- Service account assignment (serviceAccountName)
- Resource limits (CPU, memory) beyond GPU example
- Volume types beyond emptyDir (secrets, configMaps)
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 & Versioning
gcp.cloudrunv2.Service instead. The v2 resource offers better developer experience and broader support for Cloud Run features compared to this v1 resource.Resource Configuration & Immutability
name, location, and project properties are immutable and cannot be updated after creation. Changes to these properties require replacing the resource.autogenerateRevisionName to true while also setting template.metadata.name. Either enable autogeneration and omit the revision name, or disable it and provide an explicit name.Integrations & Access Control
template.metadata.annotations using the key run.googleapis.com/cloudsql-instances.roles/run.invoker role to allUsers using an IAM policy on the service.pushEndpoint, and configure oidcToken authentication with a service account that has the roles/run.invoker role.metadata.annotations: run.googleapis.com/launch-stage set to BETA and run.googleapis.com/iap-enabled set to true.Advanced Container Configuration
containers.resources.limits (e.g., nvidia.com/gpu: "1"), specify the accelerator in nodeSelector (e.g., run.googleapis.com/accelerator: "nvidia-l4"), and add annotations for run.googleapis.com/launch-stage: "BETA" and run.googleapis.com/cpu-throttling: "false".startupProbe checks initial container readiness (supports tcpSocket and httpGet), livenessProbe performs ongoing health checks (supports httpGet), and readinessProbe determines traffic readiness (supports grpc, requires run.googleapis.com/launch-stage: "BETA" annotation).template.spec.containers, specify container startup dependencies using the run.googleapis.com/container-dependencies annotation in template.metadata.annotations, and optionally configure shared volumes using emptyDir in template.spec.volumes.Using a different cloud?
Explore serverless guides for other cloud providers: