The gcp:gkebackup/backupPlan:BackupPlan resource, part of the Pulumi GCP provider, defines a backup plan for GKE clusters: what to back up, when to back it up, and how long to retain backups. This guide focuses on four capabilities: namespace selection strategies, customer-managed encryption, automated scheduling and retention, and RPO-based backup frequency.
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 by protecting an entire cluster, capturing both application state and persistent volume data.
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 backed up. 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 backups.
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 specifies a Cloud KMS CryptoKey for encrypting backup data. Instead of allNamespaces, this example uses selectedNamespaces to back up only the “default” and “test” namespaces. The backup service account needs the cryptoKeyEncrypterDecrypter role on the specified key.
Select namespaces by label selectors
Teams managing multi-tenant clusters often organize workloads with labels and need to back up only namespaces matching specific criteria.
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 key-value pairs. Only namespaces with matching labels are included in backups. This approach works well when you organize workloads by environment, team, or application tier.
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 sets the retention period, while backupDeleteLockDays prevents deletion for a minimum number of days. This example also uses selectedApplications to back up specific Kubernetes resources by name and namespace.
Define RPO targets with exclusion windows
Applications with strict recovery point objectives need frequent backups but may want to avoid backup operations during maintenance windows or peak 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. Backup for GKE attempts to maintain this RPO by creating backups as frequently as needed. The exclusionWindows array defines time periods when backups should not run: daily windows repeat every day, while singleOccurrenceDate windows apply to specific dates.
Beyond these examples
These snippets focus on specific backup plan features: namespace selection (all, specific, or label-based), encryption with customer-managed keys, scheduling and retention policies, and RPO-based backup frequency with exclusion windows. 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 encryption, and Workload Identity configuration. 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 locking (deactivated property)
- Permissive mode for partial backup success
- Application-level selection by namespaced names
- Weekly exclusion windows (daysOfWeek configuration)
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 & Immutability
cluster, location, name, and project properties are immutable and cannot be modified after creation. Changes to these require replacing the resource.deactivated to true permanently locks the BackupPlan, preventing all updates (except deletes) and blocking new backups from being created. This is a one-way operation; you cannot reactivate the plan.gkeBackupAgentConfig.enabled to true in your cluster’s addonsConfig.Backup Scope & Selection
You have four options in backupConfig:
- All namespaces - Set
allNamespaces: true - Specific namespaces - Use
selectedNamespaceswith a list of namespace names - Label-based selection - Use
selectedNamespaceLabelswith resource labels - Specific applications - Use
selectedApplicationswith namespaced names
includeSecrets and includeVolumeData to true in your backupConfig.Scheduling & Automation
cronSchedule for fixed-time backups (e.g., “0 9 * * 1” for weekly). Use rpoConfig with targetRpoMinutes for recovery point objective-based scheduling, which allows defining exclusion windows for daily, weekly, or single-occurrence periods.rpoConfig, define exclusionWindows with start times, durations, and recurrence patterns (daily, specific days of week, or single occurrence dates).Retention & Advanced Features
retentionPolicy with backupRetainDays (how long to keep backups) and backupDeleteLockDays (minimum retention period before deletion is allowed).encryptionKey.gcpKmsEncryptionKey to your KMS CryptoKey ID in the backupConfig.labels field is non-authoritative and only manages labels in your configuration. Use effectiveLabels to see all labels present on the resource, including those set by other clients or services.Using a different cloud?
Explore containers guides for other cloud providers: