4.5 Dockerボリュームのバックアップとリストア|tarで安全にデータを退避

【第2章】イメージとコンテナの基本操作

Dockerボリュームのバックアップとリストア|tarで安全にデータを退避

4-2 で Named Volume を使ってデータを永続化しました。でもボリューム自体も消える事故はあります——ホストの故障、docker volume rm の誤爆、マシン移行、バージョンアップ前の保険。

この記事では、Docker公式が推奨する「一時コンテナを使った tar バックアップ」パターンと、そのリストア手順をマスターします。

💡 この記事のゴール
① なぜボリュームにバックアップが要るか
② 標準パターン:一時コンテナ + tar でバックアップ
③ リストア手順(既存ボリュームに展開 or 新ボリューム作成)
④ PostgreSQL ボリュームで実戦ハンズオン
⑤ DBは「停止してから」等の本番Tips

目次

  1. なぜボリュームをバックアップする?
  2. 基本パターン:一時コンテナで tar
  3. バックアップ手順
  4. リストア手順
  5. ハンズオン:Postgres ボリュームを退避→復元
  6. 本番運用のTips
  7. DB固有のダンプ併用
  8. まとめ

1. なぜボリュームをバックアップする?

シナリオ バックアップがないとどうなる?
マシン故障・SSD 物理破損 全ボリュームが読めず復旧不能
docker volume prune -a 誤爆 Named volume まで消える
Docker / OS のメジャーアップデート データフォーマット非互換の可能性
開発用データを本番風にコピーしたい バックアップがあれば数秒で別環境に展開
別ホストへの移行 ボリュームを持ち運ぶ手段が必要
⚠️ 「ボリュームがあるから安心」ではない
Named Volume はコンテナの寿命を超えて生き残りますが、ホストそのものが故障したら一緒に消えます。重要データはホスト外(クラウドストレージ・別マシン)へ定期的に退避するのが原則です。

2. 基本パターン:一時コンテナで tar

Dockerには docker volume backup というコマンドはありません。Docker公式が推奨しているのは次のパターンです。

【ボリュームバックアップの王道パターン】
🗄️ バックアップ元
mydata ボリューム
/source にマウント

🛠️ 一時コンテナ
alpine
tar czf を実行
終わったら --rm で自滅

📦 バックアップ出力
ホストの $(pwd)
/backup にマウント
mydata.tar.gz

↑ 軽量イメージ(alpine等)で使い捨てコンテナを立て、ボリュームとホスト側出力ディレクトリの両方をマウントして tar する

3. バックアップ手順

# mydata ボリュームを ./backup/mydata.tar.gz に退避
mkdir -p backup
docker run --rm \
  -v mydata:/source:ro \
  -v "$(pwd)/backup":/backup \
  alpine \
  tar czf /backup/mydata.tar.gz -C /source .

# 確認
ls -lh backup/mydata.tar.gz
部分 役割
--rm コマンド終了後に一時コンテナを自動削除
-v mydata:/source:ro ボリュームを読み取り専用でマウント(誤書込防止)
-v "$(pwd)/backup":/backup ホスト側の出力ディレクトリを bind mount
alpine tar が入っていて軽量(約7MB)
tar czf ... -C /source . 圧縮(c)・gzip(z)・ファイル指定(f)、ディレクトリ変更(-C)して相対パスで tar
💡 -C /source . の意味
tar ファイルには「パス」も記録されます。-C なしだと source/file1 のような形で保存され、リストア時に変なパスができて面倒。-C /source . とすることで、アーカイブ内は ./file1 形式(相対パス)になり、どこにでも展開しやすくなります。

4. リストア手順

バックアップの逆向き——空のボリュームに tar を展開します。

# 1. リストア先のボリュームを用意(新規でもOK、既存でもOK)
docker volume create mydata-restored

# 2. 一時コンテナで tar を展開
docker run --rm \
  -v mydata-restored:/dest \
  -v "$(pwd)/backup":/backup:ro \
  alpine \
  sh -c "cd /dest && tar xzf /backup/mydata.tar.gz"

# 3. 中身の確認(別の一時コンテナで)
docker run --rm -v mydata-restored:/data alpine ls -la /data
⚠️ 既存ボリュームに上書きリストアする場合
mydata-restored が空でない場合、tar x は同名ファイルを上書きしますが、既存のファイルは消さない(差分上書き)。まっさらに戻したいなら、先に sh -c "rm -rf /dest/* && tar xzf ..." のように掃除してから展開します。

5. ハンズオン:Postgres ボリュームを退避→復元

4-2 で使った pgdata ボリュームを実際にバックアップ&リストアしてみます。

5-1. データ投入(準備)

docker volume create pgdata
docker run -d --name db \
  -e POSTGRES_PASSWORD=secret \
  -v pgdata:/var/lib/postgresql/data \
  postgres:16

docker exec -it db psql -U postgres -c "CREATE TABLE users(id SERIAL PRIMARY KEY, name TEXT);"
docker exec -it db psql -U postgres -c "INSERT INTO users(name) VALUES ('Alice'),('Bob');"

5-2. Postgres を「停止してから」バックアップ

# 整合性のため、書き込み中のDBは停止する
docker stop db

# バックアップ
mkdir -p backup
docker run --rm \
  -v pgdata:/source:ro \
  -v "$(pwd)/backup":/backup \
  alpine \
  tar czf /backup/pgdata.tar.gz -C /source .

ls -lh backup/pgdata.tar.gz

# バックアップ完了後、DBを再開
docker start db
⚠️ DBは停止してからバックアップ
Postgres のデータファイルをコピー中に書き込みが入ると、部分的に壊れたアーカイブになる恐れがあります。書き込みが止まる状態を作ってから tar を取るのが基本。どうしても停止できない本番環境では、後述の pg_dump 等の論理バックアップを使います。

5-3. 事故シミュレーション:ボリュームを消してしまう

docker rm -f db
docker volume rm pgdata   # 😱 大事なボリュームを誤削除

docker volume ls
# pgdata が消えている

5-4. バックアップから復元

# 新規ボリュームを作る
docker volume create pgdata

# tar を展開
docker run --rm \
  -v pgdata:/dest \
  -v "$(pwd)/backup":/backup:ro \
  alpine \
  sh -c "cd /dest && tar xzf /backup/pgdata.tar.gz"

# Postgres を再起動して確認
docker run -d --name db \
  -e POSTGRES_PASSWORD=secret \
  -v pgdata:/var/lib/postgresql/data \
  postgres:16

# データ確認
docker exec -it db psql -U postgres -c "SELECT * FROM users;"
#  id | name
# ----+-------
#   1 | Alice
#   2 | Bob
# (2 rows)                     ← 完全復活🎉
✅ 実証完了
ボリューム自体を削除してしまった状況から、tar バックアップだけで元の DB 状態に復元できました。これが最低限の「事故保険」です。

6. 本番運用のTips

ポイント 内容
スケジュール化 cron / systemd timer / CI cronjob で1日1回 tar を作り、S3 等に転送
世代管理 ファイル名に日付を含める:mydata-$(date +%Y%m%d).tar.gz。古いものは自動削除ルールで
オフサイト保管 ホスト故障を想定し、クラウド(S3/GCS/OneDrive)や別マシンへ必ず転送
リストアを定期的に試す バックアップが取れていても、復元できなければ意味がない。年1は模擬復元を
整合性ハッシュ sha256sum mydata.tar.gz > mydata.tar.gz.sha256 を並べて保管
DBはダンプ併用 ボリュームtarは「物理」、pg_dump等は「論理」。両方取るのが最強

7. DB固有のダンプ併用

DBのボリュームtarは「データディレクトリの物理コピー」です。これに加えて、DBネイティブの論理ダンプも取っておくと安心です。

PostgreSQL

# 動作中の Postgres から論理ダンプを取る(停止不要・オンラインバックアップ)
docker exec -t db pg_dumpall -U postgres > backup/db-$(date +%Y%m%d).sql

# リストア
cat backup/db-20260420.sql | docker exec -i db psql -U postgres

MySQL

docker exec -t mysql-db mysqldump -uroot -psecret --all-databases \
  > backup/mysql-$(date +%Y%m%d).sql

cat backup/mysql-20260420.sql | docker exec -i mysql-db mysql -uroot -psecret
💡 物理 vs 論理の使い分け
物理(tarバックアップ):早い・全データ一括・DBバージョンを合わせれば瞬時に復元
論理(pg_dump 等):遅め・SQLテキスト・別DB(別バージョン・別ホスト)への移植可能
本番では両方取るのが定石です。

8. まとめ

押さえどころ 内容
公式コマンドはない 「一時コンテナ + tar」が Docker公式推奨パターン
バックアップ docker run --rm -v vol:/source:ro -v $(pwd)/backup:/backup alpine tar czf /backup/xxx.tar.gz -C /source .
リストア docker run --rm -v vol:/dest -v $(pwd)/backup:/backup:ro alpine sh -c "cd /dest && tar xzf /backup/xxx.tar.gz"
DBは停止する 書き込み中の物理コピーは壊れやすい。停止 or ダンプ併用
オフサイト保管 ホスト故障に備え、別マシン or クラウドへ定期転送
復元演習 「取れていても復元できない」が最悪。定期的に試す
✅ 次のステップ
第4章はこれで終わりです!永続化の4つのピース(エフェメラル理解・Named Volume・Bind Mount・tmpfs・バックアップ)が揃いました。次の第5章 ネットワークでは、コンテナ同士をつなぎ・外から叩くための仕組み(ブリッジ・DNS名前解決・ポートバインディング)を学びます。

参考リンク


Dockerの基礎を動画で体系的に学びませんか?

実務で使う基礎だけを3時間に凝縮。環境構築から丁寧に解説しています。

Udemy Docker入門講座 クーポン割引で講座を見る →

コメント

タイトルとURLをコピーしました