rsyncを利用して定期的なローカルバックアップスクリプトを運用している際、転送処理中にエラーが発生して一部のファイル同期および削除処理がスキップされるトラブルに遭遇しました。今回はその原因の特定と、安全にスクリプトを修正して正常終了させるまでの手順をまとめます。
エラーの発生状況と原因
バックアップスクリプトを実行したところ、転送の途中で以下のようなメッセージが出力されました。
IO error encountered -- skipping file deletion
rsync: [sender] opendir "/path/to/app1/data/db" failed: Permission denied (13)
rsync: [sender] opendir "/path/to/app2/db-data" failed: Permission denied (13)
rsync error: some files/attrs were not transferred (see previous errors) (code 23)この現象には2つの連動した原因があります。
直接的な原因は、コンテナ等で稼働しているアプリケーション(データベースなど)のデータディレクトリに対して、一般ユーザー権限で実行していたrsyncがアクセスできず、Permission denied となったことです。コンテナ内のプロセスが専用のUIDでディレクトリを作成しているため、一般ユーザーの読み取り権限が制限されていました。
間接的なエラーである IO error encountered -- skipping file deletion は、rsyncが備えている安全機能によるものです。同期元でアクセスエラーや読み込み不可のファイルが発生した場合、rsyncはファイルが削除されたのか、単に読み込めないだけなのかを判別できません。そのため、同期先のファイルを誤って消去してしまわないよう、--delete オプションによる削除処理を自動的に中断します。
対処法:DBデータディレクトリの除外
稼働中のデータベースが持つ生データディレクトリをそのままファイル単位でrsync同期することは、データの整合性が崩れるリスクが高いため推奨されません。データベースのバックアップはダンプファイルを別途出力してそれを同期するのが安全です。
そのため、今回は読み取り権限のないデータベース関連のディレクトリを --exclude オプションで明示的に除外する方針をとりました。
修正前のスクリプトでは、ドライブ直下のシステム用ディレクトリである lost+found のみを除外していましたが、コンテナのデータディレクトリも除外対象へ追加しました。
#!/bin/bash
rsync -avh --delete --exclude="lost+found" /path/to/source_disk1/ /path/to/backup_disk/disk1/
rsync -avh --delete --exclude="lost+found" /path/to/source_disk2/ /path/to/backup_disk/disk2/
rsync -avh --delete --exclude="lost+found" /path/to/user_data/ /path/to/backup_disk/share/
rsync -avh --delete \
--exclude="lost+found" \
--exclude="app1/data/db" \
--exclude="app2/db-data" \
/path/to/applications/ /path/to/backup_disk/applications/
除外パスの指定は、同期元(/path/to/applications/)からの相対パスで記述します。
修正後の動作確認
スクリプト修正後に再度実行したところ、アクセス権限エラーや削除スキップの警告は出力されなくなりました。
実行直後に echo $? で終了ステータスを確認し、正常終了を示す 0 が返ってくることを確認して作業完了としました。
権限エラーを無理やり無視する --ignore-errors などのオプションに頼るのではなく、不要なディレクトリや整合性の担保できないデータディレクトリを適切に除外することが、堅牢なバックアップ運用につながります。