67 lines
2.3 KiB
Bash
Executable File
67 lines
2.3 KiB
Bash
Executable File
#!/bin/bash
|
|
# tver DBバックアップ(Synology ds923p / DSMタスクスケジューラで日次実行)
|
|
#
|
|
# 配置先: /volume1/docker/tver-db/backup-db.sh
|
|
# DSM設定: コントロールパネル → タスクスケジューラ → 作成
|
|
# → スケジュールされたタスク → ユーザー定義のスクリプト
|
|
# ユーザーはroot、実行周期は毎日とする。
|
|
# 実行コマンド: bash /volume1/docker/tver-db/backup-db.sh
|
|
#
|
|
# コンテナ内のpg_dumpを使い、サーバーとクライアントのバージョンを合わせる。
|
|
# PostgreSQLのローカル接続を使うため、DBパスワードはスクリプトへ書かない。
|
|
|
|
set -euo pipefail
|
|
|
|
BACKUP_DIR="${BACKUP_DIR:-/volume1/backups/tver}"
|
|
KEEP_DAYS="${KEEP_DAYS:-14}"
|
|
CONTAINER="${CONTAINER:-tver-postgres}"
|
|
DB_USER="${DB_USER:-tver}"
|
|
DB_NAME="${DB_NAME:-tver}"
|
|
DOCKER="${DOCKER:-$(command -v docker || printf '/usr/local/bin/docker')}"
|
|
STAMP="${STAMP:-$(date +%Y%m%d_%H%M%S)}"
|
|
OUT="${BACKUP_DIR}/tver_${STAMP}.sql.gz"
|
|
RAW_TMP="${BACKUP_DIR}/.tver_${STAMP}.$$.sql"
|
|
GZ_TMP="${OUT}.tmp.$$"
|
|
|
|
case "$KEEP_DAYS" in
|
|
''|*[!0-9]*)
|
|
echo "ERROR: KEEP_DAYS must be a non-negative integer: $KEEP_DAYS" >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
mkdir -p "$BACKUP_DIR"
|
|
umask 077
|
|
|
|
cleanup() {
|
|
rm -f "$RAW_TMP" "$GZ_TMP"
|
|
}
|
|
trap cleanup EXIT
|
|
|
|
# 先に非圧縮の一時ファイルへ出し、pg_dump成功と空でないことを確認する。
|
|
"$DOCKER" exec "$CONTAINER" pg_dump -U "$DB_USER" -d "$DB_NAME" > "$RAW_TMP"
|
|
if [[ ! -s "$RAW_TMP" ]]; then
|
|
echo "ERROR: dump is empty" >&2
|
|
exit 1
|
|
fi
|
|
|
|
gzip -9 -c "$RAW_TMP" > "$GZ_TMP"
|
|
if [[ ! -s "$GZ_TMP" ]]; then
|
|
echo "ERROR: compressed dump is empty" >&2
|
|
exit 1
|
|
fi
|
|
# 完成ファイルは上書きしない。同名が同時に作られても、ハードリンクの
|
|
# 作成に成功した一方だけを公開する。一時ファイルは同じディレクトリに
|
|
# あるため同一ファイルシステム内でリンクできる。
|
|
if ! ln "$GZ_TMP" "$OUT"; then
|
|
echo "ERROR: backup already exists or could not be published: $OUT" >&2
|
|
exit 1
|
|
fi
|
|
rm -f "$GZ_TMP" "$RAW_TMP"
|
|
|
|
# KEEP_DAYS日より古い完了済みバックアップだけを削除する。
|
|
find "$BACKUP_DIR" -name 'tver_*.sql.gz' -type f -mtime "+$KEEP_DAYS" -delete
|
|
|
|
SIZE_BYTES="$(wc -c < "$OUT" | tr -d '[:space:]')"
|
|
echo "OK: $OUT ($SIZE_BYTES bytes)"
|