DockerのボリュームをCLIでバックアップ・復元する
最近色々セルフホスティングでコンテナ動かしているため、バックアップの必要が出てきた。ので、その内容と実際の手順についてメモする。
ボリュームのバックアップは何をやるのか
概要
まずDockerのボリュームのバックアップとはつまり何をすることなのかについて。これは公式の「Back Up and Share Docker Volumes with This Extension | Docker」を読むとよいのだが、つまりは以下のスニペットに帰結する。
docker run --rm \
-v "$VOLUME_NAME":/backup-volume \
-v "$(pwd)":/backup \
busybox \
tar -zcvf /backup/my-backup.tar.gz /backup-volume
このコードの詳細な解説はChatGPTに譲るが、まぁ要はバックアップを作るためのコンテナを作成し、ホストマシンにデータをコピーしている形だ。復元はこれの逆をやると良い。DBなんかは通常dumpのユーティリティがあるが、記事によればDockerの場合はこれでまるごとコピーするほうが良いとのことだ。
ChatGPTによるコードの解説
このコマンドは、Dockerを使って簡単にバックアップを作成するための手順です。以下に各部分の解説を行います。
docker run --rm:
docker run は Docker コンテナを実行するコマンドです。--rm は、コンテナが終了した後にそのコンテナを自動的に削除するオプションです。これにより、バックアップが完了した時点で不要なコンテナが残らないようになります。
-v "$VOLUME_NAME":/backup-volume:
-v オプションは、ホストマシンとコンテナ間でボリュームをマウントするためのものです。$VOLUME_NAME はバックアップしたい Docker ボリュームの名前を指します。これがコンテナ内の /backup-volume ディレクトリにマウントされます。
-v "$(pwd)":/backup:
こちらも -v オプションですが、ホストマシンの現在の作業ディレクトリ($(pwd) で取得される)をコンテナ内の /backup ディレクトリにマウントしています。このディレクトリにバックアップファイルを保存します。
busybox:
これは Docker イメージの名前です。busybox は非常に軽量な Linux ベースのイメージで、基本的なユーティリティ(tar など)を含んでいます。このコンテナが一時的に起動され、バックアップ処理を実行します。
tar -zcvf /backup/my-backup.tar.gz /backup-volume:
tar コマンドで圧縮ファイル(.tar.gz)を作成しています。
-
-z
: gzip 形式で圧縮するオプション。 -
-c
: 新しいアーカイブを作成するオプション。 -
-v
: 詳細な出力(アーカイブ中のファイル名を表示する)。 -
-f /backup/my-backup.tar.gz
: 出力するファイル名を指定しています。この場合は、/backup/my-backup.tar.gz という名前で圧縮ファイルが作成されます。 -
/backup-volume
: アーカイブ対象のディレクトリで、マウントされたボリュームです。
まとめ:
このコマンドは、指定した Docker ボリューム($VOLUME_NAME)を tar コマンドで圧縮し、現在のディレクトリに my-backup.tar.gz という名前のバックアップファイルを保存します。
拡張機能について
これを実行するものとして、v4.29.0以降のDocker Desktopでは拡張機能として公式で提供されている(「Volumes Backup & Share - Docker Extension | Docker Hub」)。上の記事によれば、この拡張機能はボリュームをアタッチしているコンテナを調べて一時停止し、再起動するところまで含めてやっているようだ。
便利な拡張機能だが、もうすぐdeprecatedになる見込みで、どうやらこの機能は近日中に公式で提供されるものらしい。その際、手動バックアップは普通に使えるが、スケジューリングはサブスクプラン専用機能になる模様(Volumes | Docker Docss)。
CLIで無料でやりたい
バックアップはスケジューリングしてやりたいし、お金はないし、そもそもVPSとかDocker Desktopない環境でも使いたい。ということで、フツーにスクリプト書くかなと思った。
やっていることは単純なので、全部自分で書いてもよかったが、上記記事の中でも紹介されている https://github.com/BretFisher/docker-vackup がシンプルなシェルスクリプトでそのまま使えて便利そうだったので、これを使うことにした。
インストール手順はREADME.md見ればよいが一応書いておく。LinuxとMacならそのまんま。
sudo curl -sSL https://raw.githubusercontent.com/BretFisher/docker-vackup/main/vackup -o /usr/local/bin/vackup && sudo chmod +x /usr/local/bin/vackup
このスクリプトは特にコンテナの停止などしていないようなので、ユースケースから必要なら停止する処理を入れたスクリプト書くべし。
vackupを使ったバックアップと復元
いざという時に使えるように、練習する。
テスト用コンテナのセットアップ
テスト用のDockerネットワークを作成
docker network create test-network
MySQLコンテナを起動し、データを保存するためのVolumeを作成
docker run -d --name mysql-test \
--network test-network \
-e MYSQL_ROOT_PASSWORD=rootpassword \
-e MYSQL_DATABASE=testdb \
-v mysql-data:/var/lib/mysql \
mysql:latest
データの投入
MySQLコンテナに接続
docker exec -it mysql-test mysql -uroot -prootpassword
データベース内にテーブルを作成し、データを挿入。SELECTクエリの結果に、バックアップ時に挿入したデータ (id = 1, data = 'backup test') が表示されることを確認する。
USE testdb;
CREATE TABLE test_table (id INT, data VARCHAR(100));
INSERT INTO test_table (id, data) VALUES (1, 'backup test');
SELECT * FROM test_table
バックアップの実行
vackup export mysql-data mysql-data.tar.gz
コンテナとボリュームの削除
docker stop mysql-test
docker rm mysql-test
docker volume rm mysql-data
コンテナを再作成
docker run -d --name mysql-test \
--network test-network \
-e MYSQL_ROOT_PASSWORD=rootpassword \
-e MYSQL_DATABASE=testdb \
-v mysql-data:/var/lib/mysql \
mysql:latest
MySQLコンテナに接続
docker exec -it mysql-test mysql -uroot -prootpassword
データが空であることを確認する。
USE testdb;
SELECT * FROM test_table
復元
コンテナの停止。
docker stop mysql-test
ボリュームの復元
vackup import mysql-test.tar.gz mysql-test
MySQLコンテナを起動して接続
docker start mysql-test
docker exec -it mysql-test mysql -uroot -prootpassword
データの確認。
USE testdb;
SELECT * FROM test_table
SELECTクエリの結果に、バックアップ時に挿入したデータ (id = 1, data = 'backup test') が表示されることを確認する。
復元OK。
以上。
Discussion