はじめに
本記事では、RPM/debパッケージで導入したGitLab(いわゆるOmnibus版)を前提としています。Docker版やソースビルド版ではバックアップコマンドが異なるため、環境に合わせて読み替えてください。GitLab公式では、Omnibus版のバックアップコマンドとして次が案内されています。
sudo gitlab-backup create
GitLabを別サーバへ移行するためにバックアップを取得したところ、数十GBのtarファイルが作成されました。
ファイルが存在し、サイズも十分に大きかったため、正常に取得できたものと考えていました。しかし、移行先でリストアすると、次のエラーが発生しました。
Unexpected EOF in archive
tar: Error is not recoverable: exiting now
調査した結果、転送時に壊れたのではなく、バックアップ作成時点ですでにtarファイルが破損していたことが分かりました。
今回の経験から、GitLabバックアップでは次の3点が重要だと学びました。
- バックアップ前と実行中に空き容量を確認する
- 実行ログと終了コードを残す
- 作成後にtarファイルを検査する
バックアップファイルがあっても成功とは限らない
最初のバックアップ後、バックアップディレクトリにはtarファイルが作成されていました。
sudo ls -lh /var/opt/gitlab/backups
しかし、移行元に残っていたファイルを確認すると、移行先と同じエラーが発生しました。
BACKUP_FILE="/var/opt/gitlab/backups/<バックアップファイル>.tar"
sudo tar -tf "${BACKUP_FILE}" >/dev/null
echo $?
Unexpected EOF in archive
tar: Error is not recoverable: exiting now
この結果から、転送中の破損ではなく、バックアップ作成時点で不完全だったと判断しました。
また、バックアップ実行時のログには、次のようにアーカイブ作成の失敗が記録されていました。
Creating archive ... failed
つまり、次の状態だけではバックアップ成功とは判断できません。
- tarファイルが存在する
- ファイルサイズが数十GBある
- GitLabの形式に沿ったファイル名になっている
1. バックアップ前に空き容量を確認する
今回、バックアップ作成時のストレージ空き容量が少ない状態でした。
明確な No space left on device は確認できなかったため、容量不足が直接の原因だったとは断定できません。しかし、不要なデータを削除して空き容量を増やした後は、バックアップを正常に取得できました。
バックアップ前には、保存先の空き容量を確認します。
df -h /var/opt/gitlab/backups
バックアップ先がルートファイルシステム上にある場合は、次でも確認できます。
df -h /
既存のバックアップが使用している容量も確認します。
sudo du -sh /var/opt/gitlab/backups
sudo ls -lh /var/opt/gitlab/backups
必要な空き容量の目安
GitLab公式では、デフォルトのバックアップ方式でも、バックアップ作成中にGitLabインスタンス全体の約半分に相当する空き容量が必要になることは珍しくないと説明されています。さらに、STRATEGY=copy を使用する場合は、一時コピーのために最大で追加1倍のディスク容量を消費する可能性があります。
ただし、必要容量はリポジトリ、Artifacts、Uploads、LFSなどの構成によって変わります。
そのため、運用上の安全な目安としては、次のように考えるのがよいと思います。
バックアップ対象データに対して、少なくとも1.5倍程度、可能であれば2倍程度の空き容量を確保する。
これはGitLab公式が一律に定めた必要容量ではなく、処理途中のデータや安全マージンを考慮した目安です。空き容量がぎりぎりの場合は、バックアップを開始する前に古いバックアップや不要なキャッシュを整理した方が安全です。
実行中も監視する
バックアップ開始時に空き容量があっても、処理中に使用量が増加します。
別のSSHセッションで、次のように監視しました。
watch -n 30 'date; echo; df -h /'
バックアップ先が別のファイルシステムの場合は、そのパスを指定します。
watch -n 30 \
'date; echo; df -h /var/opt/gitlab/backups'
大容量ディレクトリに対する du の頻繁な実行は、ファイルを繰り返し走査してディスクI/Oを増やすため、継続監視には df -h を使う方が負荷を抑えられます。
2. 実行ログと終了コードを残す
再取得時は、画面表示だけでなくログファイルへ出力しました。
BACKUP_LOG="/root/gitlab_backup_$(date +%Y%m%d%H%M%S).log"
set -o pipefail
time sudo gitlab-backup create \
2>&1 |
sudo tee "${BACKUP_LOG}"
BACKUP_RC=${PIPESTATUS[0]}
echo "gitlab-backup exit code: ${BACKUP_RC}"
echo "backup log: ${BACKUP_LOG}"
teeを使う場合の注意
gitlab-backup の出力を tee に渡した場合、単純な $? では、パイプ末尾にある tee の終了コードを確認してしまうことがあります。
そのため、Bashの PIPESTATUS[0] を使用して、gitlab-backup 自体の終了コードを取得します。
BACKUP_RC=${PIPESTATUS[0]}
正常終了時は次のようになります。
gitlab-backup exit code: 0
バックアップ完了後は、保存したログを確認します。
sudo tail -100 "${BACKUP_LOG}"
失敗を示すメッセージも検索します。
sudo grep -iE \
'failed|failure|fatal|no space|unexpected' \
"${BACKUP_LOG}"
特に、最終的なアーカイブ作成が完了していることを確認します。
Creating archive ... done
確認すべきなのは、次の両方です。
Creating archive ... done
gitlab-backup exit code: 0
3. 作成後にtarファイルを確認する
ログと終了コードが正常でも、リストア前にtarファイルを確認しておくと安心です。
BACKUP_FILE="/var/opt/gitlab/backups/<バックアップファイル>.tar"
time sudo tar -tf "${BACKUP_FILE}" >/dev/null
TAR_RC=$?
echo "tar check exit code: ${TAR_RC}"
正常時は次のようになります。
tar check exit code: 0
今回の破損ファイルでは、次のエラーを確認できました。
Unexpected EOF in archive
tar: Error is not recoverable: exiting now
tar -tf はtarアーカイブの構造を読み取り、途中で切れたファイルなどを検出するための最低限の確認として利用できます。
ファイルサイズが大きい場合は処理に時間がかかりますが、移行先へ転送してリストアを始めてから破損に気づくより、移行元で確認しておく方が安全です。
なお、tar -tf だけですべてのデータ内容の完全性を保証できるわけではありません。ここでは、今回発生したような不完全なtarファイルを事前に検出するための確認として使用しています。
見直したバックアップ手順
今回の経験を踏まえ、次の流れで確認することにしました。
バックアップ前
df -h /var/opt/gitlab/backups
sudo du -sh /var/opt/gitlab/backups
sudo ls -lh /var/opt/gitlab/backups
別セッションで容量監視
watch -n 30 'date; echo; df -h /'
ログを保存してバックアップ
BACKUP_LOG="/root/gitlab_backup_$(date +%Y%m%d%H%M%S).log"
set -o pipefail
time sudo gitlab-backup create \
2>&1 |
sudo tee "${BACKUP_LOG}"
BACKUP_RC=${PIPESTATUS[0]}
echo "gitlab-backup exit code: ${BACKUP_RC}"
ログを確認
sudo tail -100 "${BACKUP_LOG}"
sudo grep -iE \
'failed|failure|fatal|no space|unexpected' \
"${BACKUP_LOG}"
確認する内容:
Creating archive ... done
gitlab-backup exit code: 0
tarファイルを確認
time sudo tar -tf \
"/var/opt/gitlab/backups/<バックアップファイル>.tar" \
>/dev/null
echo $?
確認する内容:
0
まとめ
今回、GitLabのバックアップtarは存在していたものの、アーカイブ作成が途中で失敗し、不完全な状態になっていました。
ファイルサイズも数十GBあったため、見た目だけでは破損に気づけませんでした。
今回の経験から、GitLabバックアップでは次の確認が重要だと学びました。
- バックアップ前に十分な空き容量を確保する
- バックアップ中も
df -hで容量を監視する - 実行ログを保存する
-
gitlab-backup自体の終了コードを確認する -
Creating archive ... doneまで確認する - 作成後に
tar -tfでアーカイブを検査する
tarファイルが作成されていても、バックアップが成功したとは限りません。
バックアップは、ファイルの存在だけでなく、ログ・終了コード・tarの正常性まで確認して初めて有効になると学びました。
ご参考
GitLab公式では、デフォルトのバックアップ方式でも、バックアップ作成中にGitLabインスタンス全体の約半分に相当する空き容量が必要になることは珍しくないと説明されています。
https://docs.gitlab.com/administration/backup_restore/backup_gitlab/
https://docs.gitlab.com/administration/backup_restore/troubleshooting_backup_gitlab/