【Growi】バックアップスクリプトが全然うまく書けてなかった話
はじめに
以前に下記のような記事を公開しました。
簡単に説明すると「Growi
というWiki
ツールをDocker
を使って立てたよ」という話なのですが、最近そのバックアップ設定で盛大にやらかしていた事に気づいたので、その詳細について記事にしたいと思います。
自分と同じようなやらかしをする方が少しでも減ればいいなと思います。
環境
CentOS Linux release 7.6.1810
Docker 19.03.5
以下のような構成になっていました。
/
├── opt
│ └── docker
│ └── growi
│ ├── backup.sh
│ └── backup
└── home
他にも色々あるのですが、ここでは省略しています。
バックアップスクリプト(当初)
当初backup.sh
は以下のような内容になっていました。
docker exec {mongodb コンテナ名} mongodump --archive=mongodb.archive --quiet
docker cp {mongodb コンテナ名}:/mongodb.archive /opt/docker/growi/backup/growi_`date "+%Y%m%d"`.archive
find ./ -mtime +7 -name "*.archive" | xargs ls -ltrh
rsync -av /opt/docker/growi/backup/ {マウント先パス}
意図としては
-
Growi
のデータが入っているmongodb
から毎日dump
を取り、タイムスタンプを付与して/opt/docker/growi/backup
に.archive
形式で保持しておく - バックアップは過去7日分あれば十分なので、それ以上経ったものは削除しておく
- 最後に退避場所として指定したパスに
rsync
で同期させる
といった感じです。
これをcrontab
で毎日深夜に動かすようにしていました。
※察しのいい方はこの時点で色々やらかしている事に気づくかもしれません。
何が起きたか
一言で表すと 「バックアップが消えずに延々と残り続ける」 状態となっていました。
/opt/docker/growi/backup
以下はもちろん、マウント先も毎日.archive
が残っている状態がずーっと続いていたことになります。
Why?
原因は主に2つあります。
xargs
のコマンド間違いとfind
のパス指定
①1つ目は以下のコマンドが原因です。
find ./ -mtime +7 -name "*.archive" | xargs ls -ltrh
find ./ -mtime +7 -name "*.archive"
の結果をxargs
に渡していますが、肝心のxargs
で実行しているのがls
コマンドでした。
※xargs
については下記が参考になります。
これには心当たりがあり、 「ちゃんと削除対象だけが抽出されているか確認するため」 に一旦rm -rf
ではなくls
に書き換えていました。
それを忘れたままにしてしまい、結果的に 「毎日7日以上更新されていない.archive
ファイルをls
する」 という意味のない処理を繰り返していたことになります。
また、地味にfind
のパス指定も問題で、シェル単体で実行する分には./
のパス指定で構わないのですが、cron
で実行する場合はhome
を起点にシェルが実行されるので/opt/docker/growi/backup
以外のパスの.archive
を巻き込んで消してしまう可能性があります。
cron
のパスの仕様は全く知らなかったので、正直危なかったです。
この処理は以下のようにすると正しいです。
find /opt/docker/growi/backup -mtime +7 | xargs rm -rf
絶対パスでバックアップディレクトリを指定することにしたので、ファイル名で絞り込むのはやめて更新日だけで抽出することにしました。
その上でfind
の結果をxargs
に渡してrm -rf
を実行しています。
rsync
のオプションが足りない
②上記の修正を行っても「マウント側」には過去分のバックアップが残り続けてしまいます。
これは以下の記述が原因です。
rsync -av /opt/docker/growi/backup/ {マウント先パス}
rsync
は下記が参考になります。
バックアップの同期自体は取れているのですが、「同期元にないファイルを同期先から削除する」指定がないため、「/opt/docker/growi/backup
からは過去分のバックアップが消えるようになっても、マウント先には過去分が残り続ける」という状態です。
これはrsync
に--delete
をつける事で解決します。
rsync --delete -av /opt/docker/growi/backup/ {マウント先パス}
見直し後のバックアップスクリプト
ここまでの結果を踏まえて以下のようにbackup.sh
を修正しました。
docker exec {mongodb コンテナ名} mongodump --archive=mongodb.archive --quiet
docker cp {mongodb コンテナ名}:/mongodb.archive /opt/docker/growi/backup/growi_`date "+%Y%m%d"`.archive
find /opt/docker/growi/backup -mtime +7 | xargs rm -rf
rsync --delete -av /opt/docker/growi/backup/ {マウント先パス}
まとめ
今回はGrowi
のバックアップ用のスクリプトについて、バックアップが残り続けるというやらかしをした話をまとめました。
Growi
の規模が大きくなってくると、バックアップのサイズも馬鹿にならないのでサーバを圧迫してしまいました。
事故になる前に気づいて修正ができたのは幸いでした。
根本はこのスクリプトを1人で作成して運用していたことです。
コアな部分については複数人で検証の上使用していけば、今回のような凡ミスや知識不足は防げると思うので、いい教訓になりました。
20230814追記
copen様よりコメントいただき、記事中のバックアップスクリプトを一部修正しました。
- docker exec -d {mongodb コンテナ名} mongodump --archive=mongodb.archive
+ docker exec {mongodb コンテナ名} mongodump --archive=mongodb.archive --quiet
旧コマンドでは
でmongodumpを"-d"オプションでデタッチして実行していますが、バックグラウンドで動作しているためmongodumpが完全に終了する前に次のdocker cpが走ってしまうと、不完全なファイルがコピーされます。
の動きとなってしまうためです。
Discussion
こちらの内容を参考にさせていただき、GROWIのmongoDBをバックアップしております。
時々、docker cpでコンテナからコピーしたファイルサイズが元のmongodumpしたファイルより小さい現象に悩んでいたのですが、原因が分かりましたのでコメントします。
でmongodumpを"-d"オプションでデタッチして実行していますが、バックグラウンドで動作しているためmongodumpが完全に終了する前に次のdocker cpが走ってしまうと、不完全なファイルがコピーされます。それを回避するため、
と修正し、フォアグラウンドで実行するように変更しました。
コメントありがとうございます!
記事中に追記と訂正を反映させていただきました!