The gcp:compute/backendService:BackendService resource, part of the Pulumi GCP provider, defines a global backend service that routes load balancer traffic to backend groups. This guide focuses on four capabilities: health checking and basic routing, Cloud CDN caching strategies, Traffic Director service mesh configuration, and session affinity with custom metrics.
Backend services reference health checks and backend groups that must exist separately. The examples are intentionally small. Combine them with your own instance groups, network endpoint groups, and load balancer frontends.
Route traffic to instance groups with health checks
Most deployments start by creating a backend service that routes traffic to compute instances, with health checks ensuring only healthy backends receive requests.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const defaultHttpHealthCheck = new gcp.compute.HttpHealthCheck("default", {
name: "health-check",
requestPath: "/",
checkIntervalSec: 1,
timeoutSec: 1,
});
const _default = new gcp.compute.BackendService("default", {
name: "backend-service",
healthChecks: defaultHttpHealthCheck.id,
});
import pulumi
import pulumi_gcp as gcp
default_http_health_check = gcp.compute.HttpHealthCheck("default",
name="health-check",
request_path="/",
check_interval_sec=1,
timeout_sec=1)
default = gcp.compute.BackendService("default",
name="backend-service",
health_checks=default_http_health_check.id)
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/compute"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
defaultHttpHealthCheck, err := compute.NewHttpHealthCheck(ctx, "default", &compute.HttpHealthCheckArgs{
Name: pulumi.String("health-check"),
RequestPath: pulumi.String("/"),
CheckIntervalSec: pulumi.Int(1),
TimeoutSec: pulumi.Int(1),
})
if err != nil {
return err
}
_, err = compute.NewBackendService(ctx, "default", &compute.BackendServiceArgs{
Name: pulumi.String("backend-service"),
HealthChecks: defaultHttpHealthCheck.ID(),
})
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 defaultHttpHealthCheck = new Gcp.Compute.HttpHealthCheck("default", new()
{
Name = "health-check",
RequestPath = "/",
CheckIntervalSec = 1,
TimeoutSec = 1,
});
var @default = new Gcp.Compute.BackendService("default", new()
{
Name = "backend-service",
HealthChecks = defaultHttpHealthCheck.Id,
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.compute.HttpHealthCheck;
import com.pulumi.gcp.compute.HttpHealthCheckArgs;
import com.pulumi.gcp.compute.BackendService;
import com.pulumi.gcp.compute.BackendServiceArgs;
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 defaultHttpHealthCheck = new HttpHealthCheck("defaultHttpHealthCheck", HttpHealthCheckArgs.builder()
.name("health-check")
.requestPath("/")
.checkIntervalSec(1)
.timeoutSec(1)
.build());
var default_ = new BackendService("default", BackendServiceArgs.builder()
.name("backend-service")
.healthChecks(defaultHttpHealthCheck.id())
.build());
}
}
resources:
default:
type: gcp:compute:BackendService
properties:
name: backend-service
healthChecks: ${defaultHttpHealthCheck.id}
defaultHttpHealthCheck:
type: gcp:compute:HttpHealthCheck
name: default
properties:
name: health-check
requestPath: /
checkIntervalSec: 1
timeoutSec: 1
The healthChecks property links to an HttpHealthCheck resource that probes backends on a specified path. Without backends attached, this service defines routing rules but doesn’t yet direct traffic anywhere. Add backends via the backends property to complete the configuration.
Enable Cloud CDN with signed URL caching
Applications serving static content or cacheable responses use Cloud CDN to reduce origin load and improve response times.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const defaultHttpHealthCheck = new gcp.compute.HttpHealthCheck("default", {
name: "health-check",
requestPath: "/",
checkIntervalSec: 1,
timeoutSec: 1,
});
const _default = new gcp.compute.BackendService("default", {
name: "backend-service",
healthChecks: defaultHttpHealthCheck.id,
enableCdn: true,
cdnPolicy: {
signedUrlCacheMaxAgeSec: 7200,
},
});
import pulumi
import pulumi_gcp as gcp
default_http_health_check = gcp.compute.HttpHealthCheck("default",
name="health-check",
request_path="/",
check_interval_sec=1,
timeout_sec=1)
default = gcp.compute.BackendService("default",
name="backend-service",
health_checks=default_http_health_check.id,
enable_cdn=True,
cdn_policy={
"signed_url_cache_max_age_sec": 7200,
})
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/compute"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
defaultHttpHealthCheck, err := compute.NewHttpHealthCheck(ctx, "default", &compute.HttpHealthCheckArgs{
Name: pulumi.String("health-check"),
RequestPath: pulumi.String("/"),
CheckIntervalSec: pulumi.Int(1),
TimeoutSec: pulumi.Int(1),
})
if err != nil {
return err
}
_, err = compute.NewBackendService(ctx, "default", &compute.BackendServiceArgs{
Name: pulumi.String("backend-service"),
HealthChecks: defaultHttpHealthCheck.ID(),
EnableCdn: pulumi.Bool(true),
CdnPolicy: &compute.BackendServiceCdnPolicyArgs{
SignedUrlCacheMaxAgeSec: pulumi.Int(7200),
},
})
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 defaultHttpHealthCheck = new Gcp.Compute.HttpHealthCheck("default", new()
{
Name = "health-check",
RequestPath = "/",
CheckIntervalSec = 1,
TimeoutSec = 1,
});
var @default = new Gcp.Compute.BackendService("default", new()
{
Name = "backend-service",
HealthChecks = defaultHttpHealthCheck.Id,
EnableCdn = true,
CdnPolicy = new Gcp.Compute.Inputs.BackendServiceCdnPolicyArgs
{
SignedUrlCacheMaxAgeSec = 7200,
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.compute.HttpHealthCheck;
import com.pulumi.gcp.compute.HttpHealthCheckArgs;
import com.pulumi.gcp.compute.BackendService;
import com.pulumi.gcp.compute.BackendServiceArgs;
import com.pulumi.gcp.compute.inputs.BackendServiceCdnPolicyArgs;
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 defaultHttpHealthCheck = new HttpHealthCheck("defaultHttpHealthCheck", HttpHealthCheckArgs.builder()
.name("health-check")
.requestPath("/")
.checkIntervalSec(1)
.timeoutSec(1)
.build());
var default_ = new BackendService("default", BackendServiceArgs.builder()
.name("backend-service")
.healthChecks(defaultHttpHealthCheck.id())
.enableCdn(true)
.cdnPolicy(BackendServiceCdnPolicyArgs.builder()
.signedUrlCacheMaxAgeSec(7200)
.build())
.build());
}
}
resources:
default:
type: gcp:compute:BackendService
properties:
name: backend-service
healthChecks: ${defaultHttpHealthCheck.id}
enableCdn: true
cdnPolicy:
signedUrlCacheMaxAgeSec: 7200
defaultHttpHealthCheck:
type: gcp:compute:HttpHealthCheck
name: default
properties:
name: health-check
requestPath: /
checkIntervalSec: 1
timeoutSec: 1
Setting enableCdn to true activates Cloud CDN. The cdnPolicy block controls caching behavior; signedUrlCacheMaxAgeSec sets how long signed URLs remain valid before requiring regeneration. This configuration uses default cache modes and doesn’t customize cache keys.
Customize cache keys with HTTP headers
APIs that vary responses based on custom headers need cache keys that include those headers to prevent serving incorrect content.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const _default = new gcp.compute.BackendService("default", {
name: "backend-service",
enableCdn: true,
cdnPolicy: {
cacheMode: "USE_ORIGIN_HEADERS",
cacheKeyPolicy: {
includeHost: true,
includeProtocol: true,
includeQueryString: true,
includeHttpHeaders: ["X-My-Header-Field"],
},
},
});
import pulumi
import pulumi_gcp as gcp
default = gcp.compute.BackendService("default",
name="backend-service",
enable_cdn=True,
cdn_policy={
"cache_mode": "USE_ORIGIN_HEADERS",
"cache_key_policy": {
"include_host": True,
"include_protocol": True,
"include_query_string": True,
"include_http_headers": ["X-My-Header-Field"],
},
})
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/compute"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := compute.NewBackendService(ctx, "default", &compute.BackendServiceArgs{
Name: pulumi.String("backend-service"),
EnableCdn: pulumi.Bool(true),
CdnPolicy: &compute.BackendServiceCdnPolicyArgs{
CacheMode: pulumi.String("USE_ORIGIN_HEADERS"),
CacheKeyPolicy: &compute.BackendServiceCdnPolicyCacheKeyPolicyArgs{
IncludeHost: pulumi.Bool(true),
IncludeProtocol: pulumi.Bool(true),
IncludeQueryString: pulumi.Bool(true),
IncludeHttpHeaders: pulumi.StringArray{
pulumi.String("X-My-Header-Field"),
},
},
},
})
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.Compute.BackendService("default", new()
{
Name = "backend-service",
EnableCdn = true,
CdnPolicy = new Gcp.Compute.Inputs.BackendServiceCdnPolicyArgs
{
CacheMode = "USE_ORIGIN_HEADERS",
CacheKeyPolicy = new Gcp.Compute.Inputs.BackendServiceCdnPolicyCacheKeyPolicyArgs
{
IncludeHost = true,
IncludeProtocol = true,
IncludeQueryString = true,
IncludeHttpHeaders = new[]
{
"X-My-Header-Field",
},
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.compute.BackendService;
import com.pulumi.gcp.compute.BackendServiceArgs;
import com.pulumi.gcp.compute.inputs.BackendServiceCdnPolicyArgs;
import com.pulumi.gcp.compute.inputs.BackendServiceCdnPolicyCacheKeyPolicyArgs;
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 BackendService("default", BackendServiceArgs.builder()
.name("backend-service")
.enableCdn(true)
.cdnPolicy(BackendServiceCdnPolicyArgs.builder()
.cacheMode("USE_ORIGIN_HEADERS")
.cacheKeyPolicy(BackendServiceCdnPolicyCacheKeyPolicyArgs.builder()
.includeHost(true)
.includeProtocol(true)
.includeQueryString(true)
.includeHttpHeaders("X-My-Header-Field")
.build())
.build())
.build());
}
}
resources:
default:
type: gcp:compute:BackendService
properties:
name: backend-service
enableCdn: true
cdnPolicy:
cacheMode: USE_ORIGIN_HEADERS
cacheKeyPolicy:
includeHost: true
includeProtocol: true
includeQueryString: true
includeHttpHeaders:
- X-My-Header-Field
The cacheKeyPolicy block controls what factors into cache key calculation. Setting includeHttpHeaders to include “X-My-Header-Field” ensures responses vary by that header’s value. The cacheMode of USE_ORIGIN_HEADERS respects Cache-Control headers from your origin.
Configure comprehensive CDN caching behavior
Production CDN deployments need fine-grained control over TTLs, negative caching, and cache invalidation.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const defaultHttpHealthCheck = new gcp.compute.HttpHealthCheck("default", {
name: "health-check",
requestPath: "/",
checkIntervalSec: 1,
timeoutSec: 1,
});
const _default = new gcp.compute.BackendService("default", {
name: "backend-service",
healthChecks: defaultHttpHealthCheck.id,
enableCdn: true,
cdnPolicy: {
cacheMode: "CACHE_ALL_STATIC",
defaultTtl: 3600,
clientTtl: 7200,
maxTtl: 10800,
negativeCaching: true,
signedUrlCacheMaxAgeSec: 7200,
},
});
import pulumi
import pulumi_gcp as gcp
default_http_health_check = gcp.compute.HttpHealthCheck("default",
name="health-check",
request_path="/",
check_interval_sec=1,
timeout_sec=1)
default = gcp.compute.BackendService("default",
name="backend-service",
health_checks=default_http_health_check.id,
enable_cdn=True,
cdn_policy={
"cache_mode": "CACHE_ALL_STATIC",
"default_ttl": 3600,
"client_ttl": 7200,
"max_ttl": 10800,
"negative_caching": True,
"signed_url_cache_max_age_sec": 7200,
})
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/compute"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
defaultHttpHealthCheck, err := compute.NewHttpHealthCheck(ctx, "default", &compute.HttpHealthCheckArgs{
Name: pulumi.String("health-check"),
RequestPath: pulumi.String("/"),
CheckIntervalSec: pulumi.Int(1),
TimeoutSec: pulumi.Int(1),
})
if err != nil {
return err
}
_, err = compute.NewBackendService(ctx, "default", &compute.BackendServiceArgs{
Name: pulumi.String("backend-service"),
HealthChecks: defaultHttpHealthCheck.ID(),
EnableCdn: pulumi.Bool(true),
CdnPolicy: &compute.BackendServiceCdnPolicyArgs{
CacheMode: pulumi.String("CACHE_ALL_STATIC"),
DefaultTtl: pulumi.Int(3600),
ClientTtl: pulumi.Int(7200),
MaxTtl: pulumi.Int(10800),
NegativeCaching: pulumi.Bool(true),
SignedUrlCacheMaxAgeSec: pulumi.Int(7200),
},
})
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 defaultHttpHealthCheck = new Gcp.Compute.HttpHealthCheck("default", new()
{
Name = "health-check",
RequestPath = "/",
CheckIntervalSec = 1,
TimeoutSec = 1,
});
var @default = new Gcp.Compute.BackendService("default", new()
{
Name = "backend-service",
HealthChecks = defaultHttpHealthCheck.Id,
EnableCdn = true,
CdnPolicy = new Gcp.Compute.Inputs.BackendServiceCdnPolicyArgs
{
CacheMode = "CACHE_ALL_STATIC",
DefaultTtl = 3600,
ClientTtl = 7200,
MaxTtl = 10800,
NegativeCaching = true,
SignedUrlCacheMaxAgeSec = 7200,
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.compute.HttpHealthCheck;
import com.pulumi.gcp.compute.HttpHealthCheckArgs;
import com.pulumi.gcp.compute.BackendService;
import com.pulumi.gcp.compute.BackendServiceArgs;
import com.pulumi.gcp.compute.inputs.BackendServiceCdnPolicyArgs;
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 defaultHttpHealthCheck = new HttpHealthCheck("defaultHttpHealthCheck", HttpHealthCheckArgs.builder()
.name("health-check")
.requestPath("/")
.checkIntervalSec(1)
.timeoutSec(1)
.build());
var default_ = new BackendService("default", BackendServiceArgs.builder()
.name("backend-service")
.healthChecks(defaultHttpHealthCheck.id())
.enableCdn(true)
.cdnPolicy(BackendServiceCdnPolicyArgs.builder()
.cacheMode("CACHE_ALL_STATIC")
.defaultTtl(3600)
.clientTtl(7200)
.maxTtl(10800)
.negativeCaching(true)
.signedUrlCacheMaxAgeSec(7200)
.build())
.build());
}
}
resources:
default:
type: gcp:compute:BackendService
properties:
name: backend-service
healthChecks: ${defaultHttpHealthCheck.id}
enableCdn: true
cdnPolicy:
cacheMode: CACHE_ALL_STATIC
defaultTtl: 3600
clientTtl: 7200
maxTtl: 10800
negativeCaching: true
signedUrlCacheMaxAgeSec: 7200
defaultHttpHealthCheck:
type: gcp:compute:HttpHealthCheck
name: default
properties:
name: health-check
requestPath: /
checkIntervalSec: 1
timeoutSec: 1
The cacheMode of CACHE_ALL_STATIC caches all static content regardless of origin headers. The defaultTtl, clientTtl, and maxTtl properties control how long content stays cached at different layers. Setting negativeCaching to true caches error responses, reducing origin load during failures. This extends the basic CDN example with comprehensive cache control.
Configure consistent hashing for Traffic Director
Service mesh deployments using Traffic Director need consistent hashing to maintain session affinity across backend changes.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const healthCheck = new gcp.compute.HealthCheck("health_check", {
name: "health-check",
httpHealthCheck: {
port: 80,
},
});
const _default = new gcp.compute.BackendService("default", {
name: "backend-service",
healthChecks: healthCheck.id,
loadBalancingScheme: "INTERNAL_SELF_MANAGED",
localityLbPolicy: "RING_HASH",
sessionAffinity: "HTTP_COOKIE",
circuitBreakers: {
maxConnections: 10,
},
consistentHash: {
httpCookie: {
ttl: {
seconds: 11,
nanos: 1111,
},
name: "mycookie",
},
},
outlierDetection: {
consecutiveErrors: 2,
consecutiveGatewayFailure: 5,
enforcingConsecutiveErrors: 100,
enforcingConsecutiveGatewayFailure: 0,
enforcingSuccessRate: 100,
maxEjectionPercent: 10,
successRateMinimumHosts: 5,
successRateRequestVolume: 100,
successRateStdevFactor: 1900,
},
});
import pulumi
import pulumi_gcp as gcp
health_check = gcp.compute.HealthCheck("health_check",
name="health-check",
http_health_check={
"port": 80,
})
default = gcp.compute.BackendService("default",
name="backend-service",
health_checks=health_check.id,
load_balancing_scheme="INTERNAL_SELF_MANAGED",
locality_lb_policy="RING_HASH",
session_affinity="HTTP_COOKIE",
circuit_breakers={
"max_connections": 10,
},
consistent_hash={
"http_cookie": {
"ttl": {
"seconds": 11,
"nanos": 1111,
},
"name": "mycookie",
},
},
outlier_detection={
"consecutive_errors": 2,
"consecutive_gateway_failure": 5,
"enforcing_consecutive_errors": 100,
"enforcing_consecutive_gateway_failure": 0,
"enforcing_success_rate": 100,
"max_ejection_percent": 10,
"success_rate_minimum_hosts": 5,
"success_rate_request_volume": 100,
"success_rate_stdev_factor": 1900,
})
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/compute"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
healthCheck, err := compute.NewHealthCheck(ctx, "health_check", &compute.HealthCheckArgs{
Name: pulumi.String("health-check"),
HttpHealthCheck: &compute.HealthCheckHttpHealthCheckArgs{
Port: pulumi.Int(80),
},
})
if err != nil {
return err
}
_, err = compute.NewBackendService(ctx, "default", &compute.BackendServiceArgs{
Name: pulumi.String("backend-service"),
HealthChecks: healthCheck.ID(),
LoadBalancingScheme: pulumi.String("INTERNAL_SELF_MANAGED"),
LocalityLbPolicy: pulumi.String("RING_HASH"),
SessionAffinity: pulumi.String("HTTP_COOKIE"),
CircuitBreakers: &compute.BackendServiceCircuitBreakersArgs{
MaxConnections: pulumi.Int(10),
},
ConsistentHash: &compute.BackendServiceConsistentHashArgs{
HttpCookie: &compute.BackendServiceConsistentHashHttpCookieArgs{
Ttl: &compute.BackendServiceConsistentHashHttpCookieTtlArgs{
Seconds: pulumi.Int(11),
Nanos: pulumi.Int(1111),
},
Name: pulumi.String("mycookie"),
},
},
OutlierDetection: &compute.BackendServiceOutlierDetectionArgs{
ConsecutiveErrors: pulumi.Int(2),
ConsecutiveGatewayFailure: pulumi.Int(5),
EnforcingConsecutiveErrors: pulumi.Int(100),
EnforcingConsecutiveGatewayFailure: pulumi.Int(0),
EnforcingSuccessRate: pulumi.Int(100),
MaxEjectionPercent: pulumi.Int(10),
SuccessRateMinimumHosts: pulumi.Int(5),
SuccessRateRequestVolume: pulumi.Int(100),
SuccessRateStdevFactor: pulumi.Int(1900),
},
})
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 healthCheck = new Gcp.Compute.HealthCheck("health_check", new()
{
Name = "health-check",
HttpHealthCheck = new Gcp.Compute.Inputs.HealthCheckHttpHealthCheckArgs
{
Port = 80,
},
});
var @default = new Gcp.Compute.BackendService("default", new()
{
Name = "backend-service",
HealthChecks = healthCheck.Id,
LoadBalancingScheme = "INTERNAL_SELF_MANAGED",
LocalityLbPolicy = "RING_HASH",
SessionAffinity = "HTTP_COOKIE",
CircuitBreakers = new Gcp.Compute.Inputs.BackendServiceCircuitBreakersArgs
{
MaxConnections = 10,
},
ConsistentHash = new Gcp.Compute.Inputs.BackendServiceConsistentHashArgs
{
HttpCookie = new Gcp.Compute.Inputs.BackendServiceConsistentHashHttpCookieArgs
{
Ttl = new Gcp.Compute.Inputs.BackendServiceConsistentHashHttpCookieTtlArgs
{
Seconds = 11,
Nanos = 1111,
},
Name = "mycookie",
},
},
OutlierDetection = new Gcp.Compute.Inputs.BackendServiceOutlierDetectionArgs
{
ConsecutiveErrors = 2,
ConsecutiveGatewayFailure = 5,
EnforcingConsecutiveErrors = 100,
EnforcingConsecutiveGatewayFailure = 0,
EnforcingSuccessRate = 100,
MaxEjectionPercent = 10,
SuccessRateMinimumHosts = 5,
SuccessRateRequestVolume = 100,
SuccessRateStdevFactor = 1900,
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.compute.HealthCheck;
import com.pulumi.gcp.compute.HealthCheckArgs;
import com.pulumi.gcp.compute.inputs.HealthCheckHttpHealthCheckArgs;
import com.pulumi.gcp.compute.BackendService;
import com.pulumi.gcp.compute.BackendServiceArgs;
import com.pulumi.gcp.compute.inputs.BackendServiceCircuitBreakersArgs;
import com.pulumi.gcp.compute.inputs.BackendServiceConsistentHashArgs;
import com.pulumi.gcp.compute.inputs.BackendServiceConsistentHashHttpCookieArgs;
import com.pulumi.gcp.compute.inputs.BackendServiceConsistentHashHttpCookieTtlArgs;
import com.pulumi.gcp.compute.inputs.BackendServiceOutlierDetectionArgs;
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 healthCheck = new HealthCheck("healthCheck", HealthCheckArgs.builder()
.name("health-check")
.httpHealthCheck(HealthCheckHttpHealthCheckArgs.builder()
.port(80)
.build())
.build());
var default_ = new BackendService("default", BackendServiceArgs.builder()
.name("backend-service")
.healthChecks(healthCheck.id())
.loadBalancingScheme("INTERNAL_SELF_MANAGED")
.localityLbPolicy("RING_HASH")
.sessionAffinity("HTTP_COOKIE")
.circuitBreakers(BackendServiceCircuitBreakersArgs.builder()
.maxConnections(10)
.build())
.consistentHash(BackendServiceConsistentHashArgs.builder()
.httpCookie(BackendServiceConsistentHashHttpCookieArgs.builder()
.ttl(BackendServiceConsistentHashHttpCookieTtlArgs.builder()
.seconds(11)
.nanos(1111)
.build())
.name("mycookie")
.build())
.build())
.outlierDetection(BackendServiceOutlierDetectionArgs.builder()
.consecutiveErrors(2)
.consecutiveGatewayFailure(5)
.enforcingConsecutiveErrors(100)
.enforcingConsecutiveGatewayFailure(0)
.enforcingSuccessRate(100)
.maxEjectionPercent(10)
.successRateMinimumHosts(5)
.successRateRequestVolume(100)
.successRateStdevFactor(1900)
.build())
.build());
}
}
resources:
default:
type: gcp:compute:BackendService
properties:
name: backend-service
healthChecks: ${healthCheck.id}
loadBalancingScheme: INTERNAL_SELF_MANAGED
localityLbPolicy: RING_HASH
sessionAffinity: HTTP_COOKIE
circuitBreakers:
maxConnections: 10
consistentHash:
httpCookie:
ttl:
seconds: 11
nanos: 1111
name: mycookie
outlierDetection:
consecutiveErrors: 2
consecutiveGatewayFailure: 5
enforcingConsecutiveErrors: 100
enforcingConsecutiveGatewayFailure: 0
enforcingSuccessRate: 100
maxEjectionPercent: 10
successRateMinimumHosts: 5
successRateRequestVolume: 100
successRateStdevFactor: 1900
healthCheck:
type: gcp:compute:HealthCheck
name: health_check
properties:
name: health-check
httpHealthCheck:
port: 80
The loadBalancingScheme of INTERNAL_SELF_MANAGED indicates Traffic Director usage. Setting localityLbPolicy to RING_HASH enables consistent hashing; the consistentHash block defines the hashing algorithm using HTTP cookies. The circuitBreakers property limits connections to prevent overload, while outlierDetection automatically removes unhealthy backends based on error rates.
Maintain stateful sessions with strong cookie affinity
Applications with server-side session state require strong session affinity to route requests from the same client consistently.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const healthCheck = new gcp.compute.HealthCheck("health_check", {
name: "health-check",
httpHealthCheck: {
port: 80,
},
});
const _default = new gcp.compute.BackendService("default", {
name: "backend-service",
healthChecks: healthCheck.id,
loadBalancingScheme: "EXTERNAL_MANAGED",
localityLbPolicy: "RING_HASH",
sessionAffinity: "STRONG_COOKIE_AFFINITY",
strongSessionAffinityCookie: {
ttl: {
seconds: 11,
nanos: 1111,
},
name: "mycookie",
},
});
import pulumi
import pulumi_gcp as gcp
health_check = gcp.compute.HealthCheck("health_check",
name="health-check",
http_health_check={
"port": 80,
})
default = gcp.compute.BackendService("default",
name="backend-service",
health_checks=health_check.id,
load_balancing_scheme="EXTERNAL_MANAGED",
locality_lb_policy="RING_HASH",
session_affinity="STRONG_COOKIE_AFFINITY",
strong_session_affinity_cookie={
"ttl": {
"seconds": 11,
"nanos": 1111,
},
"name": "mycookie",
})
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/compute"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
healthCheck, err := compute.NewHealthCheck(ctx, "health_check", &compute.HealthCheckArgs{
Name: pulumi.String("health-check"),
HttpHealthCheck: &compute.HealthCheckHttpHealthCheckArgs{
Port: pulumi.Int(80),
},
})
if err != nil {
return err
}
_, err = compute.NewBackendService(ctx, "default", &compute.BackendServiceArgs{
Name: pulumi.String("backend-service"),
HealthChecks: healthCheck.ID(),
LoadBalancingScheme: pulumi.String("EXTERNAL_MANAGED"),
LocalityLbPolicy: pulumi.String("RING_HASH"),
SessionAffinity: pulumi.String("STRONG_COOKIE_AFFINITY"),
StrongSessionAffinityCookie: &compute.BackendServiceStrongSessionAffinityCookieArgs{
Ttl: &compute.BackendServiceStrongSessionAffinityCookieTtlArgs{
Seconds: pulumi.Int(11),
Nanos: pulumi.Int(1111),
},
Name: pulumi.String("mycookie"),
},
})
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 healthCheck = new Gcp.Compute.HealthCheck("health_check", new()
{
Name = "health-check",
HttpHealthCheck = new Gcp.Compute.Inputs.HealthCheckHttpHealthCheckArgs
{
Port = 80,
},
});
var @default = new Gcp.Compute.BackendService("default", new()
{
Name = "backend-service",
HealthChecks = healthCheck.Id,
LoadBalancingScheme = "EXTERNAL_MANAGED",
LocalityLbPolicy = "RING_HASH",
SessionAffinity = "STRONG_COOKIE_AFFINITY",
StrongSessionAffinityCookie = new Gcp.Compute.Inputs.BackendServiceStrongSessionAffinityCookieArgs
{
Ttl = new Gcp.Compute.Inputs.BackendServiceStrongSessionAffinityCookieTtlArgs
{
Seconds = 11,
Nanos = 1111,
},
Name = "mycookie",
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.compute.HealthCheck;
import com.pulumi.gcp.compute.HealthCheckArgs;
import com.pulumi.gcp.compute.inputs.HealthCheckHttpHealthCheckArgs;
import com.pulumi.gcp.compute.BackendService;
import com.pulumi.gcp.compute.BackendServiceArgs;
import com.pulumi.gcp.compute.inputs.BackendServiceStrongSessionAffinityCookieArgs;
import com.pulumi.gcp.compute.inputs.BackendServiceStrongSessionAffinityCookieTtlArgs;
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 healthCheck = new HealthCheck("healthCheck", HealthCheckArgs.builder()
.name("health-check")
.httpHealthCheck(HealthCheckHttpHealthCheckArgs.builder()
.port(80)
.build())
.build());
var default_ = new BackendService("default", BackendServiceArgs.builder()
.name("backend-service")
.healthChecks(healthCheck.id())
.loadBalancingScheme("EXTERNAL_MANAGED")
.localityLbPolicy("RING_HASH")
.sessionAffinity("STRONG_COOKIE_AFFINITY")
.strongSessionAffinityCookie(BackendServiceStrongSessionAffinityCookieArgs.builder()
.ttl(BackendServiceStrongSessionAffinityCookieTtlArgs.builder()
.seconds(11)
.nanos(1111)
.build())
.name("mycookie")
.build())
.build());
}
}
resources:
default:
type: gcp:compute:BackendService
properties:
name: backend-service
healthChecks: ${healthCheck.id}
loadBalancingScheme: EXTERNAL_MANAGED
localityLbPolicy: RING_HASH
sessionAffinity: STRONG_COOKIE_AFFINITY
strongSessionAffinityCookie:
ttl:
seconds: 11
nanos: 1111
name: mycookie
healthCheck:
type: gcp:compute:HealthCheck
name: health_check
properties:
name: health-check
httpHealthCheck:
port: 80
Setting sessionAffinity to STRONG_COOKIE_AFFINITY enables stateful session tracking. The strongSessionAffinityCookie block defines the cookie name and TTL. This differs from GENERATED_COOKIE affinity by providing stronger guarantees about routing consistency, suitable for applications that can’t tolerate mid-session backend changes.
Route to external endpoints via network endpoint groups
Hybrid architectures that route traffic to external services use network endpoint groups to integrate non-GCP backends.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const externalProxy = new gcp.compute.GlobalNetworkEndpointGroup("external_proxy", {
name: "network-endpoint",
networkEndpointType: "INTERNET_FQDN_PORT",
defaultPort: 443,
});
const proxy = new gcp.compute.GlobalNetworkEndpoint("proxy", {
globalNetworkEndpointGroup: externalProxy.id,
fqdn: "test.example.com",
port: externalProxy.defaultPort,
});
const _default = new gcp.compute.BackendService("default", {
name: "backend-service",
enableCdn: true,
timeoutSec: 10,
connectionDrainingTimeoutSec: 10,
customRequestHeaders: [proxy.fqdn.apply(fqdn => `host: ${fqdn}`)],
customResponseHeaders: ["X-Cache-Hit: {cdn_cache_status}"],
backends: [{
group: externalProxy.id,
}],
});
import pulumi
import pulumi_gcp as gcp
external_proxy = gcp.compute.GlobalNetworkEndpointGroup("external_proxy",
name="network-endpoint",
network_endpoint_type="INTERNET_FQDN_PORT",
default_port=443)
proxy = gcp.compute.GlobalNetworkEndpoint("proxy",
global_network_endpoint_group=external_proxy.id,
fqdn="test.example.com",
port=external_proxy.default_port)
default = gcp.compute.BackendService("default",
name="backend-service",
enable_cdn=True,
timeout_sec=10,
connection_draining_timeout_sec=10,
custom_request_headers=[proxy.fqdn.apply(lambda fqdn: f"host: {fqdn}")],
custom_response_headers=["X-Cache-Hit: {cdn_cache_status}"],
backends=[{
"group": external_proxy.id,
}])
package main
import (
"fmt"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/compute"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
externalProxy, err := compute.NewGlobalNetworkEndpointGroup(ctx, "external_proxy", &compute.GlobalNetworkEndpointGroupArgs{
Name: pulumi.String("network-endpoint"),
NetworkEndpointType: pulumi.String("INTERNET_FQDN_PORT"),
DefaultPort: pulumi.Int(443),
})
if err != nil {
return err
}
proxy, err := compute.NewGlobalNetworkEndpoint(ctx, "proxy", &compute.GlobalNetworkEndpointArgs{
GlobalNetworkEndpointGroup: externalProxy.ID(),
Fqdn: pulumi.String("test.example.com"),
Port: externalProxy.DefaultPort,
})
if err != nil {
return err
}
_, err = compute.NewBackendService(ctx, "default", &compute.BackendServiceArgs{
Name: pulumi.String("backend-service"),
EnableCdn: pulumi.Bool(true),
TimeoutSec: pulumi.Int(10),
ConnectionDrainingTimeoutSec: pulumi.Int(10),
CustomRequestHeaders: pulumi.StringArray{
proxy.Fqdn.ApplyT(func(fqdn *string) (string, error) {
return fmt.Sprintf("host: %v", fqdn), nil
}).(pulumi.StringOutput),
},
CustomResponseHeaders: pulumi.StringArray{
pulumi.String("X-Cache-Hit: {cdn_cache_status}"),
},
Backends: compute.BackendServiceBackendArray{
&compute.BackendServiceBackendArgs{
Group: externalProxy.ID(),
},
},
})
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 externalProxy = new Gcp.Compute.GlobalNetworkEndpointGroup("external_proxy", new()
{
Name = "network-endpoint",
NetworkEndpointType = "INTERNET_FQDN_PORT",
DefaultPort = 443,
});
var proxy = new Gcp.Compute.GlobalNetworkEndpoint("proxy", new()
{
GlobalNetworkEndpointGroup = externalProxy.Id,
Fqdn = "test.example.com",
Port = externalProxy.DefaultPort,
});
var @default = new Gcp.Compute.BackendService("default", new()
{
Name = "backend-service",
EnableCdn = true,
TimeoutSec = 10,
ConnectionDrainingTimeoutSec = 10,
CustomRequestHeaders = new[]
{
proxy.Fqdn.Apply(fqdn => $"host: {fqdn}"),
},
CustomResponseHeaders = new[]
{
"X-Cache-Hit: {cdn_cache_status}",
},
Backends = new[]
{
new Gcp.Compute.Inputs.BackendServiceBackendArgs
{
Group = externalProxy.Id,
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.compute.GlobalNetworkEndpointGroup;
import com.pulumi.gcp.compute.GlobalNetworkEndpointGroupArgs;
import com.pulumi.gcp.compute.GlobalNetworkEndpoint;
import com.pulumi.gcp.compute.GlobalNetworkEndpointArgs;
import com.pulumi.gcp.compute.BackendService;
import com.pulumi.gcp.compute.BackendServiceArgs;
import com.pulumi.gcp.compute.inputs.BackendServiceBackendArgs;
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 externalProxy = new GlobalNetworkEndpointGroup("externalProxy", GlobalNetworkEndpointGroupArgs.builder()
.name("network-endpoint")
.networkEndpointType("INTERNET_FQDN_PORT")
.defaultPort(443)
.build());
var proxy = new GlobalNetworkEndpoint("proxy", GlobalNetworkEndpointArgs.builder()
.globalNetworkEndpointGroup(externalProxy.id())
.fqdn("test.example.com")
.port(externalProxy.defaultPort())
.build());
var default_ = new BackendService("default", BackendServiceArgs.builder()
.name("backend-service")
.enableCdn(true)
.timeoutSec(10)
.connectionDrainingTimeoutSec(10)
.customRequestHeaders(proxy.fqdn().applyValue(_fqdn -> String.format("host: %s", _fqdn)))
.customResponseHeaders("X-Cache-Hit: {cdn_cache_status}")
.backends(BackendServiceBackendArgs.builder()
.group(externalProxy.id())
.build())
.build());
}
}
resources:
externalProxy:
type: gcp:compute:GlobalNetworkEndpointGroup
name: external_proxy
properties:
name: network-endpoint
networkEndpointType: INTERNET_FQDN_PORT
defaultPort: '443'
proxy:
type: gcp:compute:GlobalNetworkEndpoint
properties:
globalNetworkEndpointGroup: ${externalProxy.id}
fqdn: test.example.com
port: ${externalProxy.defaultPort}
default:
type: gcp:compute:BackendService
properties:
name: backend-service
enableCdn: true
timeoutSec: 10
connectionDrainingTimeoutSec: 10
customRequestHeaders:
- 'host: ${proxy.fqdn}'
customResponseHeaders:
- 'X-Cache-Hit: {cdn_cache_status}'
backends:
- group: ${externalProxy.id}
The GlobalNetworkEndpointGroup with networkEndpointType INTERNET_FQDN_PORT allows routing to external FQDNs. The customRequestHeaders property modifies requests before forwarding; here it sets the Host header to match the backend’s expected value. The customResponseHeaders property adds headers to responses, useful for cache status reporting.
Weight traffic using custom backend metrics
Applications that report custom load metrics can use weighted round-robin to distribute traffic based on actual backend capacity.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const _default = new gcp.compute.Network("default", {name: "network"});
// Zonal NEG with GCE_VM_IP_PORT
const defaultNetworkEndpointGroup = new gcp.compute.NetworkEndpointGroup("default", {
name: "network-endpoint",
network: _default.id,
defaultPort: 90,
zone: "us-central1-a",
networkEndpointType: "GCE_VM_IP_PORT",
});
const defaultHealthCheck = new gcp.compute.HealthCheck("default", {
name: "health-check",
timeoutSec: 1,
checkIntervalSec: 1,
tcpHealthCheck: {
port: 80,
},
});
const defaultBackendService = new gcp.compute.BackendService("default", {
name: "backend-service",
healthChecks: defaultHealthCheck.id,
loadBalancingScheme: "EXTERNAL_MANAGED",
localityLbPolicy: "WEIGHTED_ROUND_ROBIN",
customMetrics: [{
name: "orca.application_utilization",
dryRun: false,
}],
backends: [{
group: defaultNetworkEndpointGroup.id,
balancingMode: "CUSTOM_METRICS",
customMetrics: [
{
name: "orca.cpu_utilization",
maxUtilization: 0.9,
dryRun: true,
},
{
name: "orca.named_metrics.foo",
dryRun: false,
},
],
}],
logConfig: {
enable: true,
optionalMode: "CUSTOM",
optionalFields: [
"orca_load_report",
"tls.protocol",
],
},
});
import pulumi
import pulumi_gcp as gcp
default = gcp.compute.Network("default", name="network")
# Zonal NEG with GCE_VM_IP_PORT
default_network_endpoint_group = gcp.compute.NetworkEndpointGroup("default",
name="network-endpoint",
network=default.id,
default_port=90,
zone="us-central1-a",
network_endpoint_type="GCE_VM_IP_PORT")
default_health_check = gcp.compute.HealthCheck("default",
name="health-check",
timeout_sec=1,
check_interval_sec=1,
tcp_health_check={
"port": 80,
})
default_backend_service = gcp.compute.BackendService("default",
name="backend-service",
health_checks=default_health_check.id,
load_balancing_scheme="EXTERNAL_MANAGED",
locality_lb_policy="WEIGHTED_ROUND_ROBIN",
custom_metrics=[{
"name": "orca.application_utilization",
"dry_run": False,
}],
backends=[{
"group": default_network_endpoint_group.id,
"balancing_mode": "CUSTOM_METRICS",
"custom_metrics": [
{
"name": "orca.cpu_utilization",
"max_utilization": 0.9,
"dry_run": True,
},
{
"name": "orca.named_metrics.foo",
"dry_run": False,
},
],
}],
log_config={
"enable": True,
"optional_mode": "CUSTOM",
"optional_fields": [
"orca_load_report",
"tls.protocol",
],
})
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/compute"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_default, err := compute.NewNetwork(ctx, "default", &compute.NetworkArgs{
Name: pulumi.String("network"),
})
if err != nil {
return err
}
// Zonal NEG with GCE_VM_IP_PORT
defaultNetworkEndpointGroup, err := compute.NewNetworkEndpointGroup(ctx, "default", &compute.NetworkEndpointGroupArgs{
Name: pulumi.String("network-endpoint"),
Network: _default.ID(),
DefaultPort: pulumi.Int(90),
Zone: pulumi.String("us-central1-a"),
NetworkEndpointType: pulumi.String("GCE_VM_IP_PORT"),
})
if err != nil {
return err
}
defaultHealthCheck, err := compute.NewHealthCheck(ctx, "default", &compute.HealthCheckArgs{
Name: pulumi.String("health-check"),
TimeoutSec: pulumi.Int(1),
CheckIntervalSec: pulumi.Int(1),
TcpHealthCheck: &compute.HealthCheckTcpHealthCheckArgs{
Port: pulumi.Int(80),
},
})
if err != nil {
return err
}
_, err = compute.NewBackendService(ctx, "default", &compute.BackendServiceArgs{
Name: pulumi.String("backend-service"),
HealthChecks: defaultHealthCheck.ID(),
LoadBalancingScheme: pulumi.String("EXTERNAL_MANAGED"),
LocalityLbPolicy: pulumi.String("WEIGHTED_ROUND_ROBIN"),
CustomMetrics: compute.BackendServiceCustomMetricArray{
&compute.BackendServiceCustomMetricArgs{
Name: pulumi.String("orca.application_utilization"),
DryRun: pulumi.Bool(false),
},
},
Backends: compute.BackendServiceBackendArray{
&compute.BackendServiceBackendArgs{
Group: defaultNetworkEndpointGroup.ID(),
BalancingMode: pulumi.String("CUSTOM_METRICS"),
CustomMetrics: compute.BackendServiceBackendCustomMetricArray{
&compute.BackendServiceBackendCustomMetricArgs{
Name: pulumi.String("orca.cpu_utilization"),
MaxUtilization: pulumi.Float64(0.9),
DryRun: pulumi.Bool(true),
},
&compute.BackendServiceBackendCustomMetricArgs{
Name: pulumi.String("orca.named_metrics.foo"),
DryRun: pulumi.Bool(false),
},
},
},
},
LogConfig: &compute.BackendServiceLogConfigArgs{
Enable: pulumi.Bool(true),
OptionalMode: pulumi.String("CUSTOM"),
OptionalFields: pulumi.StringArray{
pulumi.String("orca_load_report"),
pulumi.String("tls.protocol"),
},
},
})
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.Compute.Network("default", new()
{
Name = "network",
});
// Zonal NEG with GCE_VM_IP_PORT
var defaultNetworkEndpointGroup = new Gcp.Compute.NetworkEndpointGroup("default", new()
{
Name = "network-endpoint",
Network = @default.Id,
DefaultPort = 90,
Zone = "us-central1-a",
NetworkEndpointType = "GCE_VM_IP_PORT",
});
var defaultHealthCheck = new Gcp.Compute.HealthCheck("default", new()
{
Name = "health-check",
TimeoutSec = 1,
CheckIntervalSec = 1,
TcpHealthCheck = new Gcp.Compute.Inputs.HealthCheckTcpHealthCheckArgs
{
Port = 80,
},
});
var defaultBackendService = new Gcp.Compute.BackendService("default", new()
{
Name = "backend-service",
HealthChecks = defaultHealthCheck.Id,
LoadBalancingScheme = "EXTERNAL_MANAGED",
LocalityLbPolicy = "WEIGHTED_ROUND_ROBIN",
CustomMetrics = new[]
{
new Gcp.Compute.Inputs.BackendServiceCustomMetricArgs
{
Name = "orca.application_utilization",
DryRun = false,
},
},
Backends = new[]
{
new Gcp.Compute.Inputs.BackendServiceBackendArgs
{
Group = defaultNetworkEndpointGroup.Id,
BalancingMode = "CUSTOM_METRICS",
CustomMetrics = new[]
{
new Gcp.Compute.Inputs.BackendServiceBackendCustomMetricArgs
{
Name = "orca.cpu_utilization",
MaxUtilization = 0.9,
DryRun = true,
},
new Gcp.Compute.Inputs.BackendServiceBackendCustomMetricArgs
{
Name = "orca.named_metrics.foo",
DryRun = false,
},
},
},
},
LogConfig = new Gcp.Compute.Inputs.BackendServiceLogConfigArgs
{
Enable = true,
OptionalMode = "CUSTOM",
OptionalFields = new[]
{
"orca_load_report",
"tls.protocol",
},
},
});
});
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.NetworkEndpointGroup;
import com.pulumi.gcp.compute.NetworkEndpointGroupArgs;
import com.pulumi.gcp.compute.HealthCheck;
import com.pulumi.gcp.compute.HealthCheckArgs;
import com.pulumi.gcp.compute.inputs.HealthCheckTcpHealthCheckArgs;
import com.pulumi.gcp.compute.BackendService;
import com.pulumi.gcp.compute.BackendServiceArgs;
import com.pulumi.gcp.compute.inputs.BackendServiceCustomMetricArgs;
import com.pulumi.gcp.compute.inputs.BackendServiceBackendArgs;
import com.pulumi.gcp.compute.inputs.BackendServiceLogConfigArgs;
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 Network("default", NetworkArgs.builder()
.name("network")
.build());
// Zonal NEG with GCE_VM_IP_PORT
var defaultNetworkEndpointGroup = new NetworkEndpointGroup("defaultNetworkEndpointGroup", NetworkEndpointGroupArgs.builder()
.name("network-endpoint")
.network(default_.id())
.defaultPort(90)
.zone("us-central1-a")
.networkEndpointType("GCE_VM_IP_PORT")
.build());
var defaultHealthCheck = new HealthCheck("defaultHealthCheck", HealthCheckArgs.builder()
.name("health-check")
.timeoutSec(1)
.checkIntervalSec(1)
.tcpHealthCheck(HealthCheckTcpHealthCheckArgs.builder()
.port(80)
.build())
.build());
var defaultBackendService = new BackendService("defaultBackendService", BackendServiceArgs.builder()
.name("backend-service")
.healthChecks(defaultHealthCheck.id())
.loadBalancingScheme("EXTERNAL_MANAGED")
.localityLbPolicy("WEIGHTED_ROUND_ROBIN")
.customMetrics(BackendServiceCustomMetricArgs.builder()
.name("orca.application_utilization")
.dryRun(false)
.build())
.backends(BackendServiceBackendArgs.builder()
.group(defaultNetworkEndpointGroup.id())
.balancingMode("CUSTOM_METRICS")
.customMetrics(
BackendServiceBackendCustomMetricArgs.builder()
.name("orca.cpu_utilization")
.maxUtilization(0.9)
.dryRun(true)
.build(),
BackendServiceBackendCustomMetricArgs.builder()
.name("orca.named_metrics.foo")
.dryRun(false)
.build())
.build())
.logConfig(BackendServiceLogConfigArgs.builder()
.enable(true)
.optionalMode("CUSTOM")
.optionalFields(
"orca_load_report",
"tls.protocol")
.build())
.build());
}
}
resources:
default:
type: gcp:compute:Network
properties:
name: network
# Zonal NEG with GCE_VM_IP_PORT
defaultNetworkEndpointGroup:
type: gcp:compute:NetworkEndpointGroup
name: default
properties:
name: network-endpoint
network: ${default.id}
defaultPort: '90'
zone: us-central1-a
networkEndpointType: GCE_VM_IP_PORT
defaultBackendService:
type: gcp:compute:BackendService
name: default
properties:
name: backend-service
healthChecks: ${defaultHealthCheck.id}
loadBalancingScheme: EXTERNAL_MANAGED
localityLbPolicy: WEIGHTED_ROUND_ROBIN
customMetrics:
- name: orca.application_utilization
dryRun: false
backends:
- group: ${defaultNetworkEndpointGroup.id}
balancingMode: CUSTOM_METRICS
customMetrics:
- name: orca.cpu_utilization
maxUtilization: 0.9
dryRun: true
- name: orca.named_metrics.foo
dryRun: false
logConfig:
enable: true
optionalMode: CUSTOM
optionalFields:
- orca_load_report
- tls.protocol
defaultHealthCheck:
type: gcp:compute:HealthCheck
name: default
properties:
name: health-check
timeoutSec: 1
checkIntervalSec: 1
tcpHealthCheck:
port: '80'
Setting localityLbPolicy to WEIGHTED_ROUND_ROBIN enables metric-based weighting. The customMetrics property at both service and backend levels defines which ORCA metrics to use. Backends must report these metrics via the X-Endpoint-Load-Metrics header. The logConfig with optionalMode CUSTOM and optionalFields including “orca_load_report” enables metric visibility in logs.
Beyond these examples
These snippets focus on specific backend service features: health checking and backend routing, Cloud CDN caching and cache key customization, Traffic Director service mesh integration, and session affinity and custom metrics. They’re intentionally minimal rather than full load balancing deployments.
The examples reference pre-existing infrastructure such as compute instance groups or network endpoint groups, health check resources, and VPC networks and subnets for some examples. They focus on configuring the backend service rather than provisioning the complete load balancing stack.
To keep things focused, common backend service patterns are omitted, including:
- Backend configuration (capacity, balancing modes)
- IAP authentication (iap block)
- Security policies and edge security
- Connection draining and timeout tuning
- TLS settings for backend authentication
- Dynamic forwarding with Service Extensions
These omissions are intentional: the goal is to illustrate how each backend service feature is wired, not provide drop-in load balancing modules. See the Backend Service resource reference for all available configuration options.
Let's configure GCP Backend Services for Load Balancing
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Common Errors & Troubleshooting
gcp.compute.URLMap while modifying the number of those dependencies. Use lifecycle.create_before_destroy on the dependent resources to avoid this error.name must be 1-63 characters long, start with a lowercase letter, and match the regex a-z?. It can contain lowercase letters, digits, and dashes, but cannot end with a dash. The name is immutable after creation.Security & Authentication
iap.oauth2_client_secret, iap.oauth2_client_secret_sha256, and security_settings.aws_v4_authentication.access_key are stored in plain text in the Pulumi state file. Ensure your state storage is properly secured.iap.enabled to true and provide oauth2ClientId and oauth2ClientSecret. If OAuth client credentials aren’t specified, the Google-managed OAuth client is used automatically.tlsSettings with sni, subjectAltNames, and authenticationConfig. This is only available when the backend protocol is SSL, HTTPS, or HTTP2.Load Balancing & Traffic Management
loadBalancingScheme determines internal vs external load balancing. Options are EXTERNAL (default, for external load balancing), INTERNAL_SELF_MANAGED (for self-managed internal load balancing), INTERNAL_MANAGED (for managed internal load balancing), and EXTERNAL_MANAGED (for external Application Load Balancer).sessionAffinity to your desired option (default is NONE). Options include CLIENT_IP, GENERATED_COOKIE, HTTP_COOKIE, and STRONG_COOKIE_AFFINITY. If using STRONG_COOKIE_AFFINITY, you must also configure strongSessionAffinityCookie. Session affinity isn’t applicable if the protocol is UDP.ROUND_ROBIN, LEAST_REQUEST, RING_HASH, RANDOM, ORIGINAL_DESTINATION, MAGLEV, WEIGHTED_MAGLEV, and WEIGHTED_ROUND_ROBIN. Availability depends on your loadBalancingScheme and serviceProtocol. Session affinity settings only take effect if localityLbPolicy is MAGLEV, WEIGHTED_MAGLEV, or RING_HASH.externalManagedMigrationState to PREPARE, then TEST_ALL_TRAFFIC (or optionally TEST_BY_PERCENTAGE with externalManagedMigrationTestingPercentage to migrate gradually), then change loadBalancingScheme to EXTERNAL_MANAGED. To roll back, reverse the order of these state changes.Health Checks & Backends
healthChecks unless your backend uses an internet or serverless Network Endpoint Group (NEG). For internal load balancing, use a gcp.compute.HealthCheck resource; for external load balancing, you can use gcp.compute.HttpHealthCheck or gcp.compute.HttpsHealthCheck.portName field is required when loadBalancingScheme is EXTERNAL. The same port name must appear in the instance groups referenced by this backend service.HTTP (default), HTTPS, HTTP2, H2C, TCP, SSL, UDP, GRPC, and UNSPECIFIED. The protocol must be set to GRPC when the backend service is referenced by a URL map bound to a target gRPC proxy.CDN & Caching
enableCdn to true and configure cdnPolicy with your desired cache settings, such as cacheMode, defaultTtl, clientTtl, maxTtl, and cacheKeyPolicy.Advanced Features
circuitBreakers, maxStreamDuration, and consistentHash (when localityLbPolicy is MAGLEV or RING_HASH) are only available when loadBalancingScheme is INTERNAL_SELF_MANAGED.localityLbPolicy to WEIGHTED_ROUND_ROBIN and configure customMetrics at both the backend service and backend levels. Backend responses must include the X-Endpoint-Load-Metrics header with the metrics specified in backends[].customMetrics.timeoutSec is 30 seconds, with a range from 1 to 2,147,483,647 seconds. The timeout meaning varies depending on the type of load balancer.Using a different cloud?
Explore networking guides for other cloud providers: