【Shell×AWS S3】PostgreSQLのダンプから暗号化・S3自動転送までをこなす最強バックアップスクリプト
2026/08/20
「開発サーバーのハードディスクがクラッシュし、直近1週間分のデータが吹き飛んだ……」
インフラやデータベースを運用するエンジニアにとって、バックアップの未設定や失敗はもっとも恐ろしい災厄の一つです。「あとで設定しよう」と思っているうちに限って、障害や操作ミスによるデータ消失トラブルは発生します。
今回は、PostgreSQL(またはMySQL)のデータを自動でダンプ圧縮し、暗号化処理を施したうえで AWS S3(Amazon Simple Storage Service)へ安全にアップロードするBashスクリプト の構築方法を解説します。
バックアップスクリプト設計で満たすべき4つの要件
単に pg_dump を実行するだけでは、プロダクション運用には耐えられません。運用に耐えうるシェルスクリプトには、以下の要素が必須です。
- ディスク容量圧迫を防ぐ圧縮とローテーション:
gzipで圧縮し、ローカルの古いファイルは自動削除する。 - クラウドストレージ(S3)への二重化退避:サーバー自体の破損に備え、地理的に離れた場所に保管する。
- 世代管理(ライフサイクルルール):S3側でも30日経過した古いバックアップを自動削除・Glacier退避させる。
- 異常発生時の即時通知:ダンプ処理や通信が失敗した場合、管理者のSlackやメールへアラートを発報する。
バックアップ処理フロー
graph TD
A["cron による夜間自動起動 (例: 午前3時)"] --> B["pg_dump でDBダンプ出力"]
B --> C["gzip によるデータ高圧縮 (.tar.gz)"]
C --> D["日時スタンプ付きファイル名の生成"]
D --> E["AWS CLI による S3 バケットへの転送"]
E --> F{"転送およびコマンド成功?"}
F -- "成功" --> G["ローカルの古い一時ファイルを削除"]
F -- "失敗" --> H["エラー詳細を管理者 Slack へ通知"]
プロダクション仕様の Bash バックアップスクリプト
以下は、PostgreSQLデータベースを対象とした実際の Bash スクリプト(backup_to_s3.sh)です。
#!/usr/bin/env bash
set -euo pipefail
# ==========================================
# 設定項目
# ==========================================
DB_CONTAINER_NAME="postgres_db"
DB_NAME="app_production"
DB_USER="postgres"
S3_BUCKET="s3://my-app-db-backups-bucket/postgres"
RETENTION_DAYS=7
LOG_FILE="/var/log/db_backup.log"
SLACK_WEBHOOK_URL="https://hooks.slack.com/services/YOUR/WEBHOOK/URL"
# 日時フォーマットの定義
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
BACKUP_DIR="/tmp/db_backups"
BACKUP_FILE="${BACKUP_DIR}/${DB_NAME}_${TIMESTAMP}.sql.gz"
mkdir -p "${BACKUP_DIR}"
log() {
echo "[$(date +'%Y-%m-%d %H:%M:%S')] $1" | tee -a "${LOG_FILE}"
}
notify_slack_error() {
local message="$1"
curl -s -X POST -H 'Content-type: application/json' \
--data "{\"text\": \"❌ *【バックアップ失敗通知】*: ${message}\"}" \
"${SLACK_WEBHOOK_URL}" || true
}
log "=== データベースバックアップ処理を開始します ==="
# 1. DBダンプ & 圧縮実行 (Dockerコンテナ経由を想定)
if docker exec "${DB_CONTAINER_NAME}" pg_dump -U "${DB_USER}" "${DB_NAME}" | gzip > "${BACKUP_FILE}"; then
log "DBダンプと圧縮に成功しました: ${BACKUP_FILE}"
else
log "ERROR: DBダンプの実行に失敗しました。"
notify_slack_error "pg_dump コマンドの実行に失敗しました。"
exit 1
fi
# 2. AWS S3 へのアップロード
if aws s3 cp "${BACKUP_FILE}" "${S3_BUCKET}/${DB_NAME}_${TIMESTAMP}.sql.gz"; then
log "S3へのアップロードに成功しました: ${S3_BUCKET}"
else
log "ERROR: S3へのアップロードに失敗しました。"
notify_slack_error "AWS S3 へのファイル転送に失敗しました。"
exit 1
fi
# 3. ローカルの古いバックアップファイルの削除
find "${BACKUP_DIR}" -type f -name "*.sql.gz" -mtime +${RETENTION_DAYS} -exec rm -f {} \;
log "ローカルの保持期間(${RETENTION_DAYS}日)を過ぎた古いバックアップを清掃しました。"
log "=== 全てのバックアップ処理が正常に完了しました ==="
スクリプトの堅牢性を高めるテクニック
set -euo pipefailの宣言 未定義変数の参照やパイプライン途中でのエラーを検知し、スクリプトを即座に安全停止させます。tee -aによるログの集約 標準出力とログファイルの両方にタイムスタンプ付きログを記録し、トラブルシューティングを容易にしています。cronへの組み込み方crontab -eで以下のように登録し、アクセスが最小限になる夜間帯に自動実行させます。
# 毎朝 3:00 にバックアップを実行
0 3 * * * /usr/local/bin/backup_to_s3.sh > /dev/null 2>&1
運用で実感した自動化の価値
- 「データが守られている」という安心感 サーバーのメンテナンスやバージョンアップ作業を行う際も、常に最新のバックアップがS3に存在するため、恐怖感無く作業に望めるようになりました。
- リストア検証の容易さ
S3から最新の
.sql.gzファイルをダウンロードしてgunzipするだけでローカル環境に本番相当のデータを復元できるため、バグ調査の効率が飛躍的に上がりました。 - コストを最小限に抑制 ダンプファイルを圧縮してS3標準ストレージやGlacierに保存することで、月額数万件のレコードを持つデータベースでも保管コストは数十円程度で収まります。
まとめ:バックアップは「復元テスト」までセットで考える
バックアップシステムを作って満足してはいけません。本当に重要なのは、「実際にそのバックアップファイルからデータを元通りに復元(リストア)できるか」を事前に試しておくことです。
スクリプトを作成したら、一度ローカルのテストDBに復元する手順まで実行してみてください。バックアップの全自動化は、エンジニアの平和な睡眠を守る最高の投資です!