Sao lưu tự động PostgreSQL trong Docker với cron job và gzip
Hướng dẫn xây dựng script tự động backup database PostgreSQL chạy trong Docker container: gzip, cron hàng ngày, tự động xóa bản sao lưu cũ và kiểm thử phục hồi.

Tự học Docker từ A-Z
Tầm quan trọng của chiến lược sao lưu dữ liệu (Backup Strategy)
Dữ liệu là tài sản quan trọng nhất của bất kì hệ thống phần mềm nào. Cho dù bạn có thiết lập hệ thống mạnh mẽ đến đâu, các sự cố như lỗi phần cứng ổ đĩa, thao tác xóa nhầm của con người, lỗi migration cơ sở dữ liệu hoặc tấn công mã độc ransomware vẫn luôn có thể xảy ra....
Một nguyên tắc vàng trong quản trị hệ thống là: Một bản sao lưu chưa từng được kiểm tra khôi phục thì không được coi là một bản sao lưu (An untested backup is not a backup).
Trong bài viết này, chúng ta sẽ cùng nhau xây dựng một giải pháp sao lưu tự động, nén dữ liệu, dọn dẹp các bản backup cũ và phục hồi toàn diện cho cơ sở dữ liệu PostgreSQL đang chạy dưới dạng Docker container..
1. Nguyên lí hoạt động của docker exec và pg_dump
Thay vì phải cài đặt các công cụ PostgreSQL client trên máy chủ chủ (Host OS), chúng ta có thể tận dụng chính tiện ích pg_dump đã có sẵn bên trong container PostgreSQL bằng lệnh docker exec.
Lệnh sao lưu cốt lõi có dạng:
docker exec -t <CONTAINER_NAME> pg_dump -U <DB_USER> <DB_NAME> | gzip > /path/to/backup/db_backup.sql.gz
-t: Cấp quyền TTY ảo để nhận dữ liệu luồng.pg_dump -U <user> <db>: Xuất cấu trúc và toàn bộ dữ liệu bảng dưới dạng mã SQL.| gzip: Nén luồng dữ liệu ngay lập tức trên RAM trước khi ghi xuống đĩa, giúp tiết kiệm tới 80-90% dung lượng ổ cứng.
2. Viết Script Sao lưu tự động chuyên nghiệp (backup_postgres.sh)
Tạo một thư mục chuyên dụng chứa các script quản trị trên máy chủ:
sudo mkdir -p /opt/scripts /var/backups/postgres
sudo chmod 700 /var/backups/postgres
Tạo file script /opt/scripts/backup_postgres.sh:
sudo nano /opt/scripts/backup_postgres.sh
Dán nội dung script hoàn chỉnh dưới đây:
#!/bin/bash
# ==============================================================================
# SCRIPT TỰ ĐỘNG SAO LƯU POSTGRESQL TRONG DOCKER
# Tác giả: TechBlog Admin
# ==============================================================================
set -eo pipefail
# Cấu hình thông tin
CONTAINER_NAME="production_postgres"
DB_USER="pgadmin"
DB_NAME="core_production"
BACKUP_DIR="/var/backups/postgres"
DATE_STAMP=$(date +"%Y%m%d_%H%M%S")
FILENAME="${BACKUP_DIR}/${DB_NAME}_${DATE_STAMP}.sql.gz"
LOG_FILE="/var/log/postgres_backup.log"
RETENTION_DAYS=7 # Lưu trữ tối đa trong 7 ngày
log_message() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}
log_message "=== BẮT ĐẦU TIẾN TRÌNH SAO LƯU CHO DATABASE: ${DB_NAME} ==="
# Kiểm tra xem container có đang chạy hay không
if ! docker ps --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then
log_message "LỖI: Container ${CONTAINER_NAME} không hoạt động hoặc không tồn tại!"
exit 1
fi
# Thực hiện trích xuất dữ liệu và nén gzip
if docker exec -t "$CONTAINER_NAME" pg_dump -U "$DB_USER" "$DB_NAME" | gzip > "$FILENAME"; then
FILE_SIZE=$(du -h "$FILENAME" | cut -f1)
log_message "THÀNH CÔNG: Đã tạo bản sao lưu tại ${FILENAME} (Dung lượng: ${FILE_SIZE})"
else
log_message "LỖI: Tiến trình pg_dump thất bại!"
rm -f "$FILENAME"
exit 1
fi
# Tự động dọn dẹp các file backup cũ quá số ngày quy định
log_message "Đang dọn dẹp các bản backup cũ hơn ${RETENTION_DAYS} ngày..."
DELETED_COUNT=$(find "$BACKUP_DIR" -type f -name "${DB_NAME}_*.sql.gz" -mtime +${RETENTION_DAYS} -delete -print | wc -l)
log_message "Đã xóa ${DELETED_COUNT} bản sao lưu cũ."
log_message "=== HOÀN TẤT SAO LƯU THÀNH CÔNG ==="
exit 0
Phân quyền thực thi nghiêm ngặt (chỉ cho phép user root được đọc và chạy script):
sudo chmod 700 /opt/scripts/backup_postgres.sh
3. Chạy thử nghiệm Script thủ công
Hãy kiểm tra chạy thử script lần đầu để đảm bảo không có lỗi phân quyền hay sai tên container:
sudo /opt/scripts/backup_postgres.sh
Kiểm tra file sao lưu đã được tạo trong thư mục backup:
ls -lh /var/backups/postgres/
Kiểm tra nội dung log:
cat /var/log/postgres_backup.log
4. Thiết lập Lịch chạy tự động với Cron Job
Để máy chủ tự động thực hiện sao lưu vào 02:00 sáng mỗi ngày (thời điểm lượng truy cập hệ thống thấp nhất):
Mở bảng lập lịch Cron của tài khoản root:
sudo crontab -e
Thêm dòng sau vào cuối file crontab:
# Chạy sao lưu PostgreSQL vào lúc 02:00 AM hàng ngày
0 2 * * * /opt/scripts/backup_postgres.sh > /dev/null 2>&1
Lưu và đóng file (Ctrl + O, Enter, Ctrl + X trong nano).
Kiểm tra danh sách cron job đang hoạt động:
sudo crontab -l
5. Qui trình kiểm thử phục hồi dữ liệu (Database Restore)
Đừng đợi đến khi xảy ra thảm họa mới tìm cách phục hồi. Hãy thực hành quy trình khôi phục định kỳ theo các bước sau:
Bước 5.1: Giải nén và nạp dữ liệu vào container
Giả sử bạn cần khôi phục file /var/backups/postgres/core_production_20241020_020000.sql.gz:
# Giải nén và nạp trực tiếp qua lệnh psql trong Docker
gunzip -c /var/backups/postgres/core_production_20241020_020000.sql.gz | docker exec -i production_postgres psql -U pgadmin -d core_production
Trong môi trường thử nghiệm khôi phục, bạn nên tạo một cơ sở dữ liệu tạm thời (ví dụ: core_restore_test) để kiểm tra tính toàn vẹn của dữ liệu trước khi đè lên cơ sở dữ liệu chính:
# 1. Tạo database test
docker exec -it production_postgres psql -U pgadmin -c "CREATE DATABASE core_restore_test;"
# 2. Nạp dữ liệu vào database test
gunzip -c /var/backups/postgres/core_production_20241020_020000.sql.gz | docker exec -i production_postgres psql -U pgadmin -d core_restore_test
# 3. Xóa database test sau khi kiểm tra xong
docker exec -it production_postgres psql -U pgadmin -c "DROP DATABASE core_restore_test;"
6. Chiến lược mở rộng: Sao lưu Offsite lên Cloud Storage (S3 / R2)
Lưu trữ bản backup trên cùng một máy chủ VPS vẫn tiềm ẩn rủi ro nếu toàn bộ ổ cứng máy chủ bị hỏng vật lý hoặc nhà cung cấp VPS gặp sự cố trung tâm dữ liệu.
Bạn nên mở rộng script trên bằng cách cài đặt công cụ AWS CLI hoặc rclone để tự động đẩy file backup lên các dịch vụ lưu trữ đám mây giá rẻ như Cloudflare R2 hoặc AWS S3 Glacier:
# Ví dụ đẩy file lên S3 / R2 bucket
aws s3 cp "$FILENAME" s3://my-company-backups/postgres/ --endpoint-url https://<ACCOUNT_ID>.r2.cloudflarestorage.com
Bảng so sánh các phương pháp Backup PostgreSQL
| Phương pháp | Ưu điểm | Nhược điểm | Phù hợp nhất |
|---|---|---|---|
pg_dump (Logical) | File SQL dạng text, dễ đọc, khôi phục được giữa các phiên bản PostgreSQL khác nhau | Tốc độ chậm với database dung lượng cực lớn (>100GB) | Hầu hết các website và ứng dụng vừa & nhỏ (<50GB) |
pg_basebackup (Physical) | Sao chép nguyên khối nhị phân, tốc độ cực nhanh | Yêu cầu cùng kiến trúc và phiên bản PostgreSQL chính xác | Hệ thống lớn hàng trăm GB, thiết lập Streaming Replication |
| Volume Snapshot | Snapshot tức thời ở mức ổ đĩa VPS | Phải lock IO để đảm bảo tính nhất quán (Crash-consistent) | Sao lưu hạ tầng toàn diện |
Tổng kết
Bằng cách kết hợp script bash tối ưu, nén gzip và Cron Job tự động, bạn đã hoàn thiện một lá chắn bảo vệ an toàn cho cơ sở dữ liệu của mình. Hãy nhớ kiểm tra log /var/log/postgres_backup.log định kỳ để đảm bảo các bản sao lưu luôn được tạo ra đều đặn mỗi đêm.



Đăng nhập bằng tài khoản GitHub để đặt câu hỏi hoặc đóng góp ý kiến cho bài viết.