Backup and Restore
LEVEL 0
The Problem
You’re running a production database in Docker with a volume storing critical data:
docker volume create pgdata
docker run -d -v pgdata:/var/lib/postgresql/data postgres:15
The data is safe as long as the host is healthy. But what if:
- The host crashes and the disk is corrupted?
- Someone accidentally runs
docker volume rm pgdata? - You need to migrate to a different server?
- You need to restore data from last week after a bad migration?
You need backups. How do you backup and restore Docker volumes?
LEVEL 1
The Concept — The Safe Deposit Box Backup
The Concept
You store valuables in a bank’s safe deposit box (Docker volume). The bank is secure, but what if the bank burns down?
You make copies of your valuables periodically:
- Take items out of the safe deposit box
- Photograph or copy them
- Store the copies in a different location (cloud storage, another bank)
When disaster strikes, you have the copies to restore from.
Docker volume backups work the same way:
- Run a container that mounts the volume
- Copy the volume data out to a tar file
- Store the tar file somewhere safe (S3, NAS, backup server)
- To restore, reverse the process
LEVEL 2
Backing Up a Volume
Method 1: Using a temporary container
# Create a backup of volume 'pgdata' to a tar file
docker run --rm \
-v pgdata:/data:ro \
-v $(pwd):/backup \
alpine \
tar czf /backup/pgdata-backup.tar.gz -C /data .
Explanation:
--rm: Remove container when done-v pgdata:/data:ro: Mount volume as read-only at/data-v $(pwd):/backup: Mount current directory to store backup filetar czf /backup/pgdata-backup.tar.gz -C /data .: Create compressed archive of volume data
Result: pgdata-backup.tar.gz in your current directory contains all volume data.
Method 2: Backup while container is running
For databases, use the database’s backup tool:
# Backup PostgreSQL while running
docker exec postgres pg_dump -U postgres mydb > backup.sql
# Or create a full backup
docker exec postgres pg_dumpall -U postgres > full-backup.sql
Method 3: Automated backups with a script
#!/bin/bash
# backup-volumes.sh
BACKUP_DIR="/backups"
DATE=$(date +%Y%m%d-%H%M%S)
for VOLUME in pgdata redis-data uploads; do
echo "Backing up $VOLUME..."
docker run --rm \
-v $VOLUME:/data:ro \
-v $BACKUP_DIR:/backup \
alpine \
tar czf /backup/${VOLUME}-${DATE}.tar.gz -C /data .
done
echo "Backups complete!"
Run with cron:
# Daily backups at 2 AM
0 2 * * * /usr/local/bin/backup-volumes.sh
LEVEL 3
Restoring a Volume
Restore from tar backup:
# Create a new volume
docker volume create pgdata-restored
# Extract backup into the volume
docker run --rm \
-v pgdata-restored:/data \
-v $(pwd):/backup \
alpine \
tar xzf /backup/pgdata-backup.tar.gz -C /data
# Use the restored volume
docker run -d -v pgdata-restored:/var/lib/postgresql/data postgres:15
Restore database from SQL dump:
# Start PostgreSQL with fresh volume
docker run -d --name postgres -v pgdata-new:/var/lib/postgresql/data postgres:15
# Wait for PostgreSQL to start
sleep 10
# Restore from SQL backup
cat backup.sql | docker exec -i postgres psql -U postgres
LEVEL 4
Cloud Backups and Disaster Recovery
Backup to AWS S3:
#!/bin/bash
# Backup volume and upload to S3
VOLUME="pgdata"
BACKUP_FILE="pgdata-$(date +%Y%m%d-%H%M%S).tar.gz"
# Create backup
docker run --rm \
-v $VOLUME:/data:ro \
-v $(pwd):/backup \
alpine \
tar czf /backup/$BACKUP_FILE -C /data .
# Upload to S3
aws s3 cp $BACKUP_FILE s3://my-backups/docker-volumes/
# Clean up local backup
rm $BACKUP_FILE
echo "Backup uploaded to S3: $BACKUP_FILE"
Restore from S3:
#!/bin/bash
# Download and restore from S3
BACKUP_FILE="pgdata-20260131-020000.tar.gz"
VOLUME="pgdata-restored"
# Download from S3
aws s3 cp s3://my-backups/docker-volumes/$BACKUP_FILE .
# Create volume and restore
docker volume create $VOLUME
docker run --rm \
-v $VOLUME:/data \
-v $(pwd):/backup \
alpine \
tar xzf /backup/$BACKUP_FILE -C /data
echo "Volume restored: $VOLUME"
Using volume backup tools:
Third-party tools for Docker volume backups:
- docker-volume-backup: Automated backup container
- Velero: Kubernetes (also works with Docker)
- Restic: Backup to various cloud providers
Example with docker-volume-backup:
docker run -d \
--name volume-backup \
-v pgdata:/backup/pgdata:ro \
-v /var/run/docker.sock:/var/run/docker.sock:ro \
-e BACKUP_CRON_EXPRESSION="0 2 * * *" \
-e AWS_S3_BUCKET_NAME="my-backups" \
offen/docker-volume-backup
LEVEL 5
Testing Your Backups
The golden rule: Untested backups are useless.
Regularly test restoration:
#!/bin/bash
# Test backup restoration
echo "Testing backup restoration..."
# Restore to a test volume
docker volume create pgdata-test
docker run --rm \
-v pgdata-test:/data \
-v $(pwd):/backup \
alpine \
tar xzf /backup/latest-backup.tar.gz -C /data
# Start PostgreSQL with test volume
docker run -d --name postgres-test -v pgdata-test:/var/lib/postgresql/data postgres:15
# Wait for startup
sleep 10
# Run validation queries
docker exec postgres-test psql -U postgres -c "SELECT COUNT(*) FROM users;"
# Clean up
docker stop postgres-test
docker rm postgres-test
docker volume rm pgdata-test
echo "Backup test complete!"
Run this monthly to verify backups are working.