🙄

【Growi】バックアップスクリプトが全然うまく書けてなかった話

3 min read

はじめに

以前に下記のような記事を公開しました。

https://zenn.dev/nekoniki/articles/44252c08f725f811be38

簡単に説明すると「GrowiというWikiツールをDockerを使って立てたよ」という話なのですが、最近そのバックアップ設定で盛大にやらかしていた事に気づいたので、その詳細について記事にしたいと思います。

自分と同じようなやらかしをする方が少しでも減ればいいなと思います。

環境

  • CentOS Linux release 7.6.1810
  • Docker 19.03.5

以下のような構成になっていました。

/
├── opt
│   └── docker
│       └── growi
│           ├── backup.sh
│           └── backup
└── home

他にも色々あるのですが、ここでは省略しています。

バックアップスクリプト(当初)

当初backup.shは以下のような内容になっていました。

backup.sh
docker exec -d {mongodb コンテナ名} mongodump --archive=mongodb.archive
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については下記が参考になります。

https://www.atmarkit.co.jp/ait/articles/1801/19/news014.html

これには心当たりがあり、 「ちゃんと削除対象だけが抽出されているか確認するため」 に一旦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は下記が参考になります。

https://www.atmarkit.co.jp/ait/articles/1702/02/news031.html

バックアップの同期自体は取れているのですが、「同期元にないファイルを同期先から削除する」指定がないため、「/opt/docker/growi/backupからは過去分のバックアップが消えるようになっても、マウント先には過去分が残り続ける」という状態です。

これはrsync--deleteをつける事で解決します。

rsync --delete -av /opt/docker/growi/backup/ {マウント先パス}

見直し後のバックアップスクリプト

ここまでの結果を踏まえて以下のようにbackup.shを修正しました。

backup.sh
docker exec -d {mongodb コンテナ名} mongodump --archive=mongodb.archive
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人で作成して運用していたことです。
コアな部分については複数人で検証の上使用していけば、今回のような凡ミスや知識不足は防げると思うので、いい教訓になりました。

Discussion

ログインするとコメントできます