注意:この方法のみでは自動採番とデータベース中の値がかみ合わず次のINSERT時にエラーが発生します。
Docker にはボリュームというデータの永続化を行う仕組みがあります。ボリュームを使い、同じボリュームとマウントの組み合わせを持つコンテナは何度作り直しても、どう作ってもファイルシステム中に共有する部分を持ちます。これはコンテナ毎にローカルのファイルシステムを持ち、コンテナ外部のファイルシステムの一部をマウントしているといった具合です。
ボリュームの利用 | Docker ドキュメント
MySQL コンテナの生成定義時にボリュームを使ってデータベースを永続しない場合、MySQL コンテナを作り直すたびにデータベースの中身が初期化されます。開発中は毎回初期化の方が都合の良い時もありますが、実運用中はまずそんなことありません。お客様のデータが不意に消える可能性を増やしているのみで、この場合は積極的に永続化すべきです。
とはいえ既にボリュームによる永続化が動作していない状態で運用されているコンテナをボリュームを持つコンテナに作り直そうとした場合、作り直した瞬間に元々のコンテナにあったデータが消えるというジレンマが起きます。MySQL を例に主にこのコンテナ作り直しのために用いられるバックアップと復元方法を紹介します。
実行コマンドをざっと並べると次です。
# 既存コンテナ中のファイルをローカルにコピー docker cp mysqlコンテナ名:var/lib/mysql ./mysqlBackup # データベース部を永続化したコンテナを作り直し ## docker-compose の場合 ##### docker-compose.yml ############# # version: '3.1' # services: # db: # image: mysql # command: --default-authentication-plugin=mysql_native_password # restart: always # environment: # MYSQL_ROOT_PASSWORD: example # volumes: # データベースの永続化 # - ./mysql-store:/var/lib/mysql # volumes: # mysql-store: ###################################### docker-compose up --force-recreate mysql ## docker の場合 docker run -v some-mysql-store:/var/lib/mysql --name mysqlコンテナ名 -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:8.0 # 既存コンテナ同様の空テーブルの作成を行う。方法は自由 # # Laravel # docker-compose exec app php artisan migrate # # mysqldump これが使えるならそもそもファイル経由で復元しなくても良さそう # docker-compose exec mysql mysqldump -u root -p -d --databases 復元対象DB -n > ddl.sql ### 新しいコンテナの MySQL のコンソールに入って実行ここから ### SET foreign_key_checks = 0;# TABLESPACEの操作を行うために実行 ALTER TABLE バックアップしたいテーブルの名前その1 DISCARD TABLESPACE; ALTER TABLE バックアップしたいテーブルの名前その2 DISCARD TABLESPACE; ... ALTER TABLE バックアップしたいテーブルの名前最後 DISCARD TABLESPACE; ### 新しいコンテナの MySQL のコンソールに入って実行ここまで ### # ローカルのバックアップファイルをコンテナ内にコピー # docker cp ./mysqlBackUp mysqlコンテナ名:var/lib/mysql # コンテナ内にコピーしたファイルを mysql が扱えるように所有者を変更 # docker exec alc_0707_mysql_1 chown mysql:mysql -R /var/lib/mysql/alloc ### 新しいコンテナの MySQL のコンソールに入って実行ここから ### ALTER TABLE 復元したいテーブルの名前その1 IMPORT TABLESPACE; ALTER TABLE 復元したいテーブルの名前その2 IMPORT TABLESPACE; ... ALTER TABLE 復元したいテーブルの名前最後 IMPORT TABLESPACE; SET foreign_key_checks = 1; ### 新しいコンテナの MySQL のコンソールに入って実行ここまで ###
簡単にいうと MySQL の中身をローカルに出力、コンテナを作り直し、ローカルに出力した MySQL の中身を入れ直し、といった具合です。MySQL なので上記の様にいくらか処理をしていますが、単にファイルシステムで完結しているもののバックアップと復元ならばdocker cp
コマンドの操作だけで十分です。
それぞれのコマンドを詳細に解説すると以下です。
# 既存コンテナ中のファイルをローカルにコピー docker cp mysqlコンテナ名:/var/lib/mysql ./mysqlBackup
コメントの通り、コンテナ中のファイルをローカルにコピーするコマンドです。
cp — Docker-docs-ja 19.03 ドキュメント
docker cp | Docker Documentation
バックアップしたいファイルがある場所を探しておいて(MySQL ならば /var/lib/mysql 以下にデータベース中のデータを含めて MySQL 関連が詰め込まれています)、↑コマンドでローカルのファイルシステムにバックアップファイルを保存します。
# データベース部を永続化したコンテナを作り直し ## docker-compose の場合 ##### docker-compose.yml ############# # version: '3.1' # services: # db: # image: mysql # command: --default-authentication-plugin=mysql_native_password # restart: always # environment: # MYSQL_ROOT_PASSWORD: example # volumes: # データベースの永続化 # - mysql-store:/var/lib/mysql # volumes: # mysql-store: ###################################### docker-compose up --force-recreate mysql ## docker の場合 docker run -v some-mysql-store:/var/lib/mysql --name mysqlコンテナ名 -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:8.0
コンテナをボリュームによる永続化込みで作り直します。docker-compose を用いているならばコンテナ定義に使うボリュームの名前とマウント先の定義を、トップレベルの volumes 以下に用いるコンテナの定義を追加します。定義を追加したら強制再生成付きでコンテナを起動します
Use volumes | Docker Documentation#Use a volume with docker-compose
docker-compose を用いないのであれば、コマンドでボリューム名とマウント先の定義-v some-mysql-store:/var/lib/mysql
を追加するだけです。ボリューム名に該当するボリュームが存在しない場合はよしなにボリュームを作り、既に存在する場合はそのボリュームとつなげてくれます。
# 既存コンテナ同様の空テーブルの作成を行う。方法は自由 # # Laravel # docker-compose exec app php artisan migrate # # mysqldump これが使えるならそもそもファイル経由で復元しなくても良さそう # docker-compose exec mysql mysqldump -u root -p -d --databases 復元対象DB -n > ddl.sql
ここで紹介する方法は各テーブルの中身をファイルシステム上から入れ替える方法です。このため元々あったテーブルを再現する必要があります。プログラムのマイグレーションコマンドや mysqldump が手軽です。再現さえできればよいので手間ですが何かしらのデータベース定義書があれば、それを元に SQL を作って使うのもありです。
### MySQL のコンソールに入って実行ここから ### SET foreign_key_checks = 0;# TABLESPACEの操作を行うために実行 ALTER TABLE バックアップしたいテーブルの名前その1 DISCARD TABLESPACE; ALTER TABLE バックアップしたいテーブルの名前その2 DISCARD TABLESPACE; ... ALTER TABLE バックアップしたいテーブルの名前最後 DISCARD TABLESPACE; ### MySQL のコンソールに入って実行ここまで ###
各テーブルのテーブルスペースを捨てます。テーブルスペースとはファイルそステムについての情報で直にファイルを渡すために、いったんこれを無効にする必要があります。
# ローカルのバックアップファイルをコンテナ内にコピー # docker cp ./mysqlBackUp mysqlコンテナ名:var/lib/mysql # コンテナ内にコピーしたファイルを mysql が扱えるように所有者を変更 # docker exec コンテナ名 chown mysql:mysql -R /var/lib/mysql/alloc
一旦ローカルに退避させていた元々の MySQL の中身を新しい MySQL コンテナにコピーします。Docker におけるユーザーとクライアントによって変わりますがコピーしたファイルを MySQL が使える様に chown で MySQL を動かしているユーザーに MySQL のファイルの所有権を渡します。
### 新しいコンテナの MySQL のコンソールに入って実行ここから ### ALTER TABLE 復元したいテーブルの名前その1 IMPORT TABLESPACE; ALTER TABLE 復元したいテーブルの名前その2 IMPORT TABLESPACE; ... ALTER TABLE 復元したいテーブルの名前最後 IMPORT TABLESPACE; SET foreign_key_checks = 1; ### 新しいコンテナの MySQL のコンソールに入って実行ここまで ###
ファイルを映し終わったらテーブルスペースと外部キー制約を元に戻してファイルにおける復元が完了です。最後に MySQL を再起動することで新しい方の MySQL で元々のあったのと同じデータにアクセスできるようになります。