The gcp:gkebackup/backupPlan:BackupPlan resource, part of the Pulumi GCP provider, defines a GKE backup plan that controls what gets backed up, when backups run, and how long they’re retained. This guide focuses on four capabilities: namespace and application selection, customer-managed encryption, automated scheduling and retention, and RPO targets with exclusion windows.
Backup plans require GKE clusters with the Backup for GKE addon enabled and may reference Cloud KMS keys for encryption. The examples are intentionally small. Combine them with your own cluster configuration and retention requirements.
Back up all namespaces with volume data
Most GKE backup deployments start with a plan that captures all cluster namespaces, including persistent volume data and secrets.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const primary = new gcp.container.Cluster("primary", {
name: "basic-cluster",
location: "us-central1",
initialNodeCount: 1,
workloadIdentityConfig: {
workloadPool: "my-project-name.svc.id.goog",
},
addonsConfig: {
gkeBackupAgentConfig: {
enabled: true,
},
},
deletionProtection: true,
network: "default",
subnetwork: "default",
});
const basic = new gcp.gkebackup.BackupPlan("basic", {
name: "basic-plan",
cluster: primary.id,
location: "us-central1",
backupConfig: {
includeVolumeData: true,
includeSecrets: true,
allNamespaces: true,
},
});
import pulumi
import pulumi_gcp as gcp
primary = gcp.container.Cluster("primary",
name="basic-cluster",
location="us-central1",
initial_node_count=1,
workload_identity_config={
"workload_pool": "my-project-name.svc.id.goog",
},
addons_config={
"gke_backup_agent_config": {
"enabled": True,
},
},
deletion_protection=True,
network="default",
subnetwork="default")
basic = gcp.gkebackup.BackupPlan("basic",
name="basic-plan",
cluster=primary.id,
location="us-central1",
backup_config={
"include_volume_data": True,
"include_secrets": True,
"all_namespaces": True,
})
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/container"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/gkebackup"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
primary, err := container.NewCluster(ctx, "primary", &container.ClusterArgs{
Name: pulumi.String("basic-cluster"),
Location: pulumi.String("us-central1"),
InitialNodeCount: pulumi.Int(1),
WorkloadIdentityConfig: &container.ClusterWorkloadIdentityConfigArgs{
WorkloadPool: pulumi.String("my-project-name.svc.id.goog"),
},
AddonsConfig: &container.ClusterAddonsConfigArgs{
GkeBackupAgentConfig: &container.ClusterAddonsConfigGkeBackupAgentConfigArgs{
Enabled: pulumi.Bool(true),
},
},
DeletionProtection: pulumi.Bool(true),
Network: pulumi.String("default"),
Subnetwork: pulumi.String("default"),
})
if err != nil {
return err
}
_, err = gkebackup.NewBackupPlan(ctx, "basic", &gkebackup.BackupPlanArgs{
Name: pulumi.String("basic-plan"),
Cluster: primary.ID(),
Location: pulumi.String("us-central1"),
BackupConfig: &gkebackup.BackupPlanBackupConfigArgs{
IncludeVolumeData: pulumi.Bool(true),
IncludeSecrets: pulumi.Bool(true),
AllNamespaces: pulumi.Bool(true),
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;
return await Deployment.RunAsync(() =>
{
var primary = new Gcp.Container.Cluster("primary", new()
{
Name = "basic-cluster",
Location = "us-central1",
InitialNodeCount = 1,
WorkloadIdentityConfig = new Gcp.Container.Inputs.ClusterWorkloadIdentityConfigArgs
{
WorkloadPool = "my-project-name.svc.id.goog",
},
AddonsConfig = new Gcp.Container.Inputs.ClusterAddonsConfigArgs
{
GkeBackupAgentConfig = new Gcp.Container.Inputs.ClusterAddonsConfigGkeBackupAgentConfigArgs
{
Enabled = true,
},
},
DeletionProtection = true,
Network = "default",
Subnetwork = "default",
});
var basic = new Gcp.GkeBackup.BackupPlan("basic", new()
{
Name = "basic-plan",
Cluster = primary.Id,
Location = "us-central1",
BackupConfig = new Gcp.GkeBackup.Inputs.BackupPlanBackupConfigArgs
{
IncludeVolumeData = true,
IncludeSecrets = true,
AllNamespaces = true,
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.container.Cluster;
import com.pulumi.gcp.container.ClusterArgs;
import com.pulumi.gcp.container.inputs.ClusterWorkloadIdentityConfigArgs;
import com.pulumi.gcp.container.inputs.ClusterAddonsConfigArgs;
import com.pulumi.gcp.container.inputs.ClusterAddonsConfigGkeBackupAgentConfigArgs;
import com.pulumi.gcp.gkebackup.BackupPlan;
import com.pulumi.gcp.gkebackup.BackupPlanArgs;
import com.pulumi.gcp.gkebackup.inputs.BackupPlanBackupConfigArgs;
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 primary = new Cluster("primary", ClusterArgs.builder()
.name("basic-cluster")
.location("us-central1")
.initialNodeCount(1)
.workloadIdentityConfig(ClusterWorkloadIdentityConfigArgs.builder()
.workloadPool("my-project-name.svc.id.goog")
.build())
.addonsConfig(ClusterAddonsConfigArgs.builder()
.gkeBackupAgentConfig(ClusterAddonsConfigGkeBackupAgentConfigArgs.builder()
.enabled(true)
.build())
.build())
.deletionProtection(true)
.network("default")
.subnetwork("default")
.build());
var basic = new BackupPlan("basic", BackupPlanArgs.builder()
.name("basic-plan")
.cluster(primary.id())
.location("us-central1")
.backupConfig(BackupPlanBackupConfigArgs.builder()
.includeVolumeData(true)
.includeSecrets(true)
.allNamespaces(true)
.build())
.build());
}
}
resources:
primary:
type: gcp:container:Cluster
properties:
name: basic-cluster
location: us-central1
initialNodeCount: 1
workloadIdentityConfig:
workloadPool: my-project-name.svc.id.goog
addonsConfig:
gkeBackupAgentConfig:
enabled: true
deletionProtection: true
network: default
subnetwork: default
basic:
type: gcp:gkebackup:BackupPlan
properties:
name: basic-plan
cluster: ${primary.id}
location: us-central1
backupConfig:
includeVolumeData: true
includeSecrets: true
allNamespaces: true
The backupConfig property defines what gets included in each backup. Setting allNamespaces to true captures every namespace in the cluster. The includeVolumeData and includeSecrets flags control whether persistent volumes and Kubernetes secrets are included in the backup snapshot.
Encrypt backups with customer-managed keys
Organizations with compliance requirements often need to control encryption keys for backup data rather than relying on Google-managed encryption.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const primary = new gcp.container.Cluster("primary", {
name: "cmek-cluster",
location: "us-central1",
initialNodeCount: 1,
workloadIdentityConfig: {
workloadPool: "my-project-name.svc.id.goog",
},
addonsConfig: {
gkeBackupAgentConfig: {
enabled: true,
},
},
deletionProtection: true,
network: "default",
subnetwork: "default",
});
const keyRing = new gcp.kms.KeyRing("key_ring", {
name: "backup-key",
location: "us-central1",
});
const cryptoKey = new gcp.kms.CryptoKey("crypto_key", {
name: "backup-key",
keyRing: keyRing.id,
});
const cmek = new gcp.gkebackup.BackupPlan("cmek", {
name: "cmek-plan",
cluster: primary.id,
location: "us-central1",
backupConfig: {
includeVolumeData: true,
includeSecrets: true,
selectedNamespaces: {
namespaces: [
"default",
"test",
],
},
encryptionKey: {
gcpKmsEncryptionKey: cryptoKey.id,
},
},
});
import pulumi
import pulumi_gcp as gcp
primary = gcp.container.Cluster("primary",
name="cmek-cluster",
location="us-central1",
initial_node_count=1,
workload_identity_config={
"workload_pool": "my-project-name.svc.id.goog",
},
addons_config={
"gke_backup_agent_config": {
"enabled": True,
},
},
deletion_protection=True,
network="default",
subnetwork="default")
key_ring = gcp.kms.KeyRing("key_ring",
name="backup-key",
location="us-central1")
crypto_key = gcp.kms.CryptoKey("crypto_key",
name="backup-key",
key_ring=key_ring.id)
cmek = gcp.gkebackup.BackupPlan("cmek",
name="cmek-plan",
cluster=primary.id,
location="us-central1",
backup_config={
"include_volume_data": True,
"include_secrets": True,
"selected_namespaces": {
"namespaces": [
"default",
"test",
],
},
"encryption_key": {
"gcp_kms_encryption_key": crypto_key.id,
},
})
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/container"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/gkebackup"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/kms"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
primary, err := container.NewCluster(ctx, "primary", &container.ClusterArgs{
Name: pulumi.String("cmek-cluster"),
Location: pulumi.String("us-central1"),
InitialNodeCount: pulumi.Int(1),
WorkloadIdentityConfig: &container.ClusterWorkloadIdentityConfigArgs{
WorkloadPool: pulumi.String("my-project-name.svc.id.goog"),
},
AddonsConfig: &container.ClusterAddonsConfigArgs{
GkeBackupAgentConfig: &container.ClusterAddonsConfigGkeBackupAgentConfigArgs{
Enabled: pulumi.Bool(true),
},
},
DeletionProtection: pulumi.Bool(true),
Network: pulumi.String("default"),
Subnetwork: pulumi.String("default"),
})
if err != nil {
return err
}
keyRing, err := kms.NewKeyRing(ctx, "key_ring", &kms.KeyRingArgs{
Name: pulumi.String("backup-key"),
Location: pulumi.String("us-central1"),
})
if err != nil {
return err
}
cryptoKey, err := kms.NewCryptoKey(ctx, "crypto_key", &kms.CryptoKeyArgs{
Name: pulumi.String("backup-key"),
KeyRing: keyRing.ID(),
})
if err != nil {
return err
}
_, err = gkebackup.NewBackupPlan(ctx, "cmek", &gkebackup.BackupPlanArgs{
Name: pulumi.String("cmek-plan"),
Cluster: primary.ID(),
Location: pulumi.String("us-central1"),
BackupConfig: &gkebackup.BackupPlanBackupConfigArgs{
IncludeVolumeData: pulumi.Bool(true),
IncludeSecrets: pulumi.Bool(true),
SelectedNamespaces: &gkebackup.BackupPlanBackupConfigSelectedNamespacesArgs{
Namespaces: pulumi.StringArray{
pulumi.String("default"),
pulumi.String("test"),
},
},
EncryptionKey: &gkebackup.BackupPlanBackupConfigEncryptionKeyArgs{
GcpKmsEncryptionKey: cryptoKey.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 primary = new Gcp.Container.Cluster("primary", new()
{
Name = "cmek-cluster",
Location = "us-central1",
InitialNodeCount = 1,
WorkloadIdentityConfig = new Gcp.Container.Inputs.ClusterWorkloadIdentityConfigArgs
{
WorkloadPool = "my-project-name.svc.id.goog",
},
AddonsConfig = new Gcp.Container.Inputs.ClusterAddonsConfigArgs
{
GkeBackupAgentConfig = new Gcp.Container.Inputs.ClusterAddonsConfigGkeBackupAgentConfigArgs
{
Enabled = true,
},
},
DeletionProtection = true,
Network = "default",
Subnetwork = "default",
});
var keyRing = new Gcp.Kms.KeyRing("key_ring", new()
{
Name = "backup-key",
Location = "us-central1",
});
var cryptoKey = new Gcp.Kms.CryptoKey("crypto_key", new()
{
Name = "backup-key",
KeyRing = keyRing.Id,
});
var cmek = new Gcp.GkeBackup.BackupPlan("cmek", new()
{
Name = "cmek-plan",
Cluster = primary.Id,
Location = "us-central1",
BackupConfig = new Gcp.GkeBackup.Inputs.BackupPlanBackupConfigArgs
{
IncludeVolumeData = true,
IncludeSecrets = true,
SelectedNamespaces = new Gcp.GkeBackup.Inputs.BackupPlanBackupConfigSelectedNamespacesArgs
{
Namespaces = new[]
{
"default",
"test",
},
},
EncryptionKey = new Gcp.GkeBackup.Inputs.BackupPlanBackupConfigEncryptionKeyArgs
{
GcpKmsEncryptionKey = cryptoKey.Id,
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.container.Cluster;
import com.pulumi.gcp.container.ClusterArgs;
import com.pulumi.gcp.container.inputs.ClusterWorkloadIdentityConfigArgs;
import com.pulumi.gcp.container.inputs.ClusterAddonsConfigArgs;
import com.pulumi.gcp.container.inputs.ClusterAddonsConfigGkeBackupAgentConfigArgs;
import com.pulumi.gcp.kms.KeyRing;
import com.pulumi.gcp.kms.KeyRingArgs;
import com.pulumi.gcp.kms.CryptoKey;
import com.pulumi.gcp.kms.CryptoKeyArgs;
import com.pulumi.gcp.gkebackup.BackupPlan;
import com.pulumi.gcp.gkebackup.BackupPlanArgs;
import com.pulumi.gcp.gkebackup.inputs.BackupPlanBackupConfigArgs;
import com.pulumi.gcp.gkebackup.inputs.BackupPlanBackupConfigSelectedNamespacesArgs;
import com.pulumi.gcp.gkebackup.inputs.BackupPlanBackupConfigEncryptionKeyArgs;
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 primary = new Cluster("primary", ClusterArgs.builder()
.name("cmek-cluster")
.location("us-central1")
.initialNodeCount(1)
.workloadIdentityConfig(ClusterWorkloadIdentityConfigArgs.builder()
.workloadPool("my-project-name.svc.id.goog")
.build())
.addonsConfig(ClusterAddonsConfigArgs.builder()
.gkeBackupAgentConfig(ClusterAddonsConfigGkeBackupAgentConfigArgs.builder()
.enabled(true)
.build())
.build())
.deletionProtection(true)
.network("default")
.subnetwork("default")
.build());
var keyRing = new KeyRing("keyRing", KeyRingArgs.builder()
.name("backup-key")
.location("us-central1")
.build());
var cryptoKey = new CryptoKey("cryptoKey", CryptoKeyArgs.builder()
.name("backup-key")
.keyRing(keyRing.id())
.build());
var cmek = new BackupPlan("cmek", BackupPlanArgs.builder()
.name("cmek-plan")
.cluster(primary.id())
.location("us-central1")
.backupConfig(BackupPlanBackupConfigArgs.builder()
.includeVolumeData(true)
.includeSecrets(true)
.selectedNamespaces(BackupPlanBackupConfigSelectedNamespacesArgs.builder()
.namespaces(
"default",
"test")
.build())
.encryptionKey(BackupPlanBackupConfigEncryptionKeyArgs.builder()
.gcpKmsEncryptionKey(cryptoKey.id())
.build())
.build())
.build());
}
}
resources:
primary:
type: gcp:container:Cluster
properties:
name: cmek-cluster
location: us-central1
initialNodeCount: 1
workloadIdentityConfig:
workloadPool: my-project-name.svc.id.goog
addonsConfig:
gkeBackupAgentConfig:
enabled: true
deletionProtection: true
network: default
subnetwork: default
cmek:
type: gcp:gkebackup:BackupPlan
properties:
name: cmek-plan
cluster: ${primary.id}
location: us-central1
backupConfig:
includeVolumeData: true
includeSecrets: true
selectedNamespaces:
namespaces:
- default
- test
encryptionKey:
gcpKmsEncryptionKey: ${cryptoKey.id}
cryptoKey:
type: gcp:kms:CryptoKey
name: crypto_key
properties:
name: backup-key
keyRing: ${keyRing.id}
keyRing:
type: gcp:kms:KeyRing
name: key_ring
properties:
name: backup-key
location: us-central1
The encryptionKey property points to a Cloud KMS CryptoKey that encrypts backup data at rest. Instead of allNamespaces, this configuration uses selectedNamespaces to back up only the “default” and “test” namespaces. The backup service account needs the cryptoKeyEncrypterDecrypter role on the specified key.
Filter namespaces by label selectors
Teams managing multi-tenant clusters often organize workloads with namespace labels, allowing backup plans to target specific environments or teams.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const primary = new gcp.container.Cluster("primary", {
name: "nslabels-cluster",
location: "us-central1",
initialNodeCount: 1,
workloadIdentityConfig: {
workloadPool: "my-project-name.svc.id.goog",
},
addonsConfig: {
gkeBackupAgentConfig: {
enabled: true,
},
},
deletionProtection: true,
network: "default",
subnetwork: "default",
});
const nslabels = new gcp.gkebackup.BackupPlan("nslabels", {
name: "nslabels-plan",
cluster: primary.id,
location: "us-central1",
backupConfig: {
includeVolumeData: true,
includeSecrets: true,
selectedNamespaceLabels: {
resourceLabels: [{
key: "key1",
value: "value1",
}],
},
},
});
import pulumi
import pulumi_gcp as gcp
primary = gcp.container.Cluster("primary",
name="nslabels-cluster",
location="us-central1",
initial_node_count=1,
workload_identity_config={
"workload_pool": "my-project-name.svc.id.goog",
},
addons_config={
"gke_backup_agent_config": {
"enabled": True,
},
},
deletion_protection=True,
network="default",
subnetwork="default")
nslabels = gcp.gkebackup.BackupPlan("nslabels",
name="nslabels-plan",
cluster=primary.id,
location="us-central1",
backup_config={
"include_volume_data": True,
"include_secrets": True,
"selected_namespace_labels": {
"resource_labels": [{
"key": "key1",
"value": "value1",
}],
},
})
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/container"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/gkebackup"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
primary, err := container.NewCluster(ctx, "primary", &container.ClusterArgs{
Name: pulumi.String("nslabels-cluster"),
Location: pulumi.String("us-central1"),
InitialNodeCount: pulumi.Int(1),
WorkloadIdentityConfig: &container.ClusterWorkloadIdentityConfigArgs{
WorkloadPool: pulumi.String("my-project-name.svc.id.goog"),
},
AddonsConfig: &container.ClusterAddonsConfigArgs{
GkeBackupAgentConfig: &container.ClusterAddonsConfigGkeBackupAgentConfigArgs{
Enabled: pulumi.Bool(true),
},
},
DeletionProtection: pulumi.Bool(true),
Network: pulumi.String("default"),
Subnetwork: pulumi.String("default"),
})
if err != nil {
return err
}
_, err = gkebackup.NewBackupPlan(ctx, "nslabels", &gkebackup.BackupPlanArgs{
Name: pulumi.String("nslabels-plan"),
Cluster: primary.ID(),
Location: pulumi.String("us-central1"),
BackupConfig: &gkebackup.BackupPlanBackupConfigArgs{
IncludeVolumeData: pulumi.Bool(true),
IncludeSecrets: pulumi.Bool(true),
SelectedNamespaceLabels: &gkebackup.BackupPlanBackupConfigSelectedNamespaceLabelsArgs{
ResourceLabels: gkebackup.BackupPlanBackupConfigSelectedNamespaceLabelsResourceLabelArray{
&gkebackup.BackupPlanBackupConfigSelectedNamespaceLabelsResourceLabelArgs{
Key: pulumi.String("key1"),
Value: pulumi.String("value1"),
},
},
},
},
})
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 primary = new Gcp.Container.Cluster("primary", new()
{
Name = "nslabels-cluster",
Location = "us-central1",
InitialNodeCount = 1,
WorkloadIdentityConfig = new Gcp.Container.Inputs.ClusterWorkloadIdentityConfigArgs
{
WorkloadPool = "my-project-name.svc.id.goog",
},
AddonsConfig = new Gcp.Container.Inputs.ClusterAddonsConfigArgs
{
GkeBackupAgentConfig = new Gcp.Container.Inputs.ClusterAddonsConfigGkeBackupAgentConfigArgs
{
Enabled = true,
},
},
DeletionProtection = true,
Network = "default",
Subnetwork = "default",
});
var nslabels = new Gcp.GkeBackup.BackupPlan("nslabels", new()
{
Name = "nslabels-plan",
Cluster = primary.Id,
Location = "us-central1",
BackupConfig = new Gcp.GkeBackup.Inputs.BackupPlanBackupConfigArgs
{
IncludeVolumeData = true,
IncludeSecrets = true,
SelectedNamespaceLabels = new Gcp.GkeBackup.Inputs.BackupPlanBackupConfigSelectedNamespaceLabelsArgs
{
ResourceLabels = new[]
{
new Gcp.GkeBackup.Inputs.BackupPlanBackupConfigSelectedNamespaceLabelsResourceLabelArgs
{
Key = "key1",
Value = "value1",
},
},
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.container.Cluster;
import com.pulumi.gcp.container.ClusterArgs;
import com.pulumi.gcp.container.inputs.ClusterWorkloadIdentityConfigArgs;
import com.pulumi.gcp.container.inputs.ClusterAddonsConfigArgs;
import com.pulumi.gcp.container.inputs.ClusterAddonsConfigGkeBackupAgentConfigArgs;
import com.pulumi.gcp.gkebackup.BackupPlan;
import com.pulumi.gcp.gkebackup.BackupPlanArgs;
import com.pulumi.gcp.gkebackup.inputs.BackupPlanBackupConfigArgs;
import com.pulumi.gcp.gkebackup.inputs.BackupPlanBackupConfigSelectedNamespaceLabelsArgs;
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 primary = new Cluster("primary", ClusterArgs.builder()
.name("nslabels-cluster")
.location("us-central1")
.initialNodeCount(1)
.workloadIdentityConfig(ClusterWorkloadIdentityConfigArgs.builder()
.workloadPool("my-project-name.svc.id.goog")
.build())
.addonsConfig(ClusterAddonsConfigArgs.builder()
.gkeBackupAgentConfig(ClusterAddonsConfigGkeBackupAgentConfigArgs.builder()
.enabled(true)
.build())
.build())
.deletionProtection(true)
.network("default")
.subnetwork("default")
.build());
var nslabels = new BackupPlan("nslabels", BackupPlanArgs.builder()
.name("nslabels-plan")
.cluster(primary.id())
.location("us-central1")
.backupConfig(BackupPlanBackupConfigArgs.builder()
.includeVolumeData(true)
.includeSecrets(true)
.selectedNamespaceLabels(BackupPlanBackupConfigSelectedNamespaceLabelsArgs.builder()
.resourceLabels(BackupPlanBackupConfigSelectedNamespaceLabelsResourceLabelArgs.builder()
.key("key1")
.value("value1")
.build())
.build())
.build())
.build());
}
}
resources:
primary:
type: gcp:container:Cluster
properties:
name: nslabels-cluster
location: us-central1
initialNodeCount: 1
workloadIdentityConfig:
workloadPool: my-project-name.svc.id.goog
addonsConfig:
gkeBackupAgentConfig:
enabled: true
deletionProtection: true
network: default
subnetwork: default
nslabels:
type: gcp:gkebackup:BackupPlan
properties:
name: nslabels-plan
cluster: ${primary.id}
location: us-central1
backupConfig:
includeVolumeData: true
includeSecrets: true
selectedNamespaceLabels:
resourceLabels:
- key: key1
value: value1
The selectedNamespaceLabels property filters namespaces by label criteria. Only namespaces with matching resourceLabels are included in backups. This approach works well when you organize workloads by environment (dev, staging, prod) or team ownership using namespace labels.
Schedule backups with retention policies
Production environments typically automate backup creation on a schedule and enforce retention rules to balance recovery needs with storage costs.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const primary = new gcp.container.Cluster("primary", {
name: "full-cluster",
location: "us-central1",
initialNodeCount: 1,
workloadIdentityConfig: {
workloadPool: "my-project-name.svc.id.goog",
},
addonsConfig: {
gkeBackupAgentConfig: {
enabled: true,
},
},
deletionProtection: true,
network: "default",
subnetwork: "default",
});
const full = new gcp.gkebackup.BackupPlan("full", {
name: "full-plan",
cluster: primary.id,
location: "us-central1",
retentionPolicy: {
backupDeleteLockDays: 30,
backupRetainDays: 180,
},
backupSchedule: {
cronSchedule: "0 9 * * 1",
},
backupConfig: {
includeVolumeData: true,
includeSecrets: true,
selectedApplications: {
namespacedNames: [
{
name: "app1",
namespace: "ns1",
},
{
name: "app2",
namespace: "ns2",
},
],
},
},
});
import pulumi
import pulumi_gcp as gcp
primary = gcp.container.Cluster("primary",
name="full-cluster",
location="us-central1",
initial_node_count=1,
workload_identity_config={
"workload_pool": "my-project-name.svc.id.goog",
},
addons_config={
"gke_backup_agent_config": {
"enabled": True,
},
},
deletion_protection=True,
network="default",
subnetwork="default")
full = gcp.gkebackup.BackupPlan("full",
name="full-plan",
cluster=primary.id,
location="us-central1",
retention_policy={
"backup_delete_lock_days": 30,
"backup_retain_days": 180,
},
backup_schedule={
"cron_schedule": "0 9 * * 1",
},
backup_config={
"include_volume_data": True,
"include_secrets": True,
"selected_applications": {
"namespaced_names": [
{
"name": "app1",
"namespace": "ns1",
},
{
"name": "app2",
"namespace": "ns2",
},
],
},
})
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/container"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/gkebackup"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
primary, err := container.NewCluster(ctx, "primary", &container.ClusterArgs{
Name: pulumi.String("full-cluster"),
Location: pulumi.String("us-central1"),
InitialNodeCount: pulumi.Int(1),
WorkloadIdentityConfig: &container.ClusterWorkloadIdentityConfigArgs{
WorkloadPool: pulumi.String("my-project-name.svc.id.goog"),
},
AddonsConfig: &container.ClusterAddonsConfigArgs{
GkeBackupAgentConfig: &container.ClusterAddonsConfigGkeBackupAgentConfigArgs{
Enabled: pulumi.Bool(true),
},
},
DeletionProtection: pulumi.Bool(true),
Network: pulumi.String("default"),
Subnetwork: pulumi.String("default"),
})
if err != nil {
return err
}
_, err = gkebackup.NewBackupPlan(ctx, "full", &gkebackup.BackupPlanArgs{
Name: pulumi.String("full-plan"),
Cluster: primary.ID(),
Location: pulumi.String("us-central1"),
RetentionPolicy: &gkebackup.BackupPlanRetentionPolicyArgs{
BackupDeleteLockDays: pulumi.Int(30),
BackupRetainDays: pulumi.Int(180),
},
BackupSchedule: &gkebackup.BackupPlanBackupScheduleArgs{
CronSchedule: pulumi.String("0 9 * * 1"),
},
BackupConfig: &gkebackup.BackupPlanBackupConfigArgs{
IncludeVolumeData: pulumi.Bool(true),
IncludeSecrets: pulumi.Bool(true),
SelectedApplications: &gkebackup.BackupPlanBackupConfigSelectedApplicationsArgs{
NamespacedNames: gkebackup.BackupPlanBackupConfigSelectedApplicationsNamespacedNameArray{
&gkebackup.BackupPlanBackupConfigSelectedApplicationsNamespacedNameArgs{
Name: pulumi.String("app1"),
Namespace: pulumi.String("ns1"),
},
&gkebackup.BackupPlanBackupConfigSelectedApplicationsNamespacedNameArgs{
Name: pulumi.String("app2"),
Namespace: pulumi.String("ns2"),
},
},
},
},
})
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 primary = new Gcp.Container.Cluster("primary", new()
{
Name = "full-cluster",
Location = "us-central1",
InitialNodeCount = 1,
WorkloadIdentityConfig = new Gcp.Container.Inputs.ClusterWorkloadIdentityConfigArgs
{
WorkloadPool = "my-project-name.svc.id.goog",
},
AddonsConfig = new Gcp.Container.Inputs.ClusterAddonsConfigArgs
{
GkeBackupAgentConfig = new Gcp.Container.Inputs.ClusterAddonsConfigGkeBackupAgentConfigArgs
{
Enabled = true,
},
},
DeletionProtection = true,
Network = "default",
Subnetwork = "default",
});
var full = new Gcp.GkeBackup.BackupPlan("full", new()
{
Name = "full-plan",
Cluster = primary.Id,
Location = "us-central1",
RetentionPolicy = new Gcp.GkeBackup.Inputs.BackupPlanRetentionPolicyArgs
{
BackupDeleteLockDays = 30,
BackupRetainDays = 180,
},
BackupSchedule = new Gcp.GkeBackup.Inputs.BackupPlanBackupScheduleArgs
{
CronSchedule = "0 9 * * 1",
},
BackupConfig = new Gcp.GkeBackup.Inputs.BackupPlanBackupConfigArgs
{
IncludeVolumeData = true,
IncludeSecrets = true,
SelectedApplications = new Gcp.GkeBackup.Inputs.BackupPlanBackupConfigSelectedApplicationsArgs
{
NamespacedNames = new[]
{
new Gcp.GkeBackup.Inputs.BackupPlanBackupConfigSelectedApplicationsNamespacedNameArgs
{
Name = "app1",
Namespace = "ns1",
},
new Gcp.GkeBackup.Inputs.BackupPlanBackupConfigSelectedApplicationsNamespacedNameArgs
{
Name = "app2",
Namespace = "ns2",
},
},
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.container.Cluster;
import com.pulumi.gcp.container.ClusterArgs;
import com.pulumi.gcp.container.inputs.ClusterWorkloadIdentityConfigArgs;
import com.pulumi.gcp.container.inputs.ClusterAddonsConfigArgs;
import com.pulumi.gcp.container.inputs.ClusterAddonsConfigGkeBackupAgentConfigArgs;
import com.pulumi.gcp.gkebackup.BackupPlan;
import com.pulumi.gcp.gkebackup.BackupPlanArgs;
import com.pulumi.gcp.gkebackup.inputs.BackupPlanRetentionPolicyArgs;
import com.pulumi.gcp.gkebackup.inputs.BackupPlanBackupScheduleArgs;
import com.pulumi.gcp.gkebackup.inputs.BackupPlanBackupConfigArgs;
import com.pulumi.gcp.gkebackup.inputs.BackupPlanBackupConfigSelectedApplicationsArgs;
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 primary = new Cluster("primary", ClusterArgs.builder()
.name("full-cluster")
.location("us-central1")
.initialNodeCount(1)
.workloadIdentityConfig(ClusterWorkloadIdentityConfigArgs.builder()
.workloadPool("my-project-name.svc.id.goog")
.build())
.addonsConfig(ClusterAddonsConfigArgs.builder()
.gkeBackupAgentConfig(ClusterAddonsConfigGkeBackupAgentConfigArgs.builder()
.enabled(true)
.build())
.build())
.deletionProtection(true)
.network("default")
.subnetwork("default")
.build());
var full = new BackupPlan("full", BackupPlanArgs.builder()
.name("full-plan")
.cluster(primary.id())
.location("us-central1")
.retentionPolicy(BackupPlanRetentionPolicyArgs.builder()
.backupDeleteLockDays(30)
.backupRetainDays(180)
.build())
.backupSchedule(BackupPlanBackupScheduleArgs.builder()
.cronSchedule("0 9 * * 1")
.build())
.backupConfig(BackupPlanBackupConfigArgs.builder()
.includeVolumeData(true)
.includeSecrets(true)
.selectedApplications(BackupPlanBackupConfigSelectedApplicationsArgs.builder()
.namespacedNames(
BackupPlanBackupConfigSelectedApplicationsNamespacedNameArgs.builder()
.name("app1")
.namespace("ns1")
.build(),
BackupPlanBackupConfigSelectedApplicationsNamespacedNameArgs.builder()
.name("app2")
.namespace("ns2")
.build())
.build())
.build())
.build());
}
}
resources:
primary:
type: gcp:container:Cluster
properties:
name: full-cluster
location: us-central1
initialNodeCount: 1
workloadIdentityConfig:
workloadPool: my-project-name.svc.id.goog
addonsConfig:
gkeBackupAgentConfig:
enabled: true
deletionProtection: true
network: default
subnetwork: default
full:
type: gcp:gkebackup:BackupPlan
properties:
name: full-plan
cluster: ${primary.id}
location: us-central1
retentionPolicy:
backupDeleteLockDays: 30
backupRetainDays: 180
backupSchedule:
cronSchedule: 0 9 * * 1
backupConfig:
includeVolumeData: true
includeSecrets: true
selectedApplications:
namespacedNames:
- name: app1
namespace: ns1
- name: app2
namespace: ns2
The backupSchedule property defines when backups run using cron syntax. The retentionPolicy controls how long backups are kept (backupRetainDays) and prevents accidental deletion for a specified period (backupDeleteLockDays). This configuration targets specific applications using selectedApplications with namespacedNames, backing up only “app1” in “ns1” and “app2” in “ns2”.
Define RPO targets with exclusion windows
Applications with strict recovery point objectives need frequent backups but may require blackout windows during maintenance or high-traffic periods.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const primary = new gcp.container.Cluster("primary", {
name: "rpo-daily-cluster",
location: "us-central1",
initialNodeCount: 1,
workloadIdentityConfig: {
workloadPool: "my-project-name.svc.id.goog",
},
addonsConfig: {
gkeBackupAgentConfig: {
enabled: true,
},
},
deletionProtection: true,
network: "default",
subnetwork: "default",
});
const rpoDailyWindow = new gcp.gkebackup.BackupPlan("rpo_daily_window", {
name: "rpo-daily-window",
cluster: primary.id,
location: "us-central1",
retentionPolicy: {
backupDeleteLockDays: 30,
backupRetainDays: 180,
},
backupSchedule: {
paused: true,
rpoConfig: {
targetRpoMinutes: 1440,
exclusionWindows: [
{
startTime: {
hours: 12,
},
duration: "7200s",
daily: true,
},
{
startTime: {
hours: 8,
minutes: 40,
seconds: 1,
nanos: 100,
},
duration: "3600s",
singleOccurrenceDate: {
year: 2024,
month: 3,
day: 16,
},
},
],
},
},
backupConfig: {
includeVolumeData: true,
includeSecrets: true,
allNamespaces: true,
},
});
import pulumi
import pulumi_gcp as gcp
primary = gcp.container.Cluster("primary",
name="rpo-daily-cluster",
location="us-central1",
initial_node_count=1,
workload_identity_config={
"workload_pool": "my-project-name.svc.id.goog",
},
addons_config={
"gke_backup_agent_config": {
"enabled": True,
},
},
deletion_protection=True,
network="default",
subnetwork="default")
rpo_daily_window = gcp.gkebackup.BackupPlan("rpo_daily_window",
name="rpo-daily-window",
cluster=primary.id,
location="us-central1",
retention_policy={
"backup_delete_lock_days": 30,
"backup_retain_days": 180,
},
backup_schedule={
"paused": True,
"rpo_config": {
"target_rpo_minutes": 1440,
"exclusion_windows": [
{
"start_time": {
"hours": 12,
},
"duration": "7200s",
"daily": True,
},
{
"start_time": {
"hours": 8,
"minutes": 40,
"seconds": 1,
"nanos": 100,
},
"duration": "3600s",
"single_occurrence_date": {
"year": 2024,
"month": 3,
"day": 16,
},
},
],
},
},
backup_config={
"include_volume_data": True,
"include_secrets": True,
"all_namespaces": True,
})
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/container"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/gkebackup"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
primary, err := container.NewCluster(ctx, "primary", &container.ClusterArgs{
Name: pulumi.String("rpo-daily-cluster"),
Location: pulumi.String("us-central1"),
InitialNodeCount: pulumi.Int(1),
WorkloadIdentityConfig: &container.ClusterWorkloadIdentityConfigArgs{
WorkloadPool: pulumi.String("my-project-name.svc.id.goog"),
},
AddonsConfig: &container.ClusterAddonsConfigArgs{
GkeBackupAgentConfig: &container.ClusterAddonsConfigGkeBackupAgentConfigArgs{
Enabled: pulumi.Bool(true),
},
},
DeletionProtection: pulumi.Bool(true),
Network: pulumi.String("default"),
Subnetwork: pulumi.String("default"),
})
if err != nil {
return err
}
_, err = gkebackup.NewBackupPlan(ctx, "rpo_daily_window", &gkebackup.BackupPlanArgs{
Name: pulumi.String("rpo-daily-window"),
Cluster: primary.ID(),
Location: pulumi.String("us-central1"),
RetentionPolicy: &gkebackup.BackupPlanRetentionPolicyArgs{
BackupDeleteLockDays: pulumi.Int(30),
BackupRetainDays: pulumi.Int(180),
},
BackupSchedule: &gkebackup.BackupPlanBackupScheduleArgs{
Paused: pulumi.Bool(true),
RpoConfig: &gkebackup.BackupPlanBackupScheduleRpoConfigArgs{
TargetRpoMinutes: pulumi.Int(1440),
ExclusionWindows: gkebackup.BackupPlanBackupScheduleRpoConfigExclusionWindowArray{
&gkebackup.BackupPlanBackupScheduleRpoConfigExclusionWindowArgs{
StartTime: &gkebackup.BackupPlanBackupScheduleRpoConfigExclusionWindowStartTimeArgs{
Hours: pulumi.Int(12),
},
Duration: pulumi.String("7200s"),
Daily: pulumi.Bool(true),
},
&gkebackup.BackupPlanBackupScheduleRpoConfigExclusionWindowArgs{
StartTime: &gkebackup.BackupPlanBackupScheduleRpoConfigExclusionWindowStartTimeArgs{
Hours: pulumi.Int(8),
Minutes: pulumi.Int(40),
Seconds: pulumi.Int(1),
Nanos: pulumi.Int(100),
},
Duration: pulumi.String("3600s"),
SingleOccurrenceDate: &gkebackup.BackupPlanBackupScheduleRpoConfigExclusionWindowSingleOccurrenceDateArgs{
Year: pulumi.Int(2024),
Month: pulumi.Int(3),
Day: pulumi.Int(16),
},
},
},
},
},
BackupConfig: &gkebackup.BackupPlanBackupConfigArgs{
IncludeVolumeData: pulumi.Bool(true),
IncludeSecrets: pulumi.Bool(true),
AllNamespaces: pulumi.Bool(true),
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;
return await Deployment.RunAsync(() =>
{
var primary = new Gcp.Container.Cluster("primary", new()
{
Name = "rpo-daily-cluster",
Location = "us-central1",
InitialNodeCount = 1,
WorkloadIdentityConfig = new Gcp.Container.Inputs.ClusterWorkloadIdentityConfigArgs
{
WorkloadPool = "my-project-name.svc.id.goog",
},
AddonsConfig = new Gcp.Container.Inputs.ClusterAddonsConfigArgs
{
GkeBackupAgentConfig = new Gcp.Container.Inputs.ClusterAddonsConfigGkeBackupAgentConfigArgs
{
Enabled = true,
},
},
DeletionProtection = true,
Network = "default",
Subnetwork = "default",
});
var rpoDailyWindow = new Gcp.GkeBackup.BackupPlan("rpo_daily_window", new()
{
Name = "rpo-daily-window",
Cluster = primary.Id,
Location = "us-central1",
RetentionPolicy = new Gcp.GkeBackup.Inputs.BackupPlanRetentionPolicyArgs
{
BackupDeleteLockDays = 30,
BackupRetainDays = 180,
},
BackupSchedule = new Gcp.GkeBackup.Inputs.BackupPlanBackupScheduleArgs
{
Paused = true,
RpoConfig = new Gcp.GkeBackup.Inputs.BackupPlanBackupScheduleRpoConfigArgs
{
TargetRpoMinutes = 1440,
ExclusionWindows = new[]
{
new Gcp.GkeBackup.Inputs.BackupPlanBackupScheduleRpoConfigExclusionWindowArgs
{
StartTime = new Gcp.GkeBackup.Inputs.BackupPlanBackupScheduleRpoConfigExclusionWindowStartTimeArgs
{
Hours = 12,
},
Duration = "7200s",
Daily = true,
},
new Gcp.GkeBackup.Inputs.BackupPlanBackupScheduleRpoConfigExclusionWindowArgs
{
StartTime = new Gcp.GkeBackup.Inputs.BackupPlanBackupScheduleRpoConfigExclusionWindowStartTimeArgs
{
Hours = 8,
Minutes = 40,
Seconds = 1,
Nanos = 100,
},
Duration = "3600s",
SingleOccurrenceDate = new Gcp.GkeBackup.Inputs.BackupPlanBackupScheduleRpoConfigExclusionWindowSingleOccurrenceDateArgs
{
Year = 2024,
Month = 3,
Day = 16,
},
},
},
},
},
BackupConfig = new Gcp.GkeBackup.Inputs.BackupPlanBackupConfigArgs
{
IncludeVolumeData = true,
IncludeSecrets = true,
AllNamespaces = true,
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.container.Cluster;
import com.pulumi.gcp.container.ClusterArgs;
import com.pulumi.gcp.container.inputs.ClusterWorkloadIdentityConfigArgs;
import com.pulumi.gcp.container.inputs.ClusterAddonsConfigArgs;
import com.pulumi.gcp.container.inputs.ClusterAddonsConfigGkeBackupAgentConfigArgs;
import com.pulumi.gcp.gkebackup.BackupPlan;
import com.pulumi.gcp.gkebackup.BackupPlanArgs;
import com.pulumi.gcp.gkebackup.inputs.BackupPlanRetentionPolicyArgs;
import com.pulumi.gcp.gkebackup.inputs.BackupPlanBackupScheduleArgs;
import com.pulumi.gcp.gkebackup.inputs.BackupPlanBackupScheduleRpoConfigArgs;
import com.pulumi.gcp.gkebackup.inputs.BackupPlanBackupConfigArgs;
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 primary = new Cluster("primary", ClusterArgs.builder()
.name("rpo-daily-cluster")
.location("us-central1")
.initialNodeCount(1)
.workloadIdentityConfig(ClusterWorkloadIdentityConfigArgs.builder()
.workloadPool("my-project-name.svc.id.goog")
.build())
.addonsConfig(ClusterAddonsConfigArgs.builder()
.gkeBackupAgentConfig(ClusterAddonsConfigGkeBackupAgentConfigArgs.builder()
.enabled(true)
.build())
.build())
.deletionProtection(true)
.network("default")
.subnetwork("default")
.build());
var rpoDailyWindow = new BackupPlan("rpoDailyWindow", BackupPlanArgs.builder()
.name("rpo-daily-window")
.cluster(primary.id())
.location("us-central1")
.retentionPolicy(BackupPlanRetentionPolicyArgs.builder()
.backupDeleteLockDays(30)
.backupRetainDays(180)
.build())
.backupSchedule(BackupPlanBackupScheduleArgs.builder()
.paused(true)
.rpoConfig(BackupPlanBackupScheduleRpoConfigArgs.builder()
.targetRpoMinutes(1440)
.exclusionWindows(
BackupPlanBackupScheduleRpoConfigExclusionWindowArgs.builder()
.startTime(BackupPlanBackupScheduleRpoConfigExclusionWindowStartTimeArgs.builder()
.hours(12)
.build())
.duration("7200s")
.daily(true)
.build(),
BackupPlanBackupScheduleRpoConfigExclusionWindowArgs.builder()
.startTime(BackupPlanBackupScheduleRpoConfigExclusionWindowStartTimeArgs.builder()
.hours(8)
.minutes(40)
.seconds(1)
.nanos(100)
.build())
.duration("3600s")
.singleOccurrenceDate(BackupPlanBackupScheduleRpoConfigExclusionWindowSingleOccurrenceDateArgs.builder()
.year(2024)
.month(3)
.day(16)
.build())
.build())
.build())
.build())
.backupConfig(BackupPlanBackupConfigArgs.builder()
.includeVolumeData(true)
.includeSecrets(true)
.allNamespaces(true)
.build())
.build());
}
}
resources:
primary:
type: gcp:container:Cluster
properties:
name: rpo-daily-cluster
location: us-central1
initialNodeCount: 1
workloadIdentityConfig:
workloadPool: my-project-name.svc.id.goog
addonsConfig:
gkeBackupAgentConfig:
enabled: true
deletionProtection: true
network: default
subnetwork: default
rpoDailyWindow:
type: gcp:gkebackup:BackupPlan
name: rpo_daily_window
properties:
name: rpo-daily-window
cluster: ${primary.id}
location: us-central1
retentionPolicy:
backupDeleteLockDays: 30
backupRetainDays: 180
backupSchedule:
paused: true
rpoConfig:
targetRpoMinutes: 1440
exclusionWindows:
- startTime:
hours: 12
duration: 7200s
daily: true
- startTime:
hours: 8
minutes: 40
seconds: 1
nanos: 100
duration: 3600s
singleOccurrenceDate:
year: 2024
month: 3
day: 16
backupConfig:
includeVolumeData: true
includeSecrets: true
allNamespaces: true
The rpoConfig property sets a target recovery point objective in minutes (1440 minutes = 24 hours). Backup for GKE automatically schedules backups to meet this target. The exclusionWindows array defines periods when backups should not run: daily recurring windows (daily: true) and one-time windows (singleOccurrenceDate). Each window specifies a startTime and duration in seconds.
Beyond these examples
These snippets focus on specific backup plan features: namespace and application selection strategies, encryption, retention, and scheduling, and RPO-based backup automation. They’re intentionally minimal rather than full disaster recovery solutions.
The examples may reference pre-existing infrastructure such as GKE clusters with Backup for GKE addon enabled, Cloud KMS keys for customer-managed encryption, and Workload Identity configuration on clusters. They focus on configuring the backup plan rather than provisioning the underlying cluster infrastructure.
To keep things focused, common backup plan patterns are omitted, including:
- Deactivation and plan lifecycle (deactivated property)
- Permissive mode for partial backup success
- Autopilot cluster-specific configuration
- Weekly exclusion windows (daysOfWeek)
These omissions are intentional: the goal is to illustrate how each backup plan feature is wired, not provide drop-in disaster recovery modules. See the GKE BackupPlan resource reference for all available configuration options.
Let's create GCP GKE Backup Plans
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Configuration & Setup
addonsConfig.gkeBackupAgentConfig.enabled to true in your cluster configuration.cluster, location, name, and project properties are immutable. Changes to these require recreating the BackupPlan resource.labels field is non-authoritative and only manages labels in your configuration. Use effectiveLabels to see all labels on the resource, including those set by other clients or services.Backup Scope & Selection
You have four options in backupConfig:
- All namespaces - Set
allNamespacestotrue - Specific namespaces - Use
selectedNamespaceswith a list of namespace names - Label-based - Use
selectedNamespaceLabelsto match namespaces by labels - Specific applications - Use
selectedApplicationswith namespaced app names
permissiveMode to true allows backups to proceed even if some resources fail to back up, rather than failing the entire backup operation.Scheduling & Retention
cronSchedule uses cron syntax for fixed schedules (e.g., "0 9 * * 1" for weekly backups). rpoConfig uses targetRpoMinutes to define recovery point objectives and supports exclusionWindows for more flexible scheduling.exclusionWindows in rpoConfig with startTime and duration. You can specify daily windows, weekly windows using daysOfWeek, or single-occurrence windows using singleOccurrenceDate.retentionPolicy to set backupDeleteLockDays (minimum retention period) and backupRetainDays (maximum retention period) for backups created by this plan.Security & Encryption
encryptionKey.gcpKmsEncryptionKey in backupConfig with your Cloud KMS CryptoKey ID.Management & Lifecycle
deactivated to true locks the BackupPlan, preventing all updates except deletes. It also prevents any new backups from being created, including scheduled backups. This is typically done before deletion.Using a different cloud?
Explore containers guides for other cloud providers: