Dockerボリュームのバックアップと復元|named volumeのデータを別サーバーへ移行する実践手順

宮崎智広 この記事の監修:宮崎智広(Linux実務・教育歴20年以上・受講者3,100名超)
HOMELinux技術 リナックスマスター.JP(Linuxマスター.JP)Docker > Dockerボリュームのバックアップと復元|named volumeのデータを別サーバーへ移行する実践手順
「本番サーバーのDockerコンテナを別のサーバーへ移行したい。でもvolume内のDBデータはどうやって持っていけばいい?」
「docker-compose downしたら、MySQLのデータが全部消えた。バックアップはどう取ればいい?」

コンテナを止めてもデータが消えない仕組みがnamed volumeです。しかし、サーバー自体が壊れた場合や誰かがdocker volume rmを実行してしまった場合は、named volumeごとデータが失われます。

この記事では、named volumeをtarアーカイブでバックアップする手順と、別サーバーへの移行・復元の方法を解説します。コンテナを停止してバックアップする安全な方法、停止できない場合のダーティコピー、cronによる定期バックアップ自動化、PostgreSQLの実践例まで体系的にカバーします。

実行環境:Rocky Linux 9.4 / Ubuntu 24.04 LTS、Docker 26.1.x

この記事のポイント

・named volumeのバックアップは docker run --rm -v で一時コンテナを使うのが定石
・本番DBは必ず停止バックアップ。停止できない場合は pg_dump / mysqldump を使う
・別サーバーへの移行は tar + rsync/scp の2ステップで完結する
・cronで夜間に自動バックアップすれば、誤削除・障害時に数分で復元できる


「このままじゃマズい」と感じていませんか?
参考書を開く気力もない、同年代に取り残される不安——
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら

なぜDockerボリュームのバックアップが必要なのか

Dockerのnamed volumeは、コンテナを削除してもデータが消えない設計です。しかし、次のような状況ではnamed volume自体が失われ、復元できなくなります。

誤操作docker volume rmdocker system prune --volumesを誤って実行した
ホスト障害:Dockerが稼働しているLinuxサーバーのディスクが壊れた
サーバー移行:VPSの乗り換えや別AZへの移行でコンテナを新規作成する必要がある

named volumeは物理的には/var/lib/docker/volumes/ボリューム名/_data/に格納されています。このディレクトリをtarで圧縮してバックアップしておけば、どのような状況でも復元できます。

named volumeのバックアップ対象を確認する

1. docker volume lsでボリュームを一覧表示する

まず、現在のDocker環境に存在するボリュームを確認します。

# named volumeの一覧 $ docker volume ls DRIVER VOLUME NAME local myapp_pgdata local myapp_redis_data local wordpress_db_data

DRIVERlocalのものが、通常のnamed volumeです。myapp_pgdataのようにCompose起動時に自動作成されるボリューム名には、プロジェクト名がプレフィックスとして付きます。

2. docker volume inspectでMountpointを確認する

バックアップ対象のボリュームが、ホスト上のどこに格納されているか確認します。

# ボリュームの詳細確認 $ docker volume inspect myapp_pgdata [ { "CreatedAt": "2026-07-15T10:23:45Z", "Driver": "local", "Labels": { "com.docker.compose.project": "myapp", "com.docker.compose.version": "2.27.0", "com.docker.compose.volume": "pgdata" }, "Mountpoint": "/var/lib/docker/volumes/myapp_pgdata/_data", "Name": "myapp_pgdata", "Options": {}, "Scope": "local" } ]

"Mountpoint"が実際のデータ格納パスです。このパスをLinuxのtarで直接アーカイブすることも可能ですが、一時コンテナ(--rm)経由でバックアップするのが推奨手順です。コンテナのファイルシステムマウント状態が正確に再現され、パーミッションの欠損が起きにくいためです。

コンテナを停止してnamed volumeをバックアップする(推奨)

1. バックアップ前にコンテナを停止する

DBデータを扱う場合、コンテナが稼働中だとデータが書き込み途中の状態でコピーされる可能性があります。整合性を保つため、まずコンテナを停止します。

# Composeを使っている場合(upで起動したサービス全体を停止) $ docker compose -f /opt/myapp/docker-compose.yml stop # 個別コンテナを指定して停止 $ docker stop myapp_postgres_1

2. 一時コンテナでtarアーカイブを作成する

named volumeのバックアップには、一時コンテナ(--rm)を使ってvolumeをマウントし、tarで圧縮する手法が定石です。

# バックアップ保存先ディレクトリを作成 $ mkdir -p /backup/docker # named volumeをtarでバックアップ $ docker run --rm -v myapp_pgdata:/data:ro -v /backup/docker:/backup alpine tar czf /backup/myapp_pgdata_20260810.tar.gz -C /data . # 保存確認 $ ls -lh /backup/docker/myapp_pgdata_20260810.tar.gz -rw-r--r-- 1 root root 184M Aug 10 02:00 /backup/docker/myapp_pgdata_20260810.tar.gz

コマンドのポイントを整理します。
-v myapp_pgdata:/data:ro:named volumeを一時コンテナの/dataに読み取り専用でマウント
-v /backup/docker:/backup:ホスト側のバックアップディレクトリをマウント
alpine:軽量なAlpineイメージを一時コンテナとして使用(tarが標準内蔵)
tar czf /backup/xxx.tar.gz -C /data ./data(volumeの中身)をgzip圧縮でアーカイブ化する

3. バックアップ後にコンテナを再起動する

# Composeを使っている場合 $ docker compose -f /opt/myapp/docker-compose.yml start # 個別コンテナの場合 $ docker start myapp_postgres_1

コンテナを止めずにバックアップする(ダーティコピー)

24時間稼働が求められるサービスで「コンテナを止められない」という場合もあります。その場合は、整合性が保証されない「ダーティコピー」としてバックアップを取ります。

# コンテナ稼働中でもバックアップ可能(ただし整合性は保証されない) $ docker run --rm -v myapp_pgdata:/data:ro -v /backup/docker:/backup alpine tar czf /backup/myapp_pgdata_dirty_20260810.tar.gz -C /data .

コンテナを止めない場合の注意点:
DBファイルは整合性が取れない状態でコピーされる可能性があります(トランザクション途中のデータが混入する)
・PostgreSQLやMySQLの場合は、ダーティコピーではなく後述のpg_dump/mysqldumpを使うのが正しい選択です
・静的ファイル(WordPressのアップロードファイル等)であれば、ダーティコピーでも実用上問題ないケースが多いです

Dockerのボリューム設計を実務で体系的に身につけたい方は、Docker実践講座(docker.linuxmaster.jp)をご覧ください。現役エンジニアが現場目線で教えるDockerの基礎から本番設計まで、ハンズオン形式で学べます。
Dockerマスター講座の詳細はこちら >>

バックアップから別サーバーへ復元する手順

1. バックアップファイルを新サーバーへ転送する

scpまたはrsyncでバックアップファイルを新サーバーへ転送します。

# scp で転送(新サーバーのIPが 192.168.10.20 の場合) $ scp /backup/docker/myapp_pgdata_20260810.tar.gz user@192.168.10.20:/backup/ # rsync を使う場合(差分転送・再開可能) $ rsync -avz --progress /backup/docker/myapp_pgdata_20260810.tar.gz user@192.168.10.20:/backup/

2. 新サーバーでnamed volumeを作成して復元する

新サーバー側で作業します。ボリュームを先に作成してから、tarアーカイブを展開します。

# 新サーバー側の作業 # 同名のnamed volumeを事前に作成する $ docker volume create myapp_pgdata # 一時コンテナでtarを展開してvolumeへ復元 $ docker run --rm -v myapp_pgdata:/data -v /backup:/backup alpine tar xzf /backup/myapp_pgdata_20260810.tar.gz -C /data # 復元確認(ファイルが展開されているか確認) $ docker run --rm -v myapp_pgdata:/data:ro alpine ls -la /data total 44 drwx------ 19 systemd-coredump root 4096 Aug 10 01:55 . drwxr-xr-x 1 root root 4096 Aug 10 02:05 .. drwx------ 5 systemd-coredump root 4096 Aug 10 01:55 base drwx------ 2 systemd-coredump root 4096 Aug 10 01:55 global drwx------ 2 systemd-coredump root 4096 Aug 10 01:55 pg_commit_ts

3. コンテナを起動して動作確認する

# 新サーバーでdocker compose up $ docker compose -f /opt/myapp/docker-compose.yml up -d # PostgreSQLへ接続してデータを確認 $ docker compose exec postgres psql -U postgres -c "\l" $ docker compose exec postgres psql -U postgres -d mydb -c "SELECT count(*) FROM users;" count ------- 1234 (1 row)

cronで定期バックアップを自動化する方法

手動バックアップだけでは人的ミスのリスクが残ります。cronで夜間に自動バックアップするスクリプトを組みましょう。

# /opt/scripts/docker-volume-backup.sh として保存 #!/bin/bash set -euo pipefail BACKUP_DIR="/backup/docker" DATE=$(date +%Y%m%d_%H%M%S) COMPOSE_FILE="/opt/myapp/docker-compose.yml" VOLUME_NAME="myapp_pgdata" RETAIN_DAYS=7 mkdir -p "${BACKUP_DIR}" # コンテナを一時停止 docker compose -f "${COMPOSE_FILE}" stop # バックアップ実行 docker run --rm -v "${VOLUME_NAME}:/data:ro" -v "${BACKUP_DIR}:/backup" alpine tar czf "/backup/${VOLUME_NAME}_${DATE}.tar.gz" -C /data . # コンテナを再起動 docker compose -f "${COMPOSE_FILE}" start # 7日より古いバックアップを削除 find "${BACKUP_DIR}" -name "${VOLUME_NAME}_*.tar.gz" -mtime +"${RETAIN_DAYS}" -delete echo "[$(date)] Backup completed: ${BACKUP_DIR}/${VOLUME_NAME}_${DATE}.tar.gz"

スクリプトに実行権限を付与してcronに登録します。

# 実行権限付与 $ chmod 755 /opt/scripts/docker-volume-backup.sh # crontabを編集(rootで実行) $ sudo crontab -e # 毎日午前2時にバックアップ実行(結果をログに記録) 0 2 * * * /opt/scripts/docker-volume-backup.sh >> /var/log/docker-backup.log 2>&1

PostgreSQLボリュームのバックアップ実践例

PostgreSQLのデータはDB固有の内部形式で格納されているため、tarコピーだけでは復元に失敗するケースがあります。特にPostgreSQLのメジャーバージョンが異なる環境への移行ではpg_dumpを使ったSQLダンプ方式が確実です。

1. pg_dumpでSQLダンプを取得する

docker compose execを使えば、コンテナを停止せずにSQLダンプを取得できます。

# PostgreSQLコンテナからSQLダンプを取得(コンテナ稼働中でも可) $ docker compose exec postgres pg_dump -U postgres -Fc mydb > /backup/docker/mydb_20260810.dump # gzip 形式で保存する場合 $ docker compose exec postgres pg_dump -U postgres mydb | gzip > /backup/docker/mydb_20260810.sql.gz # バックアップサイズ確認 $ ls -lh /backup/docker/mydb_20260810.dump -rw-r--r-- 1 user user 42M Aug 10 02:05 /backup/docker/mydb_20260810.dump

-FcはPostgreSQLのカスタム形式で、pg_restoreで並列リストアが可能です。

2. 別サーバーのPostgreSQLへリストアする

# ダンプファイルを新サーバーへ転送 $ scp /backup/docker/mydb_20260810.dump user@192.168.10.20:/backup/ # 新サーバーでPostgreSQLコンテナを起動(DBは空の状態で) $ docker compose up -d postgres # pg_restoreでリストア(-Fcカスタム形式の場合) $ cat /backup/mydb_20260810.dump | docker compose exec -T postgres pg_restore -U postgres -d mydb # gzip形式の場合は gunzip で展開しながらパイプ $ gunzip -c /backup/mydb_20260810.sql.gz | docker compose exec -T postgres psql -U postgres -d mydb # データ確認 $ docker compose exec postgres psql -U postgres -d mydb -c "SELECT count(*) FROM users;"

