The gcp:cloudrunv2/service:Service resource, part of the Pulumi GCP provider, defines a Cloud Run service that manages container revisions, traffic routing, and scaling behavior. This guide focuses on four capabilities: container deployment with resource limits, VPC networking for private resource access, volume mounts for databases and secrets, and health probes with multi-container configurations.
Cloud Run services reference container images from registries and may connect to VPC networks, Cloud SQL instances, or Secret Manager. The examples are intentionally small. Combine them with your own networking, IAM roles, and storage infrastructure.
Deploy a container with scaling limits
Most deployments start with a container image and basic scaling configuration to control instance counts.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const _default = new gcp.cloudrunv2.Service("default", {
name: "cloudrun-service",
location: "us-central1",
deletionProtection: false,
ingress: "INGRESS_TRAFFIC_ALL",
scaling: {
maxInstanceCount: 100,
},
template: {
containers: [{
image: "us-docker.pkg.dev/cloudrun/container/hello",
}],
},
});
import pulumi
import pulumi_gcp as gcp
default = gcp.cloudrunv2.Service("default",
name="cloudrun-service",
location="us-central1",
deletion_protection=False,
ingress="INGRESS_TRAFFIC_ALL",
scaling={
"max_instance_count": 100,
},
template={
"containers": [{
"image": "us-docker.pkg.dev/cloudrun/container/hello",
}],
})
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/cloudrunv2"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := cloudrunv2.NewService(ctx, "default", &cloudrunv2.ServiceArgs{
Name: pulumi.String("cloudrun-service"),
Location: pulumi.String("us-central1"),
DeletionProtection: pulumi.Bool(false),
Ingress: pulumi.String("INGRESS_TRAFFIC_ALL"),
Scaling: &cloudrunv2.ServiceScalingArgs{
MaxInstanceCount: pulumi.Int(100),
},
Template: &cloudrunv2.ServiceTemplateArgs{
Containers: cloudrunv2.ServiceTemplateContainerArray{
&cloudrunv2.ServiceTemplateContainerArgs{
Image: pulumi.String("us-docker.pkg.dev/cloudrun/container/hello"),
},
},
},
})
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.CloudRunV2.Service("default", new()
{
Name = "cloudrun-service",
Location = "us-central1",
DeletionProtection = false,
Ingress = "INGRESS_TRAFFIC_ALL",
Scaling = new Gcp.CloudRunV2.Inputs.ServiceScalingArgs
{
MaxInstanceCount = 100,
},
Template = new Gcp.CloudRunV2.Inputs.ServiceTemplateArgs
{
Containers = new[]
{
new Gcp.CloudRunV2.Inputs.ServiceTemplateContainerArgs
{
Image = "us-docker.pkg.dev/cloudrun/container/hello",
},
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.cloudrunv2.Service;
import com.pulumi.gcp.cloudrunv2.ServiceArgs;
import com.pulumi.gcp.cloudrunv2.inputs.ServiceScalingArgs;
import com.pulumi.gcp.cloudrunv2.inputs.ServiceTemplateArgs;
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-service")
.location("us-central1")
.deletionProtection(false)
.ingress("INGRESS_TRAFFIC_ALL")
.scaling(ServiceScalingArgs.builder()
.maxInstanceCount(100)
.build())
.template(ServiceTemplateArgs.builder()
.containers(ServiceTemplateContainerArgs.builder()
.image("us-docker.pkg.dev/cloudrun/container/hello")
.build())
.build())
.build());
}
}
resources:
default:
type: gcp:cloudrunv2:Service
properties:
name: cloudrun-service
location: us-central1
deletionProtection: false
ingress: INGRESS_TRAFFIC_ALL
scaling:
maxInstanceCount: 100
template:
containers:
- image: us-docker.pkg.dev/cloudrun/container/hello
The template property defines the container specification that Cloud Run uses to create revisions. The image points to your container registry, and scaling.maxInstanceCount caps the number of concurrent instances. The ingress property controls whether traffic comes from the internet, internal sources only, or load balancers.
Set CPU and memory resource limits
Applications with specific resource requirements need explicit limits to ensure predictable performance.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const _default = new gcp.cloudrunv2.Service("default", {
name: "cloudrun-service",
location: "us-central1",
deletionProtection: false,
ingress: "INGRESS_TRAFFIC_ALL",
template: {
healthCheckDisabled: true,
containers: [{
image: "us-docker.pkg.dev/cloudrun/container/hello",
resources: {
limits: {
cpu: "2",
memory: "1024Mi",
},
},
}],
},
});
import pulumi
import pulumi_gcp as gcp
default = gcp.cloudrunv2.Service("default",
name="cloudrun-service",
location="us-central1",
deletion_protection=False,
ingress="INGRESS_TRAFFIC_ALL",
template={
"health_check_disabled": True,
"containers": [{
"image": "us-docker.pkg.dev/cloudrun/container/hello",
"resources": {
"limits": {
"cpu": "2",
"memory": "1024Mi",
},
},
}],
})
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/cloudrunv2"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := cloudrunv2.NewService(ctx, "default", &cloudrunv2.ServiceArgs{
Name: pulumi.String("cloudrun-service"),
Location: pulumi.String("us-central1"),
DeletionProtection: pulumi.Bool(false),
Ingress: pulumi.String("INGRESS_TRAFFIC_ALL"),
Template: &cloudrunv2.ServiceTemplateArgs{
HealthCheckDisabled: pulumi.Bool(true),
Containers: cloudrunv2.ServiceTemplateContainerArray{
&cloudrunv2.ServiceTemplateContainerArgs{
Image: pulumi.String("us-docker.pkg.dev/cloudrun/container/hello"),
Resources: &cloudrunv2.ServiceTemplateContainerResourcesArgs{
Limits: pulumi.StringMap{
"cpu": pulumi.String("2"),
"memory": pulumi.String("1024Mi"),
},
},
},
},
},
})
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.CloudRunV2.Service("default", new()
{
Name = "cloudrun-service",
Location = "us-central1",
DeletionProtection = false,
Ingress = "INGRESS_TRAFFIC_ALL",
Template = new Gcp.CloudRunV2.Inputs.ServiceTemplateArgs
{
HealthCheckDisabled = true,
Containers = new[]
{
new Gcp.CloudRunV2.Inputs.ServiceTemplateContainerArgs
{
Image = "us-docker.pkg.dev/cloudrun/container/hello",
Resources = new Gcp.CloudRunV2.Inputs.ServiceTemplateContainerResourcesArgs
{
Limits =
{
{ "cpu", "2" },
{ "memory", "1024Mi" },
},
},
},
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.cloudrunv2.Service;
import com.pulumi.gcp.cloudrunv2.ServiceArgs;
import com.pulumi.gcp.cloudrunv2.inputs.ServiceTemplateArgs;
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-service")
.location("us-central1")
.deletionProtection(false)
.ingress("INGRESS_TRAFFIC_ALL")
.template(ServiceTemplateArgs.builder()
.healthCheckDisabled(true)
.containers(ServiceTemplateContainerArgs.builder()
.image("us-docker.pkg.dev/cloudrun/container/hello")
.resources(ServiceTemplateContainerResourcesArgs.builder()
.limits(Map.ofEntries(
Map.entry("cpu", "2"),
Map.entry("memory", "1024Mi")
))
.build())
.build())
.build())
.build());
}
}
resources:
default:
type: gcp:cloudrunv2:Service
properties:
name: cloudrun-service
location: us-central1
deletionProtection: false
ingress: INGRESS_TRAFFIC_ALL
template:
healthCheckDisabled: true
containers:
- image: us-docker.pkg.dev/cloudrun/container/hello
resources:
limits:
cpu: '2'
memory: 1024Mi
The resources.limits block sets CPU cores and memory allocation for each container instance. Cloud Run uses these limits for billing and scheduling. Setting healthCheckDisabled to true skips default health checks when you provide custom probes.
Connect to Cloud SQL with mounted volumes
Services that need database access can mount Cloud SQL instances as volumes for Unix socket connections.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const secret = new gcp.secretmanager.Secret("secret", {
secretId: "secret-1",
replication: {
auto: {},
},
});
const secret_version_data = new gcp.secretmanager.SecretVersion("secret-version-data", {
secret: secret.name,
secretData: "secret-data",
});
const instance = new gcp.sql.DatabaseInstance("instance", {
name: "cloudrun-sql",
region: "us-central1",
databaseVersion: "MYSQL_5_7",
settings: {
tier: "db-f1-micro",
},
deletionProtection: true,
});
const _default = new gcp.cloudrunv2.Service("default", {
name: "cloudrun-service",
location: "us-central1",
deletionProtection: false,
ingress: "INGRESS_TRAFFIC_ALL",
scaling: {
maxInstanceCount: 2,
},
template: {
volumes: [{
name: "cloudsql",
cloudSqlInstance: {
instances: [instance.connectionName],
},
}],
containers: [{
image: "us-docker.pkg.dev/cloudrun/container/hello",
envs: [
{
name: "FOO",
value: "bar",
},
{
name: "SECRET_ENV_VAR",
valueSource: {
secretKeyRef: {
secret: secret.secretId,
version: "1",
},
},
},
],
volumeMounts: [{
name: "cloudsql",
mountPath: "/cloudsql",
}],
}],
},
traffics: [{
type: "TRAFFIC_TARGET_ALLOCATION_TYPE_LATEST",
percent: 100,
}],
}, {
dependsOn: [secret_version_data],
});
const project = gcp.organizations.getProject({});
const secret_access = new gcp.secretmanager.SecretIamMember("secret-access", {
secretId: secret.id,
role: "roles/secretmanager.secretAccessor",
member: project.then(project => `serviceAccount:${project.number}-compute@developer.gserviceaccount.com`),
}, {
dependsOn: [secret],
});
import pulumi
import pulumi_gcp as gcp
secret = gcp.secretmanager.Secret("secret",
secret_id="secret-1",
replication={
"auto": {},
})
secret_version_data = gcp.secretmanager.SecretVersion("secret-version-data",
secret=secret.name,
secret_data="secret-data")
instance = gcp.sql.DatabaseInstance("instance",
name="cloudrun-sql",
region="us-central1",
database_version="MYSQL_5_7",
settings={
"tier": "db-f1-micro",
},
deletion_protection=True)
default = gcp.cloudrunv2.Service("default",
name="cloudrun-service",
location="us-central1",
deletion_protection=False,
ingress="INGRESS_TRAFFIC_ALL",
scaling={
"max_instance_count": 2,
},
template={
"volumes": [{
"name": "cloudsql",
"cloud_sql_instance": {
"instances": [instance.connection_name],
},
}],
"containers": [{
"image": "us-docker.pkg.dev/cloudrun/container/hello",
"envs": [
{
"name": "FOO",
"value": "bar",
},
{
"name": "SECRET_ENV_VAR",
"value_source": {
"secret_key_ref": {
"secret": secret.secret_id,
"version": "1",
},
},
},
],
"volume_mounts": [{
"name": "cloudsql",
"mount_path": "/cloudsql",
}],
}],
},
traffics=[{
"type": "TRAFFIC_TARGET_ALLOCATION_TYPE_LATEST",
"percent": 100,
}],
opts = pulumi.ResourceOptions(depends_on=[secret_version_data]))
project = gcp.organizations.get_project()
secret_access = gcp.secretmanager.SecretIamMember("secret-access",
secret_id=secret.id,
role="roles/secretmanager.secretAccessor",
member=f"serviceAccount:{project.number}-compute@developer.gserviceaccount.com",
opts = pulumi.ResourceOptions(depends_on=[secret]))
package main
import (
"fmt"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/cloudrunv2"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/organizations"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/secretmanager"
"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 {
secret, err := secretmanager.NewSecret(ctx, "secret", &secretmanager.SecretArgs{
SecretId: pulumi.String("secret-1"),
Replication: &secretmanager.SecretReplicationArgs{
Auto: &secretmanager.SecretReplicationAutoArgs{},
},
})
if err != nil {
return err
}
secret_version_data, err := secretmanager.NewSecretVersion(ctx, "secret-version-data", &secretmanager.SecretVersionArgs{
Secret: secret.Name,
SecretData: pulumi.String("secret-data"),
})
if err != nil {
return err
}
instance, err := sql.NewDatabaseInstance(ctx, "instance", &sql.DatabaseInstanceArgs{
Name: pulumi.String("cloudrun-sql"),
Region: pulumi.String("us-central1"),
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 = cloudrunv2.NewService(ctx, "default", &cloudrunv2.ServiceArgs{
Name: pulumi.String("cloudrun-service"),
Location: pulumi.String("us-central1"),
DeletionProtection: pulumi.Bool(false),
Ingress: pulumi.String("INGRESS_TRAFFIC_ALL"),
Scaling: &cloudrunv2.ServiceScalingArgs{
MaxInstanceCount: pulumi.Int(2),
},
Template: &cloudrunv2.ServiceTemplateArgs{
Volumes: cloudrunv2.ServiceTemplateVolumeArray{
&cloudrunv2.ServiceTemplateVolumeArgs{
Name: pulumi.String("cloudsql"),
CloudSqlInstance: &cloudrunv2.ServiceTemplateVolumeCloudSqlInstanceArgs{
Instances: pulumi.StringArray{
instance.ConnectionName,
},
},
},
},
Containers: cloudrunv2.ServiceTemplateContainerArray{
&cloudrunv2.ServiceTemplateContainerArgs{
Image: pulumi.String("us-docker.pkg.dev/cloudrun/container/hello"),
Envs: cloudrunv2.ServiceTemplateContainerEnvArray{
&cloudrunv2.ServiceTemplateContainerEnvArgs{
Name: pulumi.String("FOO"),
Value: pulumi.String("bar"),
},
&cloudrunv2.ServiceTemplateContainerEnvArgs{
Name: pulumi.String("SECRET_ENV_VAR"),
ValueSource: &cloudrunv2.ServiceTemplateContainerEnvValueSourceArgs{
SecretKeyRef: &cloudrunv2.ServiceTemplateContainerEnvValueSourceSecretKeyRefArgs{
Secret: secret.SecretId,
Version: pulumi.String("1"),
},
},
},
},
VolumeMounts: cloudrunv2.ServiceTemplateContainerVolumeMountArray{
&cloudrunv2.ServiceTemplateContainerVolumeMountArgs{
Name: pulumi.String("cloudsql"),
MountPath: pulumi.String("/cloudsql"),
},
},
},
},
},
Traffics: cloudrunv2.ServiceTrafficArray{
&cloudrunv2.ServiceTrafficArgs{
Type: pulumi.String("TRAFFIC_TARGET_ALLOCATION_TYPE_LATEST"),
Percent: pulumi.Int(100),
},
},
}, pulumi.DependsOn([]pulumi.Resource{
secret_version_data,
}))
if err != nil {
return err
}
project, err := organizations.LookupProject(ctx, &organizations.LookupProjectArgs{}, nil)
if err != nil {
return err
}
_, err = secretmanager.NewSecretIamMember(ctx, "secret-access", &secretmanager.SecretIamMemberArgs{
SecretId: secret.ID(),
Role: pulumi.String("roles/secretmanager.secretAccessor"),
Member: pulumi.Sprintf("serviceAccount:%v-compute@developer.gserviceaccount.com", project.Number),
}, pulumi.DependsOn([]pulumi.Resource{
secret,
}))
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 secret = new Gcp.SecretManager.Secret("secret", new()
{
SecretId = "secret-1",
Replication = new Gcp.SecretManager.Inputs.SecretReplicationArgs
{
Auto = null,
},
});
var secret_version_data = new Gcp.SecretManager.SecretVersion("secret-version-data", new()
{
Secret = secret.Name,
SecretData = "secret-data",
});
var instance = new Gcp.Sql.DatabaseInstance("instance", new()
{
Name = "cloudrun-sql",
Region = "us-central1",
DatabaseVersion = "MYSQL_5_7",
Settings = new Gcp.Sql.Inputs.DatabaseInstanceSettingsArgs
{
Tier = "db-f1-micro",
},
DeletionProtection = true,
});
var @default = new Gcp.CloudRunV2.Service("default", new()
{
Name = "cloudrun-service",
Location = "us-central1",
DeletionProtection = false,
Ingress = "INGRESS_TRAFFIC_ALL",
Scaling = new Gcp.CloudRunV2.Inputs.ServiceScalingArgs
{
MaxInstanceCount = 2,
},
Template = new Gcp.CloudRunV2.Inputs.ServiceTemplateArgs
{
Volumes = new[]
{
new Gcp.CloudRunV2.Inputs.ServiceTemplateVolumeArgs
{
Name = "cloudsql",
CloudSqlInstance = new Gcp.CloudRunV2.Inputs.ServiceTemplateVolumeCloudSqlInstanceArgs
{
Instances = new[]
{
instance.ConnectionName,
},
},
},
},
Containers = new[]
{
new Gcp.CloudRunV2.Inputs.ServiceTemplateContainerArgs
{
Image = "us-docker.pkg.dev/cloudrun/container/hello",
Envs = new[]
{
new Gcp.CloudRunV2.Inputs.ServiceTemplateContainerEnvArgs
{
Name = "FOO",
Value = "bar",
},
new Gcp.CloudRunV2.Inputs.ServiceTemplateContainerEnvArgs
{
Name = "SECRET_ENV_VAR",
ValueSource = new Gcp.CloudRunV2.Inputs.ServiceTemplateContainerEnvValueSourceArgs
{
SecretKeyRef = new Gcp.CloudRunV2.Inputs.ServiceTemplateContainerEnvValueSourceSecretKeyRefArgs
{
Secret = secret.SecretId,
Version = "1",
},
},
},
},
VolumeMounts = new[]
{
new Gcp.CloudRunV2.Inputs.ServiceTemplateContainerVolumeMountArgs
{
Name = "cloudsql",
MountPath = "/cloudsql",
},
},
},
},
},
Traffics = new[]
{
new Gcp.CloudRunV2.Inputs.ServiceTrafficArgs
{
Type = "TRAFFIC_TARGET_ALLOCATION_TYPE_LATEST",
Percent = 100,
},
},
}, new CustomResourceOptions
{
DependsOn =
{
secret_version_data,
},
});
var project = Gcp.Organizations.GetProject.Invoke();
var secret_access = new Gcp.SecretManager.SecretIamMember("secret-access", new()
{
SecretId = secret.Id,
Role = "roles/secretmanager.secretAccessor",
Member = $"serviceAccount:{project.Apply(getProjectResult => getProjectResult.Number)}-compute@developer.gserviceaccount.com",
}, new CustomResourceOptions
{
DependsOn =
{
secret,
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.secretmanager.Secret;
import com.pulumi.gcp.secretmanager.SecretArgs;
import com.pulumi.gcp.secretmanager.inputs.SecretReplicationArgs;
import com.pulumi.gcp.secretmanager.inputs.SecretReplicationAutoArgs;
import com.pulumi.gcp.secretmanager.SecretVersion;
import com.pulumi.gcp.secretmanager.SecretVersionArgs;
import com.pulumi.gcp.sql.DatabaseInstance;
import com.pulumi.gcp.sql.DatabaseInstanceArgs;
import com.pulumi.gcp.sql.inputs.DatabaseInstanceSettingsArgs;
import com.pulumi.gcp.cloudrunv2.Service;
import com.pulumi.gcp.cloudrunv2.ServiceArgs;
import com.pulumi.gcp.cloudrunv2.inputs.ServiceScalingArgs;
import com.pulumi.gcp.cloudrunv2.inputs.ServiceTemplateArgs;
import com.pulumi.gcp.cloudrunv2.inputs.ServiceTrafficArgs;
import com.pulumi.gcp.organizations.OrganizationsFunctions;
import com.pulumi.gcp.organizations.inputs.GetProjectArgs;
import com.pulumi.gcp.secretmanager.SecretIamMember;
import com.pulumi.gcp.secretmanager.SecretIamMemberArgs;
import com.pulumi.resources.CustomResourceOptions;
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 secret = new Secret("secret", SecretArgs.builder()
.secretId("secret-1")
.replication(SecretReplicationArgs.builder()
.auto(SecretReplicationAutoArgs.builder()
.build())
.build())
.build());
var secret_version_data = new SecretVersion("secret-version-data", SecretVersionArgs.builder()
.secret(secret.name())
.secretData("secret-data")
.build());
var instance = new DatabaseInstance("instance", DatabaseInstanceArgs.builder()
.name("cloudrun-sql")
.region("us-central1")
.databaseVersion("MYSQL_5_7")
.settings(DatabaseInstanceSettingsArgs.builder()
.tier("db-f1-micro")
.build())
.deletionProtection(true)
.build());
var default_ = new Service("default", ServiceArgs.builder()
.name("cloudrun-service")
.location("us-central1")
.deletionProtection(false)
.ingress("INGRESS_TRAFFIC_ALL")
.scaling(ServiceScalingArgs.builder()
.maxInstanceCount(2)
.build())
.template(ServiceTemplateArgs.builder()
.volumes(ServiceTemplateVolumeArgs.builder()
.name("cloudsql")
.cloudSqlInstance(ServiceTemplateVolumeCloudSqlInstanceArgs.builder()
.instances(instance.connectionName())
.build())
.build())
.containers(ServiceTemplateContainerArgs.builder()
.image("us-docker.pkg.dev/cloudrun/container/hello")
.envs(
ServiceTemplateContainerEnvArgs.builder()
.name("FOO")
.value("bar")
.build(),
ServiceTemplateContainerEnvArgs.builder()
.name("SECRET_ENV_VAR")
.valueSource(ServiceTemplateContainerEnvValueSourceArgs.builder()
.secretKeyRef(ServiceTemplateContainerEnvValueSourceSecretKeyRefArgs.builder()
.secret(secret.secretId())
.version("1")
.build())
.build())
.build())
.volumeMounts(ServiceTemplateContainerVolumeMountArgs.builder()
.name("cloudsql")
.mountPath("/cloudsql")
.build())
.build())
.build())
.traffics(ServiceTrafficArgs.builder()
.type("TRAFFIC_TARGET_ALLOCATION_TYPE_LATEST")
.percent(100)
.build())
.build(), CustomResourceOptions.builder()
.dependsOn(secret_version_data)
.build());
final var project = OrganizationsFunctions.getProject(GetProjectArgs.builder()
.build());
var secret_access = new SecretIamMember("secret-access", SecretIamMemberArgs.builder()
.secretId(secret.id())
.role("roles/secretmanager.secretAccessor")
.member(String.format("serviceAccount:%s-compute@developer.gserviceaccount.com", project.number()))
.build(), CustomResourceOptions.builder()
.dependsOn(secret)
.build());
}
}
resources:
default:
type: gcp:cloudrunv2:Service
properties:
name: cloudrun-service
location: us-central1
deletionProtection: false
ingress: INGRESS_TRAFFIC_ALL
scaling:
maxInstanceCount: 2
template:
volumes:
- name: cloudsql
cloudSqlInstance:
instances:
- ${instance.connectionName}
containers:
- image: us-docker.pkg.dev/cloudrun/container/hello
envs:
- name: FOO
value: bar
- name: SECRET_ENV_VAR
valueSource:
secretKeyRef:
secret: ${secret.secretId}
version: '1'
volumeMounts:
- name: cloudsql
mountPath: /cloudsql
traffics:
- type: TRAFFIC_TARGET_ALLOCATION_TYPE_LATEST
percent: 100
options:
dependsOn:
- ${["secret-version-data"]}
secret:
type: gcp:secretmanager:Secret
properties:
secretId: secret-1
replication:
auto: {}
secret-version-data:
type: gcp:secretmanager:SecretVersion
properties:
secret: ${secret.name}
secretData: secret-data
secret-access:
type: gcp:secretmanager:SecretIamMember
properties:
secretId: ${secret.id}
role: roles/secretmanager.secretAccessor
member: serviceAccount:${project.number}-compute@developer.gserviceaccount.com
options:
dependsOn:
- ${secret}
instance:
type: gcp:sql:DatabaseInstance
properties:
name: cloudrun-sql
region: us-central1
databaseVersion: MYSQL_5_7
settings:
tier: db-f1-micro
deletionProtection: true
variables:
project:
fn::invoke:
function: gcp:organizations:getProject
arguments: {}
The volumes array defines a cloudSqlInstance volume that Cloud Run mounts at the specified path. Your container connects via Unix socket rather than TCP. The envs array shows two patterns: direct values and secrets from Secret Manager via valueSource.secretKeyRef. The service account needs Secret Manager accessor permissions.
Route traffic through VPC Access Connector
Services that need private VPC resources use Serverless VPC Access connectors to route egress traffic.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const customTestNetwork = new gcp.compute.Network("custom_test", {
name: "run-network",
autoCreateSubnetworks: false,
});
const customTest = new gcp.compute.Subnetwork("custom_test", {
name: "run-subnetwork",
ipCidrRange: "10.2.0.0/28",
region: "us-central1",
network: customTestNetwork.id,
});
const connector = new gcp.vpcaccess.Connector("connector", {
name: "run-vpc",
subnet: {
name: customTest.name,
},
machineType: "e2-standard-4",
minInstances: 2,
maxInstances: 3,
region: "us-central1",
});
const _default = new gcp.cloudrunv2.Service("default", {
name: "cloudrun-service",
location: "us-central1",
deletionProtection: false,
template: {
containers: [{
image: "us-docker.pkg.dev/cloudrun/container/hello",
}],
vpcAccess: {
connector: connector.id,
egress: "ALL_TRAFFIC",
},
},
});
import pulumi
import pulumi_gcp as gcp
custom_test_network = gcp.compute.Network("custom_test",
name="run-network",
auto_create_subnetworks=False)
custom_test = gcp.compute.Subnetwork("custom_test",
name="run-subnetwork",
ip_cidr_range="10.2.0.0/28",
region="us-central1",
network=custom_test_network.id)
connector = gcp.vpcaccess.Connector("connector",
name="run-vpc",
subnet={
"name": custom_test.name,
},
machine_type="e2-standard-4",
min_instances=2,
max_instances=3,
region="us-central1")
default = gcp.cloudrunv2.Service("default",
name="cloudrun-service",
location="us-central1",
deletion_protection=False,
template={
"containers": [{
"image": "us-docker.pkg.dev/cloudrun/container/hello",
}],
"vpc_access": {
"connector": connector.id,
"egress": "ALL_TRAFFIC",
},
})
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/cloudrunv2"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/compute"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/vpcaccess"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
customTestNetwork, err := compute.NewNetwork(ctx, "custom_test", &compute.NetworkArgs{
Name: pulumi.String("run-network"),
AutoCreateSubnetworks: pulumi.Bool(false),
})
if err != nil {
return err
}
customTest, err := compute.NewSubnetwork(ctx, "custom_test", &compute.SubnetworkArgs{
Name: pulumi.String("run-subnetwork"),
IpCidrRange: pulumi.String("10.2.0.0/28"),
Region: pulumi.String("us-central1"),
Network: customTestNetwork.ID(),
})
if err != nil {
return err
}
connector, err := vpcaccess.NewConnector(ctx, "connector", &vpcaccess.ConnectorArgs{
Name: pulumi.String("run-vpc"),
Subnet: &vpcaccess.ConnectorSubnetArgs{
Name: customTest.Name,
},
MachineType: pulumi.String("e2-standard-4"),
MinInstances: pulumi.Int(2),
MaxInstances: pulumi.Int(3),
Region: pulumi.String("us-central1"),
})
if err != nil {
return err
}
_, err = cloudrunv2.NewService(ctx, "default", &cloudrunv2.ServiceArgs{
Name: pulumi.String("cloudrun-service"),
Location: pulumi.String("us-central1"),
DeletionProtection: pulumi.Bool(false),
Template: &cloudrunv2.ServiceTemplateArgs{
Containers: cloudrunv2.ServiceTemplateContainerArray{
&cloudrunv2.ServiceTemplateContainerArgs{
Image: pulumi.String("us-docker.pkg.dev/cloudrun/container/hello"),
},
},
VpcAccess: &cloudrunv2.ServiceTemplateVpcAccessArgs{
Connector: connector.ID(),
Egress: pulumi.String("ALL_TRAFFIC"),
},
},
})
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 customTestNetwork = new Gcp.Compute.Network("custom_test", new()
{
Name = "run-network",
AutoCreateSubnetworks = false,
});
var customTest = new Gcp.Compute.Subnetwork("custom_test", new()
{
Name = "run-subnetwork",
IpCidrRange = "10.2.0.0/28",
Region = "us-central1",
Network = customTestNetwork.Id,
});
var connector = new Gcp.VpcAccess.Connector("connector", new()
{
Name = "run-vpc",
Subnet = new Gcp.VpcAccess.Inputs.ConnectorSubnetArgs
{
Name = customTest.Name,
},
MachineType = "e2-standard-4",
MinInstances = 2,
MaxInstances = 3,
Region = "us-central1",
});
var @default = new Gcp.CloudRunV2.Service("default", new()
{
Name = "cloudrun-service",
Location = "us-central1",
DeletionProtection = false,
Template = new Gcp.CloudRunV2.Inputs.ServiceTemplateArgs
{
Containers = new[]
{
new Gcp.CloudRunV2.Inputs.ServiceTemplateContainerArgs
{
Image = "us-docker.pkg.dev/cloudrun/container/hello",
},
},
VpcAccess = new Gcp.CloudRunV2.Inputs.ServiceTemplateVpcAccessArgs
{
Connector = connector.Id,
Egress = "ALL_TRAFFIC",
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.compute.Network;
import com.pulumi.gcp.compute.NetworkArgs;
import com.pulumi.gcp.compute.Subnetwork;
import com.pulumi.gcp.compute.SubnetworkArgs;
import com.pulumi.gcp.vpcaccess.Connector;
import com.pulumi.gcp.vpcaccess.ConnectorArgs;
import com.pulumi.gcp.vpcaccess.inputs.ConnectorSubnetArgs;
import com.pulumi.gcp.cloudrunv2.Service;
import com.pulumi.gcp.cloudrunv2.ServiceArgs;
import com.pulumi.gcp.cloudrunv2.inputs.ServiceTemplateArgs;
import com.pulumi.gcp.cloudrunv2.inputs.ServiceTemplateVpcAccessArgs;
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 customTestNetwork = new Network("customTestNetwork", NetworkArgs.builder()
.name("run-network")
.autoCreateSubnetworks(false)
.build());
var customTest = new Subnetwork("customTest", SubnetworkArgs.builder()
.name("run-subnetwork")
.ipCidrRange("10.2.0.0/28")
.region("us-central1")
.network(customTestNetwork.id())
.build());
var connector = new Connector("connector", ConnectorArgs.builder()
.name("run-vpc")
.subnet(ConnectorSubnetArgs.builder()
.name(customTest.name())
.build())
.machineType("e2-standard-4")
.minInstances(2)
.maxInstances(3)
.region("us-central1")
.build());
var default_ = new Service("default", ServiceArgs.builder()
.name("cloudrun-service")
.location("us-central1")
.deletionProtection(false)
.template(ServiceTemplateArgs.builder()
.containers(ServiceTemplateContainerArgs.builder()
.image("us-docker.pkg.dev/cloudrun/container/hello")
.build())
.vpcAccess(ServiceTemplateVpcAccessArgs.builder()
.connector(connector.id())
.egress("ALL_TRAFFIC")
.build())
.build())
.build());
}
}
resources:
default:
type: gcp:cloudrunv2:Service
properties:
name: cloudrun-service
location: us-central1
deletionProtection: false
template:
containers:
- image: us-docker.pkg.dev/cloudrun/container/hello
vpcAccess:
connector: ${connector.id}
egress: ALL_TRAFFIC
connector:
type: gcp:vpcaccess:Connector
properties:
name: run-vpc
subnet:
name: ${customTest.name}
machineType: e2-standard-4
minInstances: 2
maxInstances: 3
region: us-central1
customTest:
type: gcp:compute:Subnetwork
name: custom_test
properties:
name: run-subnetwork
ipCidrRange: 10.2.0.0/28
region: us-central1
network: ${customTestNetwork.id}
customTestNetwork:
type: gcp:compute:Network
name: custom_test
properties:
name: run-network
autoCreateSubnetworks: false
The vpcAccess.connector property references a VPC Access Connector that bridges Cloud Run to your VPC. Setting egress to ALL_TRAFFIC routes all outbound requests through the connector, enabling access to private IPs, Cloud SQL private connections, and internal load balancers.
Connect directly to VPC with network interfaces
Direct VPC egress attaches network interfaces to your service, reducing latency for VPC communication.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const _default = new gcp.cloudrunv2.Service("default", {
name: "cloudrun-service",
location: "us-central1",
deletionProtection: false,
launchStage: "GA",
template: {
containers: [{
image: "us-docker.pkg.dev/cloudrun/container/hello",
}],
vpcAccess: {
networkInterfaces: [{
network: "default",
subnetwork: "default",
tags: [
"tag1",
"tag2",
"tag3",
],
}],
},
},
});
import pulumi
import pulumi_gcp as gcp
default = gcp.cloudrunv2.Service("default",
name="cloudrun-service",
location="us-central1",
deletion_protection=False,
launch_stage="GA",
template={
"containers": [{
"image": "us-docker.pkg.dev/cloudrun/container/hello",
}],
"vpc_access": {
"network_interfaces": [{
"network": "default",
"subnetwork": "default",
"tags": [
"tag1",
"tag2",
"tag3",
],
}],
},
})
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/cloudrunv2"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := cloudrunv2.NewService(ctx, "default", &cloudrunv2.ServiceArgs{
Name: pulumi.String("cloudrun-service"),
Location: pulumi.String("us-central1"),
DeletionProtection: pulumi.Bool(false),
LaunchStage: pulumi.String("GA"),
Template: &cloudrunv2.ServiceTemplateArgs{
Containers: cloudrunv2.ServiceTemplateContainerArray{
&cloudrunv2.ServiceTemplateContainerArgs{
Image: pulumi.String("us-docker.pkg.dev/cloudrun/container/hello"),
},
},
VpcAccess: &cloudrunv2.ServiceTemplateVpcAccessArgs{
NetworkInterfaces: cloudrunv2.ServiceTemplateVpcAccessNetworkInterfaceArray{
&cloudrunv2.ServiceTemplateVpcAccessNetworkInterfaceArgs{
Network: pulumi.String("default"),
Subnetwork: pulumi.String("default"),
Tags: pulumi.StringArray{
pulumi.String("tag1"),
pulumi.String("tag2"),
pulumi.String("tag3"),
},
},
},
},
},
})
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.CloudRunV2.Service("default", new()
{
Name = "cloudrun-service",
Location = "us-central1",
DeletionProtection = false,
LaunchStage = "GA",
Template = new Gcp.CloudRunV2.Inputs.ServiceTemplateArgs
{
Containers = new[]
{
new Gcp.CloudRunV2.Inputs.ServiceTemplateContainerArgs
{
Image = "us-docker.pkg.dev/cloudrun/container/hello",
},
},
VpcAccess = new Gcp.CloudRunV2.Inputs.ServiceTemplateVpcAccessArgs
{
NetworkInterfaces = new[]
{
new Gcp.CloudRunV2.Inputs.ServiceTemplateVpcAccessNetworkInterfaceArgs
{
Network = "default",
Subnetwork = "default",
Tags = new[]
{
"tag1",
"tag2",
"tag3",
},
},
},
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.cloudrunv2.Service;
import com.pulumi.gcp.cloudrunv2.ServiceArgs;
import com.pulumi.gcp.cloudrunv2.inputs.ServiceTemplateArgs;
import com.pulumi.gcp.cloudrunv2.inputs.ServiceTemplateVpcAccessArgs;
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-service")
.location("us-central1")
.deletionProtection(false)
.launchStage("GA")
.template(ServiceTemplateArgs.builder()
.containers(ServiceTemplateContainerArgs.builder()
.image("us-docker.pkg.dev/cloudrun/container/hello")
.build())
.vpcAccess(ServiceTemplateVpcAccessArgs.builder()
.networkInterfaces(ServiceTemplateVpcAccessNetworkInterfaceArgs.builder()
.network("default")
.subnetwork("default")
.tags(
"tag1",
"tag2",
"tag3")
.build())
.build())
.build())
.build());
}
}
resources:
default:
type: gcp:cloudrunv2:Service
properties:
name: cloudrun-service
location: us-central1
deletionProtection: false
launchStage: GA
template:
containers:
- image: us-docker.pkg.dev/cloudrun/container/hello
vpcAccess:
networkInterfaces:
- network: default
subnetwork: default
tags:
- tag1
- tag2
- tag3
The networkInterfaces property attaches your service directly to VPC subnets without a connector. This reduces latency and cost for VPC resource access. The tags array applies network tags for firewall rules.
Configure health checks with startup and liveness probes
Production services need 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.cloudrunv2.Service("default", {
name: "cloudrun-service",
location: "us-central1",
deletionProtection: false,
template: {
containers: [{
image: "us-docker.pkg.dev/cloudrun/container/hello",
startupProbe: {
initialDelaySeconds: 0,
timeoutSeconds: 1,
periodSeconds: 3,
failureThreshold: 1,
tcpSocket: {
port: 8080,
},
},
livenessProbe: {
httpGet: {
path: "/",
},
},
}],
},
});
import pulumi
import pulumi_gcp as gcp
default = gcp.cloudrunv2.Service("default",
name="cloudrun-service",
location="us-central1",
deletion_protection=False,
template={
"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": "/",
},
},
}],
})
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/cloudrunv2"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := cloudrunv2.NewService(ctx, "default", &cloudrunv2.ServiceArgs{
Name: pulumi.String("cloudrun-service"),
Location: pulumi.String("us-central1"),
DeletionProtection: pulumi.Bool(false),
Template: &cloudrunv2.ServiceTemplateArgs{
Containers: cloudrunv2.ServiceTemplateContainerArray{
&cloudrunv2.ServiceTemplateContainerArgs{
Image: pulumi.String("us-docker.pkg.dev/cloudrun/container/hello"),
StartupProbe: &cloudrunv2.ServiceTemplateContainerStartupProbeArgs{
InitialDelaySeconds: pulumi.Int(0),
TimeoutSeconds: pulumi.Int(1),
PeriodSeconds: pulumi.Int(3),
FailureThreshold: pulumi.Int(1),
TcpSocket: &cloudrunv2.ServiceTemplateContainerStartupProbeTcpSocketArgs{
Port: pulumi.Int(8080),
},
},
LivenessProbe: &cloudrunv2.ServiceTemplateContainerLivenessProbeArgs{
HttpGet: &cloudrunv2.ServiceTemplateContainerLivenessProbeHttpGetArgs{
Path: pulumi.String("/"),
},
},
},
},
},
})
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.CloudRunV2.Service("default", new()
{
Name = "cloudrun-service",
Location = "us-central1",
DeletionProtection = false,
Template = new Gcp.CloudRunV2.Inputs.ServiceTemplateArgs
{
Containers = new[]
{
new Gcp.CloudRunV2.Inputs.ServiceTemplateContainerArgs
{
Image = "us-docker.pkg.dev/cloudrun/container/hello",
StartupProbe = new Gcp.CloudRunV2.Inputs.ServiceTemplateContainerStartupProbeArgs
{
InitialDelaySeconds = 0,
TimeoutSeconds = 1,
PeriodSeconds = 3,
FailureThreshold = 1,
TcpSocket = new Gcp.CloudRunV2.Inputs.ServiceTemplateContainerStartupProbeTcpSocketArgs
{
Port = 8080,
},
},
LivenessProbe = new Gcp.CloudRunV2.Inputs.ServiceTemplateContainerLivenessProbeArgs
{
HttpGet = new Gcp.CloudRunV2.Inputs.ServiceTemplateContainerLivenessProbeHttpGetArgs
{
Path = "/",
},
},
},
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.cloudrunv2.Service;
import com.pulumi.gcp.cloudrunv2.ServiceArgs;
import com.pulumi.gcp.cloudrunv2.inputs.ServiceTemplateArgs;
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-service")
.location("us-central1")
.deletionProtection(false)
.template(ServiceTemplateArgs.builder()
.containers(ServiceTemplateContainerArgs.builder()
.image("us-docker.pkg.dev/cloudrun/container/hello")
.startupProbe(ServiceTemplateContainerStartupProbeArgs.builder()
.initialDelaySeconds(0)
.timeoutSeconds(1)
.periodSeconds(3)
.failureThreshold(1)
.tcpSocket(ServiceTemplateContainerStartupProbeTcpSocketArgs.builder()
.port(8080)
.build())
.build())
.livenessProbe(ServiceTemplateContainerLivenessProbeArgs.builder()
.httpGet(ServiceTemplateContainerLivenessProbeHttpGetArgs.builder()
.path("/")
.build())
.build())
.build())
.build())
.build());
}
}
resources:
default:
type: gcp:cloudrunv2:Service
properties:
name: cloudrun-service
location: us-central1
deletionProtection: false
template:
containers:
- image: us-docker.pkg.dev/cloudrun/container/hello
startupProbe:
initialDelaySeconds: 0
timeoutSeconds: 1
periodSeconds: 3
failureThreshold: 1
tcpSocket:
port: 8080
livenessProbe:
httpGet:
path: /
The startupProbe runs during container initialization, using tcpSocket to check port availability. The livenessProbe monitors running containers with httpGet requests. Cloud Run replaces containers that fail liveness checks. The periodSeconds and failureThreshold properties control check frequency and tolerance.
Run multiple containers with shared volumes
Sidecar patterns can run multiple containers in a single service, sharing volumes and coordinating startup.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const _default = new gcp.cloudrunv2.Service("default", {
name: "cloudrun-service",
location: "us-central1",
deletionProtection: false,
ingress: "INGRESS_TRAFFIC_ALL",
template: {
containers: [
{
name: "hello-1",
ports: {
containerPort: 8080,
},
image: "us-docker.pkg.dev/cloudrun/container/hello",
dependsOns: ["hello-2"],
volumeMounts: [{
name: "empty-dir-volume",
mountPath: "/mnt",
}],
},
{
name: "hello-2",
image: "us-docker.pkg.dev/cloudrun/container/hello",
envs: [{
name: "PORT",
value: "8081",
}],
startupProbe: {
httpGet: {
port: 8081,
},
},
},
],
volumes: [{
name: "empty-dir-volume",
emptyDir: {
medium: "MEMORY",
sizeLimit: "256Mi",
},
}],
},
});
import pulumi
import pulumi_gcp as gcp
default = gcp.cloudrunv2.Service("default",
name="cloudrun-service",
location="us-central1",
deletion_protection=False,
ingress="INGRESS_TRAFFIC_ALL",
template={
"containers": [
{
"name": "hello-1",
"ports": {
"container_port": 8080,
},
"image": "us-docker.pkg.dev/cloudrun/container/hello",
"depends_ons": ["hello-2"],
"volume_mounts": [{
"name": "empty-dir-volume",
"mount_path": "/mnt",
}],
},
{
"name": "hello-2",
"image": "us-docker.pkg.dev/cloudrun/container/hello",
"envs": [{
"name": "PORT",
"value": "8081",
}],
"startup_probe": {
"http_get": {
"port": 8081,
},
},
},
],
"volumes": [{
"name": "empty-dir-volume",
"empty_dir": {
"medium": "MEMORY",
"size_limit": "256Mi",
},
}],
})
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/cloudrunv2"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := cloudrunv2.NewService(ctx, "default", &cloudrunv2.ServiceArgs{
Name: pulumi.String("cloudrun-service"),
Location: pulumi.String("us-central1"),
DeletionProtection: pulumi.Bool(false),
Ingress: pulumi.String("INGRESS_TRAFFIC_ALL"),
Template: &cloudrunv2.ServiceTemplateArgs{
Containers: cloudrunv2.ServiceTemplateContainerArray{
&cloudrunv2.ServiceTemplateContainerArgs{
Name: pulumi.String("hello-1"),
Ports: &cloudrunv2.ServiceTemplateContainerPortsArgs{
ContainerPort: pulumi.Int(8080),
},
Image: pulumi.String("us-docker.pkg.dev/cloudrun/container/hello"),
DependsOns: pulumi.StringArray{
pulumi.String("hello-2"),
},
VolumeMounts: cloudrunv2.ServiceTemplateContainerVolumeMountArray{
&cloudrunv2.ServiceTemplateContainerVolumeMountArgs{
Name: pulumi.String("empty-dir-volume"),
MountPath: pulumi.String("/mnt"),
},
},
},
&cloudrunv2.ServiceTemplateContainerArgs{
Name: pulumi.String("hello-2"),
Image: pulumi.String("us-docker.pkg.dev/cloudrun/container/hello"),
Envs: cloudrunv2.ServiceTemplateContainerEnvArray{
&cloudrunv2.ServiceTemplateContainerEnvArgs{
Name: pulumi.String("PORT"),
Value: pulumi.String("8081"),
},
},
StartupProbe: &cloudrunv2.ServiceTemplateContainerStartupProbeArgs{
HttpGet: &cloudrunv2.ServiceTemplateContainerStartupProbeHttpGetArgs{
Port: pulumi.Int(8081),
},
},
},
},
Volumes: cloudrunv2.ServiceTemplateVolumeArray{
&cloudrunv2.ServiceTemplateVolumeArgs{
Name: pulumi.String("empty-dir-volume"),
EmptyDir: &cloudrunv2.ServiceTemplateVolumeEmptyDirArgs{
Medium: pulumi.String("MEMORY"),
SizeLimit: pulumi.String("256Mi"),
},
},
},
},
})
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.CloudRunV2.Service("default", new()
{
Name = "cloudrun-service",
Location = "us-central1",
DeletionProtection = false,
Ingress = "INGRESS_TRAFFIC_ALL",
Template = new Gcp.CloudRunV2.Inputs.ServiceTemplateArgs
{
Containers = new[]
{
new Gcp.CloudRunV2.Inputs.ServiceTemplateContainerArgs
{
Name = "hello-1",
Ports = new Gcp.CloudRunV2.Inputs.ServiceTemplateContainerPortsArgs
{
ContainerPort = 8080,
},
Image = "us-docker.pkg.dev/cloudrun/container/hello",
DependsOns = new[]
{
"hello-2",
},
VolumeMounts = new[]
{
new Gcp.CloudRunV2.Inputs.ServiceTemplateContainerVolumeMountArgs
{
Name = "empty-dir-volume",
MountPath = "/mnt",
},
},
},
new Gcp.CloudRunV2.Inputs.ServiceTemplateContainerArgs
{
Name = "hello-2",
Image = "us-docker.pkg.dev/cloudrun/container/hello",
Envs = new[]
{
new Gcp.CloudRunV2.Inputs.ServiceTemplateContainerEnvArgs
{
Name = "PORT",
Value = "8081",
},
},
StartupProbe = new Gcp.CloudRunV2.Inputs.ServiceTemplateContainerStartupProbeArgs
{
HttpGet = new Gcp.CloudRunV2.Inputs.ServiceTemplateContainerStartupProbeHttpGetArgs
{
Port = 8081,
},
},
},
},
Volumes = new[]
{
new Gcp.CloudRunV2.Inputs.ServiceTemplateVolumeArgs
{
Name = "empty-dir-volume",
EmptyDir = new Gcp.CloudRunV2.Inputs.ServiceTemplateVolumeEmptyDirArgs
{
Medium = "MEMORY",
SizeLimit = "256Mi",
},
},
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.cloudrunv2.Service;
import com.pulumi.gcp.cloudrunv2.ServiceArgs;
import com.pulumi.gcp.cloudrunv2.inputs.ServiceTemplateArgs;
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-service")
.location("us-central1")
.deletionProtection(false)
.ingress("INGRESS_TRAFFIC_ALL")
.template(ServiceTemplateArgs.builder()
.containers(
ServiceTemplateContainerArgs.builder()
.name("hello-1")
.ports(ServiceTemplateContainerPortsArgs.builder()
.containerPort(8080)
.build())
.image("us-docker.pkg.dev/cloudrun/container/hello")
.dependsOns("hello-2")
.volumeMounts(ServiceTemplateContainerVolumeMountArgs.builder()
.name("empty-dir-volume")
.mountPath("/mnt")
.build())
.build(),
ServiceTemplateContainerArgs.builder()
.name("hello-2")
.image("us-docker.pkg.dev/cloudrun/container/hello")
.envs(ServiceTemplateContainerEnvArgs.builder()
.name("PORT")
.value("8081")
.build())
.startupProbe(ServiceTemplateContainerStartupProbeArgs.builder()
.httpGet(ServiceTemplateContainerStartupProbeHttpGetArgs.builder()
.port(8081)
.build())
.build())
.build())
.volumes(ServiceTemplateVolumeArgs.builder()
.name("empty-dir-volume")
.emptyDir(ServiceTemplateVolumeEmptyDirArgs.builder()
.medium("MEMORY")
.sizeLimit("256Mi")
.build())
.build())
.build())
.build());
}
}
resources:
default:
type: gcp:cloudrunv2:Service
properties:
name: cloudrun-service
location: us-central1
deletionProtection: false
ingress: INGRESS_TRAFFIC_ALL
template:
containers:
- name: hello-1
ports:
containerPort: 8080
image: us-docker.pkg.dev/cloudrun/container/hello
dependsOns:
- hello-2
volumeMounts:
- name: empty-dir-volume
mountPath: /mnt
- name: hello-2
image: us-docker.pkg.dev/cloudrun/container/hello
envs:
- name: PORT
value: '8081'
startupProbe:
httpGet:
port: 8081
volumes:
- name: empty-dir-volume
emptyDir:
medium: MEMORY
sizeLimit: 256Mi
The containers array defines multiple containers with distinct names. The dependsOns property controls startup order, ensuring hello-2 starts before hello-1. The emptyDir volume provides shared memory-backed storage. Each container mounts volumes at different paths via volumeMounts.
Mount secrets as files in containers
Applications that read configuration from files can mount Secret Manager secrets as volumes.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const secret = new gcp.secretmanager.Secret("secret", {
secretId: "secret-1",
replication: {
auto: {},
},
});
const secret_version_data = new gcp.secretmanager.SecretVersion("secret-version-data", {
secret: secret.name,
secretData: "secret-data",
});
const _default = new gcp.cloudrunv2.Service("default", {
name: "cloudrun-service",
location: "us-central1",
deletionProtection: false,
ingress: "INGRESS_TRAFFIC_ALL",
template: {
volumes: [{
name: "a-volume",
secret: {
secret: secret.secretId,
defaultMode: 292,
items: [{
version: "1",
path: "my-secret",
}],
},
}],
containers: [{
image: "us-docker.pkg.dev/cloudrun/container/hello",
volumeMounts: [{
name: "a-volume",
mountPath: "/secrets",
}],
}],
},
}, {
dependsOn: [secret_version_data],
});
const project = gcp.organizations.getProject({});
const secret_access = new gcp.secretmanager.SecretIamMember("secret-access", {
secretId: secret.id,
role: "roles/secretmanager.secretAccessor",
member: project.then(project => `serviceAccount:${project.number}-compute@developer.gserviceaccount.com`),
}, {
dependsOn: [secret],
});
import pulumi
import pulumi_gcp as gcp
secret = gcp.secretmanager.Secret("secret",
secret_id="secret-1",
replication={
"auto": {},
})
secret_version_data = gcp.secretmanager.SecretVersion("secret-version-data",
secret=secret.name,
secret_data="secret-data")
default = gcp.cloudrunv2.Service("default",
name="cloudrun-service",
location="us-central1",
deletion_protection=False,
ingress="INGRESS_TRAFFIC_ALL",
template={
"volumes": [{
"name": "a-volume",
"secret": {
"secret": secret.secret_id,
"default_mode": 292,
"items": [{
"version": "1",
"path": "my-secret",
}],
},
}],
"containers": [{
"image": "us-docker.pkg.dev/cloudrun/container/hello",
"volume_mounts": [{
"name": "a-volume",
"mount_path": "/secrets",
}],
}],
},
opts = pulumi.ResourceOptions(depends_on=[secret_version_data]))
project = gcp.organizations.get_project()
secret_access = gcp.secretmanager.SecretIamMember("secret-access",
secret_id=secret.id,
role="roles/secretmanager.secretAccessor",
member=f"serviceAccount:{project.number}-compute@developer.gserviceaccount.com",
opts = pulumi.ResourceOptions(depends_on=[secret]))
package main
import (
"fmt"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/cloudrunv2"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/organizations"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/secretmanager"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
secret, err := secretmanager.NewSecret(ctx, "secret", &secretmanager.SecretArgs{
SecretId: pulumi.String("secret-1"),
Replication: &secretmanager.SecretReplicationArgs{
Auto: &secretmanager.SecretReplicationAutoArgs{},
},
})
if err != nil {
return err
}
secret_version_data, err := secretmanager.NewSecretVersion(ctx, "secret-version-data", &secretmanager.SecretVersionArgs{
Secret: secret.Name,
SecretData: pulumi.String("secret-data"),
})
if err != nil {
return err
}
_, err = cloudrunv2.NewService(ctx, "default", &cloudrunv2.ServiceArgs{
Name: pulumi.String("cloudrun-service"),
Location: pulumi.String("us-central1"),
DeletionProtection: pulumi.Bool(false),
Ingress: pulumi.String("INGRESS_TRAFFIC_ALL"),
Template: &cloudrunv2.ServiceTemplateArgs{
Volumes: cloudrunv2.ServiceTemplateVolumeArray{
&cloudrunv2.ServiceTemplateVolumeArgs{
Name: pulumi.String("a-volume"),
Secret: &cloudrunv2.ServiceTemplateVolumeSecretArgs{
Secret: secret.SecretId,
DefaultMode: pulumi.Int(292),
Items: cloudrunv2.ServiceTemplateVolumeSecretItemArray{
&cloudrunv2.ServiceTemplateVolumeSecretItemArgs{
Version: pulumi.String("1"),
Path: pulumi.String("my-secret"),
},
},
},
},
},
Containers: cloudrunv2.ServiceTemplateContainerArray{
&cloudrunv2.ServiceTemplateContainerArgs{
Image: pulumi.String("us-docker.pkg.dev/cloudrun/container/hello"),
VolumeMounts: cloudrunv2.ServiceTemplateContainerVolumeMountArray{
&cloudrunv2.ServiceTemplateContainerVolumeMountArgs{
Name: pulumi.String("a-volume"),
MountPath: pulumi.String("/secrets"),
},
},
},
},
},
}, pulumi.DependsOn([]pulumi.Resource{
secret_version_data,
}))
if err != nil {
return err
}
project, err := organizations.LookupProject(ctx, &organizations.LookupProjectArgs{}, nil)
if err != nil {
return err
}
_, err = secretmanager.NewSecretIamMember(ctx, "secret-access", &secretmanager.SecretIamMemberArgs{
SecretId: secret.ID(),
Role: pulumi.String("roles/secretmanager.secretAccessor"),
Member: pulumi.Sprintf("serviceAccount:%v-compute@developer.gserviceaccount.com", project.Number),
}, pulumi.DependsOn([]pulumi.Resource{
secret,
}))
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 secret = new Gcp.SecretManager.Secret("secret", new()
{
SecretId = "secret-1",
Replication = new Gcp.SecretManager.Inputs.SecretReplicationArgs
{
Auto = null,
},
});
var secret_version_data = new Gcp.SecretManager.SecretVersion("secret-version-data", new()
{
Secret = secret.Name,
SecretData = "secret-data",
});
var @default = new Gcp.CloudRunV2.Service("default", new()
{
Name = "cloudrun-service",
Location = "us-central1",
DeletionProtection = false,
Ingress = "INGRESS_TRAFFIC_ALL",
Template = new Gcp.CloudRunV2.Inputs.ServiceTemplateArgs
{
Volumes = new[]
{
new Gcp.CloudRunV2.Inputs.ServiceTemplateVolumeArgs
{
Name = "a-volume",
Secret = new Gcp.CloudRunV2.Inputs.ServiceTemplateVolumeSecretArgs
{
Secret = secret.SecretId,
DefaultMode = 292,
Items = new[]
{
new Gcp.CloudRunV2.Inputs.ServiceTemplateVolumeSecretItemArgs
{
Version = "1",
Path = "my-secret",
},
},
},
},
},
Containers = new[]
{
new Gcp.CloudRunV2.Inputs.ServiceTemplateContainerArgs
{
Image = "us-docker.pkg.dev/cloudrun/container/hello",
VolumeMounts = new[]
{
new Gcp.CloudRunV2.Inputs.ServiceTemplateContainerVolumeMountArgs
{
Name = "a-volume",
MountPath = "/secrets",
},
},
},
},
},
}, new CustomResourceOptions
{
DependsOn =
{
secret_version_data,
},
});
var project = Gcp.Organizations.GetProject.Invoke();
var secret_access = new Gcp.SecretManager.SecretIamMember("secret-access", new()
{
SecretId = secret.Id,
Role = "roles/secretmanager.secretAccessor",
Member = $"serviceAccount:{project.Apply(getProjectResult => getProjectResult.Number)}-compute@developer.gserviceaccount.com",
}, new CustomResourceOptions
{
DependsOn =
{
secret,
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.secretmanager.Secret;
import com.pulumi.gcp.secretmanager.SecretArgs;
import com.pulumi.gcp.secretmanager.inputs.SecretReplicationArgs;
import com.pulumi.gcp.secretmanager.inputs.SecretReplicationAutoArgs;
import com.pulumi.gcp.secretmanager.SecretVersion;
import com.pulumi.gcp.secretmanager.SecretVersionArgs;
import com.pulumi.gcp.cloudrunv2.Service;
import com.pulumi.gcp.cloudrunv2.ServiceArgs;
import com.pulumi.gcp.cloudrunv2.inputs.ServiceTemplateArgs;
import com.pulumi.gcp.organizations.OrganizationsFunctions;
import com.pulumi.gcp.organizations.inputs.GetProjectArgs;
import com.pulumi.gcp.secretmanager.SecretIamMember;
import com.pulumi.gcp.secretmanager.SecretIamMemberArgs;
import com.pulumi.resources.CustomResourceOptions;
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 secret = new Secret("secret", SecretArgs.builder()
.secretId("secret-1")
.replication(SecretReplicationArgs.builder()
.auto(SecretReplicationAutoArgs.builder()
.build())
.build())
.build());
var secret_version_data = new SecretVersion("secret-version-data", SecretVersionArgs.builder()
.secret(secret.name())
.secretData("secret-data")
.build());
var default_ = new Service("default", ServiceArgs.builder()
.name("cloudrun-service")
.location("us-central1")
.deletionProtection(false)
.ingress("INGRESS_TRAFFIC_ALL")
.template(ServiceTemplateArgs.builder()
.volumes(ServiceTemplateVolumeArgs.builder()
.name("a-volume")
.secret(ServiceTemplateVolumeSecretArgs.builder()
.secret(secret.secretId())
.defaultMode(292)
.items(ServiceTemplateVolumeSecretItemArgs.builder()
.version("1")
.path("my-secret")
.build())
.build())
.build())
.containers(ServiceTemplateContainerArgs.builder()
.image("us-docker.pkg.dev/cloudrun/container/hello")
.volumeMounts(ServiceTemplateContainerVolumeMountArgs.builder()
.name("a-volume")
.mountPath("/secrets")
.build())
.build())
.build())
.build(), CustomResourceOptions.builder()
.dependsOn(secret_version_data)
.build());
final var project = OrganizationsFunctions.getProject(GetProjectArgs.builder()
.build());
var secret_access = new SecretIamMember("secret-access", SecretIamMemberArgs.builder()
.secretId(secret.id())
.role("roles/secretmanager.secretAccessor")
.member(String.format("serviceAccount:%s-compute@developer.gserviceaccount.com", project.number()))
.build(), CustomResourceOptions.builder()
.dependsOn(secret)
.build());
}
}
resources:
default:
type: gcp:cloudrunv2:Service
properties:
name: cloudrun-service
location: us-central1
deletionProtection: false
ingress: INGRESS_TRAFFIC_ALL
template:
volumes:
- name: a-volume
secret:
secret: ${secret.secretId}
defaultMode: 292
items:
- version: '1'
path: my-secret
containers:
- image: us-docker.pkg.dev/cloudrun/container/hello
volumeMounts:
- name: a-volume
mountPath: /secrets
options:
dependsOn:
- ${["secret-version-data"]}
secret:
type: gcp:secretmanager:Secret
properties:
secretId: secret-1
replication:
auto: {}
secret-version-data:
type: gcp:secretmanager:SecretVersion
properties:
secret: ${secret.name}
secretData: secret-data
secret-access:
type: gcp:secretmanager:SecretIamMember
properties:
secretId: ${secret.id}
role: roles/secretmanager.secretAccessor
member: serviceAccount:${project.number}-compute@developer.gserviceaccount.com
options:
dependsOn:
- ${secret}
variables:
project:
fn::invoke:
function: gcp:organizations:getProject
arguments: {}
The volumes.secret block mounts a Secret Manager secret at the specified path. The items array maps secret versions to file paths within the mount. Your container reads the secret from /secrets/my-secret. The defaultMode sets file permissions (292 is octal 0444, read-only).
Beyond these examples
These snippets focus on specific service-level features: container deployment and resource limits, VPC networking (connectors and direct interfaces), volume mounts (Cloud SQL, secrets, GCS, NFS, emptyDir), 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 VPC networks, subnets, and VPC Access Connectors, Cloud SQL instances and Secret Manager secrets, and IAM service accounts with appropriate permissions. They focus on configuring the service rather than provisioning everything around it.
To keep things focused, common service patterns are omitted, including:
- Traffic splitting and revision management (traffics property)
- Binary Authorization and build configuration
- Service mesh integration and IAP authentication
- Custom audiences and invoker IAM controls
- GCS and NFS volume mounts
- GPU configuration and node selectors
These omissions are intentional: the goal is to illustrate how each service feature is wired, not provide drop-in application modules. See the Cloud Run Service resource reference for all available configuration options.
Let's deploy GCP 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
Configuration & Immutability
location, name, and project properties are immutable and cannot be changed after service creation.annotations and labels fields are non-authoritative and only manage values present in your configuration. To access all annotations and labels on the resource, use the effectiveAnnotations and effectiveLabels output fields.reconciling output field indicates whether Cloud Run is asynchronously performing steps to bring the service to its desired state. When true, fields like observedGeneration, latestReadyRevision, and uri may have transient values. Once reconciliation completes, these fields will match the intended state or show error information in terminalCondition.Networking & VPC
vpcAccess.connector with a connector ID and egress setting. Direct VPC access uses vpcAccess.networkInterfaces with network, subnetwork, and optional tags. Direct VPC provides more granular control over network configuration.INGRESS_TRAFFIC_ALL (public access), INGRESS_TRAFFIC_INTERNAL_ONLY (VPC internal only), and INGRESS_TRAFFIC_INTERNAL_LOAD_BALANCER (internal load balancer only).Dependencies & Timing
time.Sleep with createDuration: "1m") after mesh creation and add it as a dependency.roles/secretmanager.secretAccessor role using gcp.secretmanager.SecretIamMember. Use dependsOn to ensure the secret version exists before creating the service.Storage & Volumes
template.executionEnvironment to EXECUTION_ENVIRONMENT_GEN2, create a volume with gcs configuration containing the bucket name and readOnly setting, then mount it using volumeMounts in your container.template.executionEnvironment to EXECUTION_ENVIRONMENT_GEN2, configure vpcAccess.networkInterfaces for VPC connectivity, create a volume with nfs configuration (server IP and path), and mount it in your container.cloudSqlInstance containing the instance connection name, mount it in your container using volumeMounts, and use dependsOn to ensure dependencies are created first.Advanced Features
nvidia.com/gpu (e.g., "1"), configure template.nodeSelector.accelerator with the GPU type (e.g., nvidia-l4), and optionally set gpuZonalRedundancyDisabled to true.template.containers. Use the dependsOns field to specify startup order, and share data between containers using emptyDir volumes with medium and sizeLimit settings.iapEnabled to true and launchStage to BETA, as IAP is a preview feature.invokerIamDisabled to true. The service URL will not perform IAM checks when invoked.Traffic & Deployment
traffics is empty or not provided, Cloud Run defaults to 100% traffic to the latest Ready Revision.ALPHA, BETA, and GA. If not specified, GA is assumed. Set the launch stage to a preview stage (ALPHA or BETA) to use preview features in that stage.Using a different cloud?
Explore containers guides for other cloud providers: