The gcp:dns/recordSet:RecordSet resource, part of the Pulumi GCP provider, defines DNS records within a Cloud DNS managed zone: hostname mappings, mail routing, and traffic steering policies. This guide focuses on three capabilities: standard record types (A, MX, CNAME), dynamic IP binding from compute resources, and geographic and failover routing.
Record sets belong to managed zones and may reference compute instances, load balancers, or networks for dynamic values and routing policies. The examples are intentionally small. Combine them with your own managed zones and infrastructure.
Add an A record with static IP addresses
Most DNS configurations start with A records that map hostnames to IPv4 addresses, directing traffic to servers or load balancers.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const prod = new gcp.dns.ManagedZone("prod", {
name: "prod-zone",
dnsName: "prod.mydomain.com.",
});
const a = new gcp.dns.RecordSet("a", {
name: pulumi.interpolate`backend.${prod.dnsName}`,
managedZone: prod.name,
type: "A",
ttl: 300,
rrdatas: ["8.8.8.8"],
});
import pulumi
import pulumi_gcp as gcp
prod = gcp.dns.ManagedZone("prod",
name="prod-zone",
dns_name="prod.mydomain.com.")
a = gcp.dns.RecordSet("a",
name=prod.dns_name.apply(lambda dns_name: f"backend.{dns_name}"),
managed_zone=prod.name,
type="A",
ttl=300,
rrdatas=["8.8.8.8"])
package main
import (
"fmt"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/dns"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
prod, err := dns.NewManagedZone(ctx, "prod", &dns.ManagedZoneArgs{
Name: pulumi.String("prod-zone"),
DnsName: pulumi.String("prod.mydomain.com."),
})
if err != nil {
return err
}
_, err = dns.NewRecordSet(ctx, "a", &dns.RecordSetArgs{
Name: prod.DnsName.ApplyT(func(dnsName string) (string, error) {
return fmt.Sprintf("backend.%v", dnsName), nil
}).(pulumi.StringOutput),
ManagedZone: prod.Name,
Type: pulumi.String("A"),
Ttl: pulumi.Int(300),
Rrdatas: pulumi.StringArray{
pulumi.String("8.8.8.8"),
},
})
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 prod = new Gcp.Dns.ManagedZone("prod", new()
{
Name = "prod-zone",
DnsName = "prod.mydomain.com.",
});
var a = new Gcp.Dns.RecordSet("a", new()
{
Name = prod.DnsName.Apply(dnsName => $"backend.{dnsName}"),
ManagedZone = prod.Name,
Type = "A",
Ttl = 300,
Rrdatas = new[]
{
"8.8.8.8",
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.dns.ManagedZone;
import com.pulumi.gcp.dns.ManagedZoneArgs;
import com.pulumi.gcp.dns.RecordSet;
import com.pulumi.gcp.dns.RecordSetArgs;
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 prod = new ManagedZone("prod", ManagedZoneArgs.builder()
.name("prod-zone")
.dnsName("prod.mydomain.com.")
.build());
var a = new RecordSet("a", RecordSetArgs.builder()
.name(prod.dnsName().applyValue(_dnsName -> String.format("backend.%s", _dnsName)))
.managedZone(prod.name())
.type("A")
.ttl(300)
.rrdatas("8.8.8.8")
.build());
}
}
resources:
a:
type: gcp:dns:RecordSet
properties:
name: backend.${prod.dnsName}
managedZone: ${prod.name}
type: A
ttl: 300
rrdatas:
- 8.8.8.8
prod:
type: gcp:dns:ManagedZone
properties:
name: prod-zone
dnsName: prod.mydomain.com.
The name property sets the fully qualified domain name (must end with a dot). The rrdatas array contains one or more IPv4 addresses. The ttl property controls how long resolvers cache this record (in seconds).
Configure mail routing with MX records
Email delivery requires MX records that specify mail servers and their priority order, with lower values indicating preferred servers.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const prod = new gcp.dns.ManagedZone("prod", {
name: "prod-zone",
dnsName: "prod.mydomain.com.",
});
const mx = new gcp.dns.RecordSet("mx", {
name: prod.dnsName,
managedZone: prod.name,
type: "MX",
ttl: 3600,
rrdatas: [
"1 aspmx.l.google.com.",
"5 alt1.aspmx.l.google.com.",
"5 alt2.aspmx.l.google.com.",
"10 alt3.aspmx.l.google.com.",
"10 alt4.aspmx.l.google.com.",
],
});
import pulumi
import pulumi_gcp as gcp
prod = gcp.dns.ManagedZone("prod",
name="prod-zone",
dns_name="prod.mydomain.com.")
mx = gcp.dns.RecordSet("mx",
name=prod.dns_name,
managed_zone=prod.name,
type="MX",
ttl=3600,
rrdatas=[
"1 aspmx.l.google.com.",
"5 alt1.aspmx.l.google.com.",
"5 alt2.aspmx.l.google.com.",
"10 alt3.aspmx.l.google.com.",
"10 alt4.aspmx.l.google.com.",
])
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/dns"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
prod, err := dns.NewManagedZone(ctx, "prod", &dns.ManagedZoneArgs{
Name: pulumi.String("prod-zone"),
DnsName: pulumi.String("prod.mydomain.com."),
})
if err != nil {
return err
}
_, err = dns.NewRecordSet(ctx, "mx", &dns.RecordSetArgs{
Name: prod.DnsName,
ManagedZone: prod.Name,
Type: pulumi.String("MX"),
Ttl: pulumi.Int(3600),
Rrdatas: pulumi.StringArray{
pulumi.String("1 aspmx.l.google.com."),
pulumi.String("5 alt1.aspmx.l.google.com."),
pulumi.String("5 alt2.aspmx.l.google.com."),
pulumi.String("10 alt3.aspmx.l.google.com."),
pulumi.String("10 alt4.aspmx.l.google.com."),
},
})
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 prod = new Gcp.Dns.ManagedZone("prod", new()
{
Name = "prod-zone",
DnsName = "prod.mydomain.com.",
});
var mx = new Gcp.Dns.RecordSet("mx", new()
{
Name = prod.DnsName,
ManagedZone = prod.Name,
Type = "MX",
Ttl = 3600,
Rrdatas = new[]
{
"1 aspmx.l.google.com.",
"5 alt1.aspmx.l.google.com.",
"5 alt2.aspmx.l.google.com.",
"10 alt3.aspmx.l.google.com.",
"10 alt4.aspmx.l.google.com.",
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.dns.ManagedZone;
import com.pulumi.gcp.dns.ManagedZoneArgs;
import com.pulumi.gcp.dns.RecordSet;
import com.pulumi.gcp.dns.RecordSetArgs;
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 prod = new ManagedZone("prod", ManagedZoneArgs.builder()
.name("prod-zone")
.dnsName("prod.mydomain.com.")
.build());
var mx = new RecordSet("mx", RecordSetArgs.builder()
.name(prod.dnsName())
.managedZone(prod.name())
.type("MX")
.ttl(3600)
.rrdatas(
"1 aspmx.l.google.com.",
"5 alt1.aspmx.l.google.com.",
"5 alt2.aspmx.l.google.com.",
"10 alt3.aspmx.l.google.com.",
"10 alt4.aspmx.l.google.com.")
.build());
}
}
resources:
mx:
type: gcp:dns:RecordSet
properties:
name: ${prod.dnsName}
managedZone: ${prod.name}
type: MX
ttl: 3600
rrdatas:
- 1 aspmx.l.google.com.
- 5 alt1.aspmx.l.google.com.
- 5 alt2.aspmx.l.google.com.
- 10 alt3.aspmx.l.google.com.
- 10 alt4.aspmx.l.google.com.
prod:
type: gcp:dns:ManagedZone
properties:
name: prod-zone
dnsName: prod.mydomain.com.
MX records use the rrdatas array to list mail servers with priority prefixes (e.g., “1 aspmx.l.google.com.”). Mail servers try the lowest priority first, falling back to higher values if delivery fails.
Create aliases with CNAME records
CNAME records create aliases that point one hostname to another, useful for service endpoints or CDN configurations.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const prod = new gcp.dns.ManagedZone("prod", {
name: "prod-zone",
dnsName: "prod.mydomain.com.",
});
const cname = new gcp.dns.RecordSet("cname", {
name: pulumi.interpolate`frontend.${prod.dnsName}`,
managedZone: prod.name,
type: "CNAME",
ttl: 300,
rrdatas: ["frontend.mydomain.com."],
});
import pulumi
import pulumi_gcp as gcp
prod = gcp.dns.ManagedZone("prod",
name="prod-zone",
dns_name="prod.mydomain.com.")
cname = gcp.dns.RecordSet("cname",
name=prod.dns_name.apply(lambda dns_name: f"frontend.{dns_name}"),
managed_zone=prod.name,
type="CNAME",
ttl=300,
rrdatas=["frontend.mydomain.com."])
package main
import (
"fmt"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/dns"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
prod, err := dns.NewManagedZone(ctx, "prod", &dns.ManagedZoneArgs{
Name: pulumi.String("prod-zone"),
DnsName: pulumi.String("prod.mydomain.com."),
})
if err != nil {
return err
}
_, err = dns.NewRecordSet(ctx, "cname", &dns.RecordSetArgs{
Name: prod.DnsName.ApplyT(func(dnsName string) (string, error) {
return fmt.Sprintf("frontend.%v", dnsName), nil
}).(pulumi.StringOutput),
ManagedZone: prod.Name,
Type: pulumi.String("CNAME"),
Ttl: pulumi.Int(300),
Rrdatas: pulumi.StringArray{
pulumi.String("frontend.mydomain.com."),
},
})
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 prod = new Gcp.Dns.ManagedZone("prod", new()
{
Name = "prod-zone",
DnsName = "prod.mydomain.com.",
});
var cname = new Gcp.Dns.RecordSet("cname", new()
{
Name = prod.DnsName.Apply(dnsName => $"frontend.{dnsName}"),
ManagedZone = prod.Name,
Type = "CNAME",
Ttl = 300,
Rrdatas = new[]
{
"frontend.mydomain.com.",
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.dns.ManagedZone;
import com.pulumi.gcp.dns.ManagedZoneArgs;
import com.pulumi.gcp.dns.RecordSet;
import com.pulumi.gcp.dns.RecordSetArgs;
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 prod = new ManagedZone("prod", ManagedZoneArgs.builder()
.name("prod-zone")
.dnsName("prod.mydomain.com.")
.build());
var cname = new RecordSet("cname", RecordSetArgs.builder()
.name(prod.dnsName().applyValue(_dnsName -> String.format("frontend.%s", _dnsName)))
.managedZone(prod.name())
.type("CNAME")
.ttl(300)
.rrdatas("frontend.mydomain.com.")
.build());
}
}
resources:
cname:
type: gcp:dns:RecordSet
properties:
name: frontend.${prod.dnsName}
managedZone: ${prod.name}
type: CNAME
ttl: 300
rrdatas:
- frontend.mydomain.com.
prod:
type: gcp:dns:ManagedZone
properties:
name: prod-zone
dnsName: prod.mydomain.com.
CNAME records require exactly one entry in rrdatas: the canonical hostname. The type property must be “CNAME”, and the target hostname must end with a dot.
Bind DNS to dynamically assigned instance IPs
When launching compute instances, their public IPs are assigned at creation time. DNS records can reference these dynamic values using Pulumi’s interpolation.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const frontendInstance = new gcp.compute.Instance("frontend", {
networkInterfaces: [{
accessConfigs: [{}],
network: "default",
}],
name: "frontend",
machineType: "g1-small",
zone: "us-central1-b",
bootDisk: {
initializeParams: {
image: "debian-cloud/debian-11",
},
},
});
const prod = new gcp.dns.ManagedZone("prod", {
name: "prod-zone",
dnsName: "prod.mydomain.com.",
});
const frontend = new gcp.dns.RecordSet("frontend", {
name: pulumi.interpolate`frontend.${prod.dnsName}`,
type: "A",
ttl: 300,
managedZone: prod.name,
rrdatas: [frontendInstance.networkInterfaces.apply(networkInterfaces => networkInterfaces[0].accessConfigs?.[0]?.natIp)],
});
import pulumi
import pulumi_gcp as gcp
frontend_instance = gcp.compute.Instance("frontend",
network_interfaces=[{
"access_configs": [{}],
"network": "default",
}],
name="frontend",
machine_type="g1-small",
zone="us-central1-b",
boot_disk={
"initialize_params": {
"image": "debian-cloud/debian-11",
},
})
prod = gcp.dns.ManagedZone("prod",
name="prod-zone",
dns_name="prod.mydomain.com.")
frontend = gcp.dns.RecordSet("frontend",
name=prod.dns_name.apply(lambda dns_name: f"frontend.{dns_name}"),
type="A",
ttl=300,
managed_zone=prod.name,
rrdatas=[frontend_instance.network_interfaces[0].access_configs[0].nat_ip])
package main
import (
"fmt"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/compute"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/dns"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
frontendInstance, err := compute.NewInstance(ctx, "frontend", &compute.InstanceArgs{
NetworkInterfaces: compute.InstanceNetworkInterfaceArray{
&compute.InstanceNetworkInterfaceArgs{
AccessConfigs: compute.InstanceNetworkInterfaceAccessConfigArray{
&compute.InstanceNetworkInterfaceAccessConfigArgs{},
},
Network: pulumi.String("default"),
},
},
Name: pulumi.String("frontend"),
MachineType: pulumi.String("g1-small"),
Zone: pulumi.String("us-central1-b"),
BootDisk: &compute.InstanceBootDiskArgs{
InitializeParams: &compute.InstanceBootDiskInitializeParamsArgs{
Image: pulumi.String("debian-cloud/debian-11"),
},
},
})
if err != nil {
return err
}
prod, err := dns.NewManagedZone(ctx, "prod", &dns.ManagedZoneArgs{
Name: pulumi.String("prod-zone"),
DnsName: pulumi.String("prod.mydomain.com."),
})
if err != nil {
return err
}
_, err = dns.NewRecordSet(ctx, "frontend", &dns.RecordSetArgs{
Name: prod.DnsName.ApplyT(func(dnsName string) (string, error) {
return fmt.Sprintf("frontend.%v", dnsName), nil
}).(pulumi.StringOutput),
Type: pulumi.String("A"),
Ttl: pulumi.Int(300),
ManagedZone: prod.Name,
Rrdatas: pulumi.StringArray{
pulumi.String(frontendInstance.NetworkInterfaces.ApplyT(func(networkInterfaces []compute.InstanceNetworkInterface) (*string, error) {
return &networkInterfaces[0].AccessConfigs[0].NatIp, nil
}).(pulumi.StringPtrOutput)),
},
})
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 frontendInstance = new Gcp.Compute.Instance("frontend", new()
{
NetworkInterfaces = new[]
{
new Gcp.Compute.Inputs.InstanceNetworkInterfaceArgs
{
AccessConfigs = new[]
{
null,
},
Network = "default",
},
},
Name = "frontend",
MachineType = "g1-small",
Zone = "us-central1-b",
BootDisk = new Gcp.Compute.Inputs.InstanceBootDiskArgs
{
InitializeParams = new Gcp.Compute.Inputs.InstanceBootDiskInitializeParamsArgs
{
Image = "debian-cloud/debian-11",
},
},
});
var prod = new Gcp.Dns.ManagedZone("prod", new()
{
Name = "prod-zone",
DnsName = "prod.mydomain.com.",
});
var frontend = new Gcp.Dns.RecordSet("frontend", new()
{
Name = prod.DnsName.Apply(dnsName => $"frontend.{dnsName}"),
Type = "A",
Ttl = 300,
ManagedZone = prod.Name,
Rrdatas = new[]
{
frontendInstance.NetworkInterfaces.Apply(networkInterfaces => networkInterfaces[0].AccessConfigs[0]?.NatIp),
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.compute.Instance;
import com.pulumi.gcp.compute.InstanceArgs;
import com.pulumi.gcp.compute.inputs.InstanceNetworkInterfaceArgs;
import com.pulumi.gcp.compute.inputs.InstanceBootDiskArgs;
import com.pulumi.gcp.compute.inputs.InstanceBootDiskInitializeParamsArgs;
import com.pulumi.gcp.dns.ManagedZone;
import com.pulumi.gcp.dns.ManagedZoneArgs;
import com.pulumi.gcp.dns.RecordSet;
import com.pulumi.gcp.dns.RecordSetArgs;
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 frontendInstance = new Instance("frontendInstance", InstanceArgs.builder()
.networkInterfaces(InstanceNetworkInterfaceArgs.builder()
.accessConfigs(InstanceNetworkInterfaceAccessConfigArgs.builder()
.build())
.network("default")
.build())
.name("frontend")
.machineType("g1-small")
.zone("us-central1-b")
.bootDisk(InstanceBootDiskArgs.builder()
.initializeParams(InstanceBootDiskInitializeParamsArgs.builder()
.image("debian-cloud/debian-11")
.build())
.build())
.build());
var prod = new ManagedZone("prod", ManagedZoneArgs.builder()
.name("prod-zone")
.dnsName("prod.mydomain.com.")
.build());
var frontend = new RecordSet("frontend", RecordSetArgs.builder()
.name(prod.dnsName().applyValue(_dnsName -> String.format("frontend.%s", _dnsName)))
.type("A")
.ttl(300)
.managedZone(prod.name())
.rrdatas(frontendInstance.networkInterfaces().applyValue(_networkInterfaces -> _networkInterfaces[0].accessConfigs()[0].natIp()))
.build());
}
}
resources:
frontend:
type: gcp:dns:RecordSet
properties:
name: frontend.${prod.dnsName}
type: A
ttl: 300
managedZone: ${prod.name}
rrdatas:
- ${frontendInstance.networkInterfaces[0].accessConfigs[0].natIp}
frontendInstance:
type: gcp:compute:Instance
name: frontend
properties:
networkInterfaces:
- accessConfigs:
- {}
network: default
name: frontend
machineType: g1-small
zone: us-central1-b
bootDisk:
initializeParams:
image: debian-cloud/debian-11
prod:
type: gcp:dns:ManagedZone
properties:
name: prod-zone
dnsName: prod.mydomain.com.
The rrdatas array references the instance’s natIp from its network interface configuration. Pulumi resolves this value at deployment time, creating the DNS record after the instance receives its IP address.
Route traffic by geographic location
Applications serving global users can direct traffic to regional endpoints based on the client’s geographic location, reducing latency.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const geo = new gcp.dns.RecordSet("geo", {
name: `backend.${prod.dnsName}`,
managedZone: prod.name,
type: "A",
ttl: 300,
routingPolicy: {
geos: [
{
location: "asia-east1",
rrdatas: ["10.128.1.1"],
},
{
location: "us-central1",
rrdatas: ["10.130.1.1"],
},
],
},
});
import pulumi
import pulumi_gcp as gcp
geo = gcp.dns.RecordSet("geo",
name=f"backend.{prod['dnsName']}",
managed_zone=prod["name"],
type="A",
ttl=300,
routing_policy={
"geos": [
{
"location": "asia-east1",
"rrdatas": ["10.128.1.1"],
},
{
"location": "us-central1",
"rrdatas": ["10.130.1.1"],
},
],
})
package main
import (
"fmt"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/dns"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := dns.NewRecordSet(ctx, "geo", &dns.RecordSetArgs{
Name: pulumi.Sprintf("backend.%v", prod.DnsName),
ManagedZone: pulumi.Any(prod.Name),
Type: pulumi.String("A"),
Ttl: pulumi.Int(300),
RoutingPolicy: &dns.RecordSetRoutingPolicyArgs{
Geos: dns.RecordSetRoutingPolicyGeoArray{
&dns.RecordSetRoutingPolicyGeoArgs{
Location: pulumi.String("asia-east1"),
Rrdatas: pulumi.StringArray{
pulumi.String("10.128.1.1"),
},
},
&dns.RecordSetRoutingPolicyGeoArgs{
Location: pulumi.String("us-central1"),
Rrdatas: pulumi.StringArray{
pulumi.String("10.130.1.1"),
},
},
},
},
})
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 geo = new Gcp.Dns.RecordSet("geo", new()
{
Name = $"backend.{prod.DnsName}",
ManagedZone = prod.Name,
Type = "A",
Ttl = 300,
RoutingPolicy = new Gcp.Dns.Inputs.RecordSetRoutingPolicyArgs
{
Geos = new[]
{
new Gcp.Dns.Inputs.RecordSetRoutingPolicyGeoArgs
{
Location = "asia-east1",
Rrdatas = new[]
{
"10.128.1.1",
},
},
new Gcp.Dns.Inputs.RecordSetRoutingPolicyGeoArgs
{
Location = "us-central1",
Rrdatas = new[]
{
"10.130.1.1",
},
},
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.dns.RecordSet;
import com.pulumi.gcp.dns.RecordSetArgs;
import com.pulumi.gcp.dns.inputs.RecordSetRoutingPolicyArgs;
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 geo = new RecordSet("geo", RecordSetArgs.builder()
.name(String.format("backend.%s", prod.dnsName()))
.managedZone(prod.name())
.type("A")
.ttl(300)
.routingPolicy(RecordSetRoutingPolicyArgs.builder()
.geos(
RecordSetRoutingPolicyGeoArgs.builder()
.location("asia-east1")
.rrdatas("10.128.1.1")
.build(),
RecordSetRoutingPolicyGeoArgs.builder()
.location("us-central1")
.rrdatas("10.130.1.1")
.build())
.build())
.build());
}
}
resources:
geo:
type: gcp:dns:RecordSet
properties:
name: backend.${prod.dnsName}
managedZone: ${prod.name}
type: A
ttl: 300
routingPolicy:
geos:
- location: asia-east1
rrdatas:
- 10.128.1.1
- location: us-central1
rrdatas:
- 10.130.1.1
The routingPolicy property replaces rrdatas for advanced traffic steering. The geos array maps GCP regions to IP addresses. Cloud DNS returns the IP closest to the query origin.
Configure failover with primary and backup targets
High-availability architectures need automatic failover to backup endpoints when primary targets become unavailable.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const prod = new gcp.dns.ManagedZone("prod", {
name: "prod-zone",
dnsName: "prod.mydomain.com.",
visibility: "private",
});
const prodRegionBackendService = new gcp.compute.RegionBackendService("prod", {
name: "prod-backend",
region: "us-central1",
});
const prodNetwork = new gcp.compute.Network("prod", {name: "prod-network"});
const prodForwardingRule = new gcp.compute.ForwardingRule("prod", {
name: "prod-ilb",
region: "us-central1",
loadBalancingScheme: "INTERNAL",
backendService: prodRegionBackendService.id,
allPorts: true,
network: prodNetwork.name,
allowGlobalAccess: true,
});
const a = new gcp.dns.RecordSet("a", {
name: pulumi.interpolate`backend.${prod.dnsName}`,
managedZone: prod.name,
type: "A",
ttl: 300,
routingPolicy: {
primaryBackup: {
trickleRatio: 0.1,
primary: {
internalLoadBalancers: [{
loadBalancerType: "regionalL4ilb",
ipAddress: prodForwardingRule.ipAddress,
port: "80",
ipProtocol: "tcp",
networkUrl: prodNetwork.id,
project: prodForwardingRule.project,
region: prodForwardingRule.region,
}],
},
backupGeos: [
{
location: "asia-east1",
rrdatas: ["10.128.1.1"],
},
{
location: "us-west1",
rrdatas: ["10.130.1.1"],
},
],
},
},
});
import pulumi
import pulumi_gcp as gcp
prod = gcp.dns.ManagedZone("prod",
name="prod-zone",
dns_name="prod.mydomain.com.",
visibility="private")
prod_region_backend_service = gcp.compute.RegionBackendService("prod",
name="prod-backend",
region="us-central1")
prod_network = gcp.compute.Network("prod", name="prod-network")
prod_forwarding_rule = gcp.compute.ForwardingRule("prod",
name="prod-ilb",
region="us-central1",
load_balancing_scheme="INTERNAL",
backend_service=prod_region_backend_service.id,
all_ports=True,
network=prod_network.name,
allow_global_access=True)
a = gcp.dns.RecordSet("a",
name=prod.dns_name.apply(lambda dns_name: f"backend.{dns_name}"),
managed_zone=prod.name,
type="A",
ttl=300,
routing_policy={
"primary_backup": {
"trickle_ratio": 0.1,
"primary": {
"internal_load_balancers": [{
"load_balancer_type": "regionalL4ilb",
"ip_address": prod_forwarding_rule.ip_address,
"port": "80",
"ip_protocol": "tcp",
"network_url": prod_network.id,
"project": prod_forwarding_rule.project,
"region": prod_forwarding_rule.region,
}],
},
"backup_geos": [
{
"location": "asia-east1",
"rrdatas": ["10.128.1.1"],
},
{
"location": "us-west1",
"rrdatas": ["10.130.1.1"],
},
],
},
})
package main
import (
"fmt"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/compute"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/dns"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
prod, err := dns.NewManagedZone(ctx, "prod", &dns.ManagedZoneArgs{
Name: pulumi.String("prod-zone"),
DnsName: pulumi.String("prod.mydomain.com."),
Visibility: pulumi.String("private"),
})
if err != nil {
return err
}
prodRegionBackendService, err := compute.NewRegionBackendService(ctx, "prod", &compute.RegionBackendServiceArgs{
Name: pulumi.String("prod-backend"),
Region: pulumi.String("us-central1"),
})
if err != nil {
return err
}
prodNetwork, err := compute.NewNetwork(ctx, "prod", &compute.NetworkArgs{
Name: pulumi.String("prod-network"),
})
if err != nil {
return err
}
prodForwardingRule, err := compute.NewForwardingRule(ctx, "prod", &compute.ForwardingRuleArgs{
Name: pulumi.String("prod-ilb"),
Region: pulumi.String("us-central1"),
LoadBalancingScheme: pulumi.String("INTERNAL"),
BackendService: prodRegionBackendService.ID(),
AllPorts: pulumi.Bool(true),
Network: prodNetwork.Name,
AllowGlobalAccess: pulumi.Bool(true),
})
if err != nil {
return err
}
_, err = dns.NewRecordSet(ctx, "a", &dns.RecordSetArgs{
Name: prod.DnsName.ApplyT(func(dnsName string) (string, error) {
return fmt.Sprintf("backend.%v", dnsName), nil
}).(pulumi.StringOutput),
ManagedZone: prod.Name,
Type: pulumi.String("A"),
Ttl: pulumi.Int(300),
RoutingPolicy: &dns.RecordSetRoutingPolicyArgs{
PrimaryBackup: &dns.RecordSetRoutingPolicyPrimaryBackupArgs{
TrickleRatio: pulumi.Float64(0.1),
Primary: &dns.RecordSetRoutingPolicyPrimaryBackupPrimaryArgs{
InternalLoadBalancers: dns.RecordSetRoutingPolicyPrimaryBackupPrimaryInternalLoadBalancerArray{
&dns.RecordSetRoutingPolicyPrimaryBackupPrimaryInternalLoadBalancerArgs{
LoadBalancerType: pulumi.String("regionalL4ilb"),
IpAddress: prodForwardingRule.IpAddress,
Port: pulumi.String("80"),
IpProtocol: pulumi.String("tcp"),
NetworkUrl: prodNetwork.ID(),
Project: prodForwardingRule.Project,
Region: prodForwardingRule.Region,
},
},
},
BackupGeos: dns.RecordSetRoutingPolicyPrimaryBackupBackupGeoArray{
&dns.RecordSetRoutingPolicyPrimaryBackupBackupGeoArgs{
Location: pulumi.String("asia-east1"),
Rrdatas: pulumi.StringArray{
pulumi.String("10.128.1.1"),
},
},
&dns.RecordSetRoutingPolicyPrimaryBackupBackupGeoArgs{
Location: pulumi.String("us-west1"),
Rrdatas: pulumi.StringArray{
pulumi.String("10.130.1.1"),
},
},
},
},
},
})
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 prod = new Gcp.Dns.ManagedZone("prod", new()
{
Name = "prod-zone",
DnsName = "prod.mydomain.com.",
Visibility = "private",
});
var prodRegionBackendService = new Gcp.Compute.RegionBackendService("prod", new()
{
Name = "prod-backend",
Region = "us-central1",
});
var prodNetwork = new Gcp.Compute.Network("prod", new()
{
Name = "prod-network",
});
var prodForwardingRule = new Gcp.Compute.ForwardingRule("prod", new()
{
Name = "prod-ilb",
Region = "us-central1",
LoadBalancingScheme = "INTERNAL",
BackendService = prodRegionBackendService.Id,
AllPorts = true,
Network = prodNetwork.Name,
AllowGlobalAccess = true,
});
var a = new Gcp.Dns.RecordSet("a", new()
{
Name = prod.DnsName.Apply(dnsName => $"backend.{dnsName}"),
ManagedZone = prod.Name,
Type = "A",
Ttl = 300,
RoutingPolicy = new Gcp.Dns.Inputs.RecordSetRoutingPolicyArgs
{
PrimaryBackup = new Gcp.Dns.Inputs.RecordSetRoutingPolicyPrimaryBackupArgs
{
TrickleRatio = 0.1,
Primary = new Gcp.Dns.Inputs.RecordSetRoutingPolicyPrimaryBackupPrimaryArgs
{
InternalLoadBalancers = new[]
{
new Gcp.Dns.Inputs.RecordSetRoutingPolicyPrimaryBackupPrimaryInternalLoadBalancerArgs
{
LoadBalancerType = "regionalL4ilb",
IpAddress = prodForwardingRule.IpAddress,
Port = "80",
IpProtocol = "tcp",
NetworkUrl = prodNetwork.Id,
Project = prodForwardingRule.Project,
Region = prodForwardingRule.Region,
},
},
},
BackupGeos = new[]
{
new Gcp.Dns.Inputs.RecordSetRoutingPolicyPrimaryBackupBackupGeoArgs
{
Location = "asia-east1",
Rrdatas = new[]
{
"10.128.1.1",
},
},
new Gcp.Dns.Inputs.RecordSetRoutingPolicyPrimaryBackupBackupGeoArgs
{
Location = "us-west1",
Rrdatas = new[]
{
"10.130.1.1",
},
},
},
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.dns.ManagedZone;
import com.pulumi.gcp.dns.ManagedZoneArgs;
import com.pulumi.gcp.compute.RegionBackendService;
import com.pulumi.gcp.compute.RegionBackendServiceArgs;
import com.pulumi.gcp.compute.Network;
import com.pulumi.gcp.compute.NetworkArgs;
import com.pulumi.gcp.compute.ForwardingRule;
import com.pulumi.gcp.compute.ForwardingRuleArgs;
import com.pulumi.gcp.dns.RecordSet;
import com.pulumi.gcp.dns.RecordSetArgs;
import com.pulumi.gcp.dns.inputs.RecordSetRoutingPolicyArgs;
import com.pulumi.gcp.dns.inputs.RecordSetRoutingPolicyPrimaryBackupArgs;
import com.pulumi.gcp.dns.inputs.RecordSetRoutingPolicyPrimaryBackupPrimaryArgs;
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 prod = new ManagedZone("prod", ManagedZoneArgs.builder()
.name("prod-zone")
.dnsName("prod.mydomain.com.")
.visibility("private")
.build());
var prodRegionBackendService = new RegionBackendService("prodRegionBackendService", RegionBackendServiceArgs.builder()
.name("prod-backend")
.region("us-central1")
.build());
var prodNetwork = new Network("prodNetwork", NetworkArgs.builder()
.name("prod-network")
.build());
var prodForwardingRule = new ForwardingRule("prodForwardingRule", ForwardingRuleArgs.builder()
.name("prod-ilb")
.region("us-central1")
.loadBalancingScheme("INTERNAL")
.backendService(prodRegionBackendService.id())
.allPorts(true)
.network(prodNetwork.name())
.allowGlobalAccess(true)
.build());
var a = new RecordSet("a", RecordSetArgs.builder()
.name(prod.dnsName().applyValue(_dnsName -> String.format("backend.%s", _dnsName)))
.managedZone(prod.name())
.type("A")
.ttl(300)
.routingPolicy(RecordSetRoutingPolicyArgs.builder()
.primaryBackup(RecordSetRoutingPolicyPrimaryBackupArgs.builder()
.trickleRatio(0.1)
.primary(RecordSetRoutingPolicyPrimaryBackupPrimaryArgs.builder()
.internalLoadBalancers(RecordSetRoutingPolicyPrimaryBackupPrimaryInternalLoadBalancerArgs.builder()
.loadBalancerType("regionalL4ilb")
.ipAddress(prodForwardingRule.ipAddress())
.port("80")
.ipProtocol("tcp")
.networkUrl(prodNetwork.id())
.project(prodForwardingRule.project())
.region(prodForwardingRule.region())
.build())
.build())
.backupGeos(
RecordSetRoutingPolicyPrimaryBackupBackupGeoArgs.builder()
.location("asia-east1")
.rrdatas("10.128.1.1")
.build(),
RecordSetRoutingPolicyPrimaryBackupBackupGeoArgs.builder()
.location("us-west1")
.rrdatas("10.130.1.1")
.build())
.build())
.build())
.build());
}
}
resources:
a:
type: gcp:dns:RecordSet
properties:
name: backend.${prod.dnsName}
managedZone: ${prod.name}
type: A
ttl: 300
routingPolicy:
primaryBackup:
trickleRatio: 0.1
primary:
internalLoadBalancers:
- loadBalancerType: regionalL4ilb
ipAddress: ${prodForwardingRule.ipAddress}
port: '80'
ipProtocol: tcp
networkUrl: ${prodNetwork.id}
project: ${prodForwardingRule.project}
region: ${prodForwardingRule.region}
backupGeos:
- location: asia-east1
rrdatas:
- 10.128.1.1
- location: us-west1
rrdatas:
- 10.130.1.1
prod:
type: gcp:dns:ManagedZone
properties:
name: prod-zone
dnsName: prod.mydomain.com.
visibility: private
prodForwardingRule:
type: gcp:compute:ForwardingRule
name: prod
properties:
name: prod-ilb
region: us-central1
loadBalancingScheme: INTERNAL
backendService: ${prodRegionBackendService.id}
allPorts: true
network: ${prodNetwork.name}
allowGlobalAccess: true
prodRegionBackendService:
type: gcp:compute:RegionBackendService
name: prod
properties:
name: prod-backend
region: us-central1
prodNetwork:
type: gcp:compute:Network
name: prod
properties:
name: prod-network
The primaryBackup configuration defines a primary target (here, an internal load balancer) and backup geographic endpoints. The trickleRatio controls what percentage of traffic goes to backups even when the primary is healthy, enabling gradual failover testing.
Beyond these examples
These snippets focus on specific record set features: standard record types (A, MX, CNAME, TXT), dynamic IP binding from compute resources, and geographic and failover routing policies. They’re intentionally minimal rather than full DNS configurations.
The examples may reference pre-existing infrastructure such as Cloud DNS managed zones, and compute instances, load balancers, and networks for dynamic binding. They focus on configuring the record set rather than provisioning the surrounding DNS infrastructure.
To keep things focused, common record set patterns are omitted, including:
- SPF record quoting requirements (TXT records need escaped quotes)
- Health check integration with routing policies
- Weighted round-robin routing (WRR)
- Public zone failover with external endpoints
These omissions are intentional: the goal is to illustrate how each record set feature is wired, not provide drop-in DNS modules. See the DNS RecordSet resource reference for all available configuration options.
Let's create GCP DNS Record Sets
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Record Configuration & Types
rrdatas value to prevent the string from being split on spaces. Wrap the entire SPF value in escaped quotes: ["\"v=spf1 ip4:111.111.111.111 include:example.com -all\""].rrdatas array corresponding to the canonical name. Multiple entries aren’t supported for CNAME records.type property accepts standard DNS record types including A, AAAA, CNAME, MX, TXT, and others. Examples in the schema demonstrate A, MX, TXT (for SPF), and CNAME records.Routing & Traffic Management
rrdatas for simple static DNS records with fixed IP addresses or values. Use routingPolicy for advanced traffic steering like geolocation-based routing, weighted round robin, or failover configurations.routingPolicy.geos with an array of locations and their corresponding rrdatas. Each entry specifies a location (like asia-east1 or us-central1) and the IP addresses to return for queries from that region.routingPolicy.primaryBackup with a primary target (either internalLoadBalancers or externalEndpoints) and backupGeos for failover locations. You can also specify a trickleRatio to gradually shift traffic.healthCheck ID in the routingPolicy to monitor endpoint health. The public zone failover example shows using a health check with primaryBackup routing and healthCheckedTargets in backup geos.Resource Management
managedZone, name, and project properties are immutable and cannot be changed after creation. You’ll need to delete and recreate the record set to modify these values.example.com. not example.com). The examples also show names with trailing dots when using zone DNS names.Using a different cloud?
Explore networking guides for other cloud providers: