Dockerを使用していると、コンテナではなく ボリューム に保存されたデータをバックアップしたり、テストのために別のボリュームにコピーしたりする必要がよく発生します。
単純に docker cp コマンドを考えることができますが、このコマンドは コンテナのファイルシステム とホスト間のコピーのみをサポートし、Dockerが管理するボリュームには直接アクセスできません。
この記事では、Dockerボリュームをコピーする正しい方法を紹介します。ただ単にコマンドを列挙するのではなく、 ‘なぜ’この方法を使うべきなのか という原理に焦点を当てます。この原理を理解すれば、コマンドを暗記せずとも必要な時に自然に応用できるでしょう。
核心原理は簡単です。
Dockerボリュームを操作する最も安全で‘Dockerらしい’方法は、該当ボリュームにアクセスできる‘一時コンテナ’を橋渡し(bridge)として活用することです。
1. 既存のボリュームを新しいボリュームにコピーする (Volume-to-Volume)
最も一般的なシナリオです。稼働中の db_data ボリュームをテスト用の db_data_test ボリュームにコピーしたい場合があります。
🤔 WHY: なぜ一時コンテナを使うのか?
Dockerボリュームはホストファイルシステムのどこか(/var/lib/docker/volumes/...など)に保存されますが、Dockerデーモンがこのパスを管理します。このパスに直接アクセスして cp コマンドを使用することは推奨されておらず、権限の問題やデータの整合性の問題を引き起こす可能性があります。
代わりに、私たちは 2つのボリュームを同時にマウントした 一時コンテナを実行します。
-
コンテナが
/fromパスに 元のボリューム(source_volume)をマウントします。 -
コンテナが
/toパスに 対象ボリューム(new_volume)をマウントします。 -
コンテナは起動するとすぐに
/fromのすべてのデータを/toにコピーする簡単なLinuxコマンド(cpまたはtar)を実行します。 -
コマンドが終了すると、コンテナは自動的に削除されます(
--rmオプション)。
このコンテナはデータコピーのための‘ツール’としてのみ使用されます。
🚀 HOW: コマンドの例
source_data ボリュームのデータを target_data ボリュームにコピーする例です。
- テスト用ボリューム作成 (オプション)
docker volume create source_data
docker volume create target_data
# (source_dataにデータがあると仮定します。)
- 一時コンテナを利用したコピー
docker run --rm \
-v source_data:/from \
-v target_data:/to \
alpine \
sh -c "cp -a /from/. /to/"
💡 コマンド解説
-
docker run --rm:--rmフラグはコンテナが作業を完了し終了すると 即座にコンテナを削除 することを意味します。短期的な作業に必須です。 -
-v source_data:/from:source_dataボリュームをコンテナ内部の/fromディレクトリにマウントします。 -
-v target_data:/to:target_dataボリュームをコンテナ内部の/toディレクトリにマウントします。 -
alpine:cpやshなどの基本ユーティリティを含みつつも、非常に軽量なalpineLinuxイメージを使用します。 -
sh -c "...": alpineコンテナが起動するときに実行するコマンドです。 -
cp -a /from/. /to/:-
-a(archive): このフラグが核心です。単なるコピー(cp -r)ではなく 所有権や権限、タイムスタンプなどすべての属性を保持して コピーします。データベースファイルなど敏感なデータを扱う際に非常に重要です。 -
/from/.:/fromディレクトリではなく、/from内部のすべてのコンテンツ (隠しファイルも含む)を意味します。
-
2. ボリュームデータをホストファイルシステムにコピーする (バックアップ)
ボリュームのデータをローカルマシンやサーバーの特定のディレクトリに .tar ファイルなどでバックアップしたいときに使用します。
🤔 WHY: どのように機能するのか?
原理は1番と同じです。ただし、対象が‘Dockerボリューム’ ではなく‘ホストディレクトリ’に変わっただけです。
Dockerはホストの特定のディレクトリをコンテナにマウントする バインドマウント(Bind Mount) 機能をサポートしています。
-
コンテナが
/dataパスに 元のボリューム(source_volume)をマウントします。 -
コンテナが
/backupパスに ホストの特定ディレクトリ($(pwd)/backup)をマウントします。 -
コンテナは
/dataの内容を/backupディレクトリにコピー(または圧縮)します。 -
この作業はコンテナ内で行われますが、
/backupは実際のホストディレクトリと接続されているため、結果はホストに残ります。
🚀 HOW: コマンドの例
source_data ボリュームのデータを現在の位置($(pwd))の backup ディレクトリにコピーします。
# ホストにバックアップを取るためのディレクトリを作成
mkdir -p $(pwd)/backup
docker run --rm \
-v source_data:/data:ro \
-v $(pwd)/backup:/backup \
alpine \
cp -a /data/. /backup/
💡 コマンド解説
-
-v source_data:/data:ro::ro(Read-Only) フラグを追加しました。バックアップはデータを読むだけで済むため、誤って元のボリュームを修正するのを防ぐために 読み取り専用でマウント することが推奨されます。 -
-v $(pwd)/backup:/backup:source_data(ボリューム名)とは異なり、/で始まるか$(pwd)(現在のパス)を含む 絶対/相対パスはホストのディレクトリを指します。
3. 重要なコピーのヒント (Tips)
ヒント 1: tar を使用した効率的なコピー (圧縮バックアップ)
cp コマンドの代わりに tar を使用すると、いくつかの利点があります。特にデータをアーカイブファイル(.tar.gz)として一度にまとめてバックアップする際に便利です。
Volume-to-Volume (tar使用)
cpよりも早くなる可能性があり、特にファイルが多い場合に効率的です。
docker run --rm \
-v source_data:/from \
-v target_data:/to \
alpine \
sh -c "cd /from && tar -cf - . | (cd /to && tar -xf -)"
-
cd /from && tar -cf - .:/fromに移動し、現在のディレクトリ(.)の内容をtarでまとめて(c)ファイル(f)ではなく標準出力(-)に送ります。 -
| (cd /to && tar -xf -): パイプ(|)で標準出力を受け取り、/toディレクトリでtarの圧縮を解きます(x)。
Volume-to-Host (圧縮バックアップ)
source_data ボリュームの内容を backup.tar.gz ファイルとして圧縮してホストに保存します。
docker run --rm \
-v source_data:/data:ro \
-v $(pwd):/backup \
alpine \
tar -czf /backup/backup.tar.gz -C /data .
-
tar -czf /backup/backup.tar.gz ...:c(生成)、z(gzip圧縮)、f(ファイルとして)/backup/backup.tar.gzファイルを作成します。 -
-C /data .: この部分が重要です。 /data ディレクトリにまず移動(Change directory)した後、その中のすべてを圧縮します。こうすることで tar ファイル内部に余分な /data パスが含まれません。
ヒント 2: ホストファイルをボリュームに復元する
バックアップの逆、つまり復元も同じ原理を使います。 cp の方向を逆にすれば良いです。
# $(pwd)/backup ディレクトリのデータを new_data ボリュームに復元
docker run --rm \
-v new_data:/data \
-v $(pwd)/backup:/backup:ro \
alpine \
cp -a /backup/. /data/
まとめ
Dockerボリュームを扱う核心は “コンテナをツールとして使う” という考え方です。ホストで直接ボリュームファイルを触るのではなく、必要なボリュームとディレクトリを装着した一時コンテナを実行してその中で安全に cp や tar などの標準Linuxコマンドを実行することです。
この原理さえ覚えていれば、どんな状況でもボリュームデータを自由にコピー、バックアップ、復元できるようになるでしょう。
コメントはありません。