トラブルシュート・よくある失敗

「Permission denied」でtarが失敗する

named volume内のファイルがrootまたは特定のUIDで所有されている場合、alpineコンテナ内でアクセス拒否になることがあります。

# --user rootを明示してtarを実行する $ docker run --rm --user root -v myapp_pgdata:/data:ro -v /backup/docker:/backup alpine tar czf /backup/myapp_pgdata_20260810.tar.gz -C /data .

復元後にPostgreSQLが起動しない(データ形式の不一致)

tarコピーでPostgreSQLを復元した場合、DBのメジャーバージョンが異なるとデータ形式の互換性問題が起きます。バージョンをまたぐ移行は必ずpg_dump/pg_restoreを使用してください。

また、PostgreSQLのページサイズ(デフォルト8KB)が変更されている環境では復元に失敗することがあります。移行元と移行先のイメージバージョンが同じであることを確認してから復元してください。

volumeが見つからないとエラーが出る

# エラー例 Error response from daemon: invalid mount config for type "volume": no such volume: myapp_pgdata # 対処:volumeを先に作成してから復元コマンドを実行する $ docker volume create myapp_pgdata $ docker run --rm -v myapp_pgdata:/data -v /backup:/backup alpine tar xzf /backup/myapp_pgdata_20260810.tar.gz -C /data

本記事のまとめ

Dockerのnamed volumeバックアップと復元・移行の手順をまとめます。
やりたいこと コマンド・手順
ボリューム一覧を確認する docker volume ls
ボリュームの格納先を確認する docker volume inspect ボリューム名
named volumeをtarでバックアップ docker run --rm -v ボリューム名:/data:ro -v /backup:/backup alpine tar czf /backup/xxx.tar.gz -C /data .
tarから復元する docker run --rm -v ボリューム名:/data -v /backup:/backup alpine tar xzf /backup/xxx.tar.gz -C /data
PostgreSQLのSQLダンプを取得する docker compose exec postgres pg_dump -U postgres -Fc mydb > backup.dump
SQLダンプからリストアする cat backup.dump | docker compose exec -T postgres pg_restore -U postgres -d mydb
cronで定期バックアップを自動化する シェルスクリプト化してsudo crontab -eで登録
tarコマンドの詳しい使い方はtar コマンドの実用例も参考にしてください。圧縮アーカイブの展開方法についてはtar.bz2 の解凍方法も合わせてご覧ください。

Dockerボリューム管理を現場で使いこなすには、Linux基盤の理解が土台になります

named volumeのバックアップはLinuxのtarコマンドとファイルシステムの知識が基礎です。/var/lib/docker/volumes/の構造やMountpointの意味を理解しておくと、障害時の復旧が格段に速くなります。
現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、『Linuxサーバー構築入門マニュアル(図解60P)』を完全無料でプレゼントしています。

「独学の時間がもったいない」「プロから直接、現場の技術を最短で学びたい」という本気の方には、2日で実務レベルのスキルが身につく【初心者向けハンズオンセミナー】も開催しています。

無料メルマガで学習を続ける

Linuxの実践スキルをメールで毎週お届け。
登録は30秒、解除もいつでも可。

登録無料・いつでも解除できます

暗記不要・1時間後にはサーバーが動く

3,100名以上が実践した「型」を無料で公開中

プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。

姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら

Linux無料マニュアル(図解60P) 名前とメールで30秒登録
宮崎 智広

この記事を書いた人

宮崎 智広(みやざき ともひろ)

株式会社イーネットマーキュリー代表。現役のLinuxサーバー管理者として20年以上の実務経験を持ち、これまでに累計3,100名以上のエンジニアを指導してきたLinux教育のプロフェッショナル。「現場で本当に使える技術」を体系的に伝えることをモットーに、実践型のLinuxセミナーの開催や無料マニュアルの配布を通じてLinux人材の育成に取り組んでいる。

趣味は、キャンプにカメラ、トラウト釣り。好きな食べ物は、ラーメンにお酒。休肝日が作れない、酒量を減らせないのが悩み。最近、ドラマ「フライトエンジェル」を観て涙腺が崩壊しました。