1. Answers
  2. PostgreSQL Backup and Restore Workflows in Kubernetes

How do I set up PostgreSQL backup and restore workflows in Kubernetes?

In this guide, we will set up a PostgreSQL database in a Kubernetes cluster and configure backup and restore workflows using Pulumi. We will use Kubernetes CronJobs to schedule the backups and PersistentVolumeClaims to store the backup data.

Key Points

  • Deploy a PostgreSQL instance in Kubernetes.
  • Set up a PersistentVolumeClaim for backup storage.
  • Create a Kubernetes CronJob to handle backups.
  • Create a Kubernetes Job to handle restores.

Below is the complete Pulumi program written in TypeScript:

import * as pulumi from "@pulumi/pulumi";
import * as k8s from "@pulumi/kubernetes";

// Define the namespace
const namespace = new k8s.core.v1.Namespace("pg-backup-restore-ns", {
    metadata: { name: "pg-backup-restore" }
});

// Define the PersistentVolumeClaim for backup storage
const backupPvc = new k8s.core.v1.PersistentVolumeClaim("pg-backup-pvc", {
    metadata: {
        namespace: namespace.metadata.name,
    },
    spec: {
        accessModes: ["ReadWriteOnce"],
        resources: {
            requests: {
                storage: "10Gi",
            },
        },
    },
});

// Define the PostgreSQL deployment
const pgDeployment = new k8s.apps.v1.Deployment("pg-deployment", {
    metadata: {
        namespace: namespace.metadata.name,
    },
    spec: {
        selector: { matchLabels: { app: "postgres" } },
        template: {
            metadata: { labels: { app: "postgres" } },
            spec: {
                containers: [{
                    name: "postgres",
                    image: "postgres:13",
                    env: [
                        { name: "POSTGRES_DB", value: "mydatabase" },
                        { name: "POSTGRES_USER", value: "myuser" },
                        { name: "POSTGRES_PASSWORD", value: "mypassword" },
                    ],
                    ports: [{ containerPort: 5432 }],
                    volumeMounts: [{
                        name: "pgdata",
                        mountPath: "/var/lib/postgresql/data",
                    }],
                }],
                volumes: [{
                    name: "pgdata",
                    persistentVolumeClaim: {
                        claimName: backupPvc.metadata.name,
                    },
                }],
            },
        },
    },
});

// Define the CronJob for backups
const backupCronJob = new k8s.batch.v1beta1.CronJob("pg-backup-cronjob", {
    metadata: {
        namespace: namespace.metadata.name,
    },
    spec: {
        schedule: "0 2 * * *", // Daily at 2am
        jobTemplate: {
            spec: {
                template: {
                    spec: {
                        containers: [{
                            name: "pg-backup",
                            image: "postgres:13",
                            env: [
                                { name: "PGHOST", value: "postgres" },
                                { name: "PGUSER", value: "myuser" },
                                { name: "PGPASSWORD", value: "mypassword" },
                                { name: "PGDATABASE", value: "mydatabase" },
                            ],
                            command: [
                                "sh",
                                "-c",
                                "pg_dumpall -c > /backup/all-databases.sql",
                            ],
                            volumeMounts: [{
                                name: "backup-storage",
                                mountPath: "/backup",
                            }],
                        }],
                        restartPolicy: "OnFailure",
                        volumes: [{
                            name: "backup-storage",
                            persistentVolumeClaim: {
                                claimName: backupPvc.metadata.name,
                            },
                        }],
                    },
                },
            },
        },
    },
});

// Define the Job for restoring from backup
const restoreJob = new k8s.batch.v1.Job("pg-restore-job", {
    metadata: {
        namespace: namespace.metadata.name,
    },
    spec: {
        template: {
            spec: {
                containers: [{
                    name: "pg-restore",
                    image: "postgres:13",
                    env: [
                        { name: "PGHOST", value: "postgres" },
                        { name: "PGUSER", value: "myuser" },
                        { name: "PGPASSWORD", value: "mypassword" },
                        { name: "PGDATABASE", value: "mydatabase" },
                    ],
                    command: [
                        "sh",
                        "-c",
                        "psql -f /backup/all-databases.sql",
                    ],
                    volumeMounts: [{
                        name: "backup-storage",
                        mountPath: "/backup",
                    }],
                }],
                restartPolicy: "OnFailure",
                volumes: [{
                    name: "backup-storage",
                    persistentVolumeClaim: {
                        claimName: backupPvc.metadata.name,
                    },
                }],
            },
        },
    },
});

Summary

In this guide, we deployed a PostgreSQL instance in a Kubernetes cluster and set up backup and restore workflows using Pulumi. We configured a PersistentVolumeClaim to store backup data, a CronJob to schedule regular backups, and a Job to restore data from backups. This setup ensures that your PostgreSQL data is regularly backed up and can be restored when needed.

Deploy this code

Want to deploy this code? Sign up for a free Pulumi account to deploy in a few clicks.

Sign up

New to Pulumi?

Want to deploy this code? Sign up with Pulumi to deploy in a few clicks.

Sign up