Schedule icon
Webhook icon
Query icon
Commands icon
Docker icon
Upload icon
If icon
Set icon
Log icon
SlackIncomingWebhook icon
Fail icon

Automated PostgreSQL Backup to S3 with Integrity Verification Gate

Automate PostgreSQL database backups with pg_dump and gzip, archive to Amazon S3, verify size integrity, track in KV, and alert Slack on failures.

Categories
CloudData

Database backups often fail quietly: cron jobs exit without error while writing empty files, disks run out of space mid-dump, or credentials expire unnoticed until a recovery drill is attempted. This blueprint provides a production-grade, observable PostgreSQL disaster recovery pipeline. It queries database metadata, dumps and compresses tables with pg_dump inside an isolated container, streams the archive to Amazon S3 with structured date-partitioned keys, evaluates archive size against a safety threshold, updates the namespace KV store with the latest backup state, and notifies Slack on either size anomalies or pipeline errors.

How it works

  1. check_db_connectivity (io.kestra.plugin.jdbc.postgresql.Query) connects using POSTGRES_USER and POSTGRES_PASSWORD, verifying database availability and counting tables in public schema via fetchType: FETCH_ONE.
  2. generate_backup (io.kestra.plugin.scripts.shell.Commands on the io.kestra.plugin.scripts.runner.docker.Docker runner) runs pg_dump with gzip compression in a lightweight postgres:17-alpine container, measures the compressed size with du -k, and emits backup_size_kb through Kestra's outputs protocol while capturing backup.sql.gz as an output file.
  3. upload_to_s3 (io.kestra.plugin.aws.s3.Upload) streams the compressed archive to the configured Amazon S3 bucket under backups/<database_name>/<yyyy-MM-dd>/backup-<timestamp>.sql.gz.
  4. verify_backup_integrity (io.kestra.plugin.core.flow.If) compares backup_size_kb against min_backup_size_kb. If healthy, record_latest_backup_kv (io.kestra.plugin.core.kv.Set) publishes the backup metadata to POSTGRES_LAST_BACKUP_METADATA and log_backup_success records an audit entry. If underweight, alert_underweight_backup posts a warning to Slack and fail_on_anomaly flags the execution as failed.
  5. The errors block alerts Slack immediately if any connection, dump, or upload step fails.
  6. Dual triggers allow scheduled runs (io.kestra.plugin.core.trigger.Schedule, 02:00 UTC) and automated pre-deployment snapshots via io.kestra.plugin.core.trigger.Webhook.

What you get

  • Automated, scheduled logical backups with zero local disk footprint on the host.
  • Timestamped and date-partitioned S3 storage keys enabling granular point-in-time recovery.
  • A post-dump size integrity gate preventing truncated or empty dumps from passing unnoticed.
  • A single authoritative KV key (POSTGRES_LAST_BACKUP_METADATA) exposing the latest valid backup URI and table count for downstream restore drills or status boards.
  • Multi-channel failure alerting with direct execution links for fast incident triage.

Who it's for

  • DevOps and Site Reliability Engineers managing PostgreSQL production workloads.
  • Database Administrators requiring auditable disaster recovery pipelines.
  • Data Platform teams needing pre-deployment automated database snapshots.

Why orchestrate this with Kestra

Standalone cron scripts running pg_dump lack visibility: failed uploads leave silent gaps, error messages are lost in local mail queues, and credentials must be scattered across database nodes. Kestra orchestrates the entire lifecycle declaratively: secrets are managed centrally, containerized runners guarantee matching PostgreSQL client versions, retries handle transient network blips during S3 uploads, and execution history maintains an immutable audit trail of every snapshot taken.

Prerequisites

  • A reachable PostgreSQL database (version 12 through 17).
  • An Amazon S3 bucket with an IAM identity allowed to put objects (s3:PutObject).
  • Docker daemon accessible to the Kestra worker for containerized task execution.
  • A Slack incoming webhook for notification delivery.

Secrets

  • POSTGRES_HOST: Hostname or IP address of the PostgreSQL server.
  • POSTGRES_USER: Database username with read access to target schemas.
  • POSTGRES_PASSWORD: Database user password.
  • AWS_ACCESS_KEY_ID: AWS access key for S3 bucket upload.
  • AWS_SECRET_ACCESS_KEY: AWS secret key matching the access key.
  • SLACK_WEBHOOK_URL: Slack incoming webhook URL for anomaly and failure alerts.
  • BACKUP_WEBHOOK_KEY: Secret authentication key for the on-demand webhook trigger.

Quick start

  1. Add the seven required secrets to your Kestra namespace.
  2. Adjust database_name and s3_bucket inputs to reflect your environment.
  3. Trigger a manual execution to verify the dump, S3 upload, and KV registration.
  4. Inspect outputs.backup_summary and confirm the file is visible in your S3 bucket.
  5. Enable the daily_backup_schedule trigger by setting disabled: false.

How to extend

  • Automated Restore Drill: Attach a downstream subflow that downloads the latest S3 archive, restores it into an ephemeral test container, and executes sanity checks.
  • S3 Glacier Lifecycle: Configure S3 bucket lifecycle rules to transition archives older than 30 days to S3 Glacier Flexible Retrieval.
  • Schema Exclusion: Add -N schema_name flags to pg_dump commands to omit temporary or cache tables from the backup archive.
  • Multi-Database Fanout: Wrap the flow in a ForEachItem task to back up multiple PostgreSQL databases across the cluster sequentially or in parallel.

Links

See How

New to Kestra?

Use blueprints to kickstart your first workflows.