現在常時稼働サーバがMac・Linuxと無意味に分かれている。Linuxマシンに統一してIntel Mac mini 2018には予備役となってもらうように、少しずつ機能を移行している。今回は自宅サーバのWebサイト。つまりこのサイト。
環境
Mac上で展開していたDocker + WordPressのサイトを、別マシンに移行する。前回の移行時はプラグインを使って復元したのだが、せっかくコンテナでやってるのにそれではかいがないと思い、今回はCLIで実施。
- 元マシン: Intel Mac mini 2018
- Docker Desktop 4.73.0
- 移行先マシン: Linux Mint Xfce 22.3
- Docker 29.5.0
- GitHub - BretFisher/docker-vackup: Script to easily backup and restore docker volumes · GitHub
vackupコマンドの中身については以下の記事を参照。

手順
全体は以下。
- 元マシン:コンテナを停止する
- 元マシン:ボリュームのエクスポート
- 元マシン:コンテナを再開する
- 元マシンからコンテナにボリュームをコピー
- 移行先:ボリュームをリストア
- 移行先:コンテナを起動
- 移行先:localhostにアクセスして復元されていることを確認する
- リバースプロキシなどで向け先を移行先に。元サイトは落とす
元マシン:ボリュームのバックアップ
コンテナは持ち運べるとして、問題は永続化ボリュームをコピーすること。ここでは、docker-compose.ymlは以下のようなものとする。変数は.envで定義しているとする。内容は、WordPressとDBそれぞれコンテナたててるよ、それぞれボリュームを指定して使うよ、というもの。
services:
hp_wordpress:
image: wordpress:latest
ports:
- "ポート番号:80"
environment:
WORDPRESS_DB_HOST: データベースコンテナ
WORDPRESS_DB_USER: ${DB_USER}
WORDPRESS_DB_PASSWORD: ${DB_PASSWORD}
WORDPRESS_DB_NAME: ${_DB_NAME}
volumes:
- hp_wordpress_data:/var/www/html
- ./custom-php.ini:/usr/local/etc/php/conf.d/custom-php.ini
restart: always
depends_on:
- db
db:
image: mariadb:latest
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: ${DB_NAME}
MYSQL_USER: ${DB_USER}
MYSQL_PASSWORD: ${DB_PASSWORD}
volumes:
- ai_hackle_db_data:/var/lib/mysql
restart: always
volumes:
hp_wordpress_data:
external: true
db_data:
external: truevolumeとして、hp_wordpress_dataとdb_dataを外部で作成したものを使うような設定になっている。
現在のボリュームを確認する。
docker volume lsターゲットとなるボリューム名と存在することを確認しておく。
コンテナを停止する。
docker compose stop以下のコマンドでバックアップ。
mkdir volume-backups
vackup export WPボリューム名 bakcups/WPボリューム名.tar.gz
vackup export DBボリューム名 bakcups/DBボリューム名.tar.gzダウンタイムを小さくしたいなら、この時点で元マシンをdocker compose up -dで復帰させる。
転送する。
rsync -avz --progress volume-backups ユーザ:移行先:移行先のパス/容量大きくて途中でdisconnectされるときは
rsync -avz --progress -e "ssh -o ServerAliveInterval=60 -o ServerAliveCountMax=10" volume-backups ユーザ:移行先:移行先のパス/移行先マシン:ボリュームのリストア
作業ディレクトリに移動し、ボリュームを復元する。
vackup import WPボリューム.tar.gz WPボリューム名
vackup import DBボリューム.tar.gz DBボリューム名ここで注意が必要。ボリュームの中身を見てみると…
$ docker run --rm -v ボリューム:/volume alpine ls -lh /volume
total 4K
drwxr-xr-x 6 999 ping 4.0K May 18 02:53 vackup-volumevackup-volumeなる親ディレクトリが出来ていて、その下にディレクトリがあるようだ。
しかし復元では直下に展開されていることが期待される。なので、以下のコマンドによりvackup-volume以下を展開する。
docker run --rm -v WPボリューム名:/volume alpine sh -c "mv /volume/vackup-volume/* /volume/ 2>/dev/null || true; mv /volume/vackup-volume/.[!.]* /volume/ 2>/dev/null || true; rmdir /volume/vackup-volume"もう一度ボリュームを確認したら直下に展開されていることがわかる。DBのほうのボリュームも同様に。
これでいけるのだが、なんかよくわからんことをしている気がする。vackup-volumeが出来てしまうのはvackupコマンドの仕様なんかな…。
とにかく、ここでリストアを実行する。
vackup import WPボリューム.tar.gz WPボリューム名
vackup import DBボリューム.tar.gz DBボリューム名起動と疎通確認
最後にもう一度docker-compose.ymlを確認し、コンテナを起動する。
docker compose upエラーとか出ないかを確認するため、最初はフォアグラウンドで。http://localhost:ポートにアクセスし、いつもの画面が表示されることを確認する。インストール画面が出たら初期化されちゃってます。なにか間違えているので最初からやりなおし。やりなおした🥺
問題なければ正式にバックグラウンドで動かす。
docker compose up -d移行元から移行先に向ける
準備が整ったので、DNSやらリバースプロキシやらいじって、移行元から移行先に向ける。
この時点で移行元を落としていいが、いつ落とすかは考え方による。ダウンタイムを小さくするなら移行元をしばらく残しておいてもいい。しかし、変に残しておいてナイスタイミングでコメントついてしまい、消えてしまうみたいな事故が起きる可能性もあるので、何がいいとも言えない。僕はいらなくなったら落とす。
インフラはAI無能
最初これくらいAIがすぐできるだろうと思ったけど何か色々ハマってしまって、結局手作業で心を込めてやりました。インフラ周りは固有の環境や設定が多すぎるので、汎用的な一般解を出し続けるAIは無能になりがち。
それにしてもこの手の作業をするとき、昔書いた記事を参考にすることがよくあるのだけれど、このサイト自身が対象のとき、失敗するとサイト自体が落ちてしまって閲覧することができないっていう。まぁそれを考えると、ニッチな記事でもnoteに転載していくのは保険としての意味もあるか。釈然としないけど。
今後Linuxマシンは色々なハードウェアを検証していくため、移行作業はスクリプト化してスムーズに検証できる体制を整えたい。
コメント