Docker Volume を GitHub に自動バックアップする:1Panel 向けの低コスト復旧構成
自分で Docker サービスを運用していると、「コンテナが普通に動いているからバックアップは後でいい」と思いがちです。
本当に困るのは、コンテナそのものではなく、Volume のデータ、1Panel の設定、自分で変更したファイルを復元できるかどうかです。
私は最終的に、あまり重いバックアップ基盤にはせず、次の形にしました。
- Docker Volume と 1Panel の設定を毎日圧縮
- ローカルには直近 7 日分だけ残す
- 圧縮ファイルを GitHub の Private リポジトリへ同期する
豪華な構成ではありませんが、「直近の状態へすぐ戻せること」と「現在のサーバー以外にもコピーがあること」の二つを先に満たせます。
なぜ最初から大規模なバックアップ基盤にしなかったのか
バックアップというと、オブジェクトストレージ、多世代管理、複数リージョン、専用バックアップ製品まで考えたくなります。
ただ、個人サーバーや小規模環境では、最初の問題は「設計が高度か」ではなく、毎日確実に実行される仕組みがあるかです。
私が優先したのは次の三つです。
- 手動操作を忘れても自動で動く
- 数日前の状態へ短時間で戻せる
- バックアップを同じサーバーだけに置かない
そこで、最初の構成を次のようにしました。
Docker Volume / 1Panel 設定
↓
docker-sync スクリプト
↓
backup_<timestamp> をローカル生成
↓
7 日より古いバックアップを削除
↓
圧縮ファイルを Git リポジトリへコピー
↓
Git LFS で .tar.gz を管理
↓
GitHub Private リポジトリへ push
非常に大きなデータには向きませんし、企業向け DR と同じものでもありません。
ただ、1Panel で数個のサイト、DB、アプリを動かしている程度なら、「ローカル 7 日 + GitHub Private」という組み合わせはかなり実用的です。
まず GitHub への SSH 接続を手動で通す
ここは最初に一度だけ手動確認しておくのがおすすめです。
後で Shell や 1Panel のスケジュールタスクから実行しても、最後は「このサーバーから GitHub へ push できるか」に依存するからです。
ssh-keygen -t ed25519 -C "[email protected]"
cat ~/.ssh/id_ed25519.pub
ssh -T [email protected]
1 行目で鍵を作り、2 行目の公開鍵を GitHub の SSH keys に登録し、3 行目で接続を確認します。
ここを曖昧にしたまま自動化を作ると、後でスクリプトではなく SSH 認証で止まっていることがよくあります。
バックアップ用リポジトリは、業務コードとは分けた方が扱いやすいです。
[email protected]:kuangyongjie/my-docker-backup.git
もちろん Private にします。
バックアップ処理を docker-sync にまとめる
長く使う処理は、実行入口を固定した方が後で迷いません。
私は次のパスにまとめています。
/usr/local/bin/docker-sync
スクリプト本体は次のような形です。
cat << 'EOF' > /usr/local/bin/docker-sync
#!/bin/bash
GITHUB_REPO="[email protected]:kuangyongjie/my-docker-backup.git"
GIT_USER_NAME="kuangyongjie"
GIT_USER_EMAIL="[email protected]"
LOCAL_SYNC_PATH="/root/github_sync_space"
if ! command -v git-lfs &> /dev/null; then
apt-get update && apt-get install -y git git-lfs && git lfs install
fi
if [ ! -d "$LOCAL_SYNC_PATH/.git" ]; then
echo "--- 第一次运行:初始化同步目录 ---"
rm -rf "$LOCAL_SYNC_PATH"
GIT_SSH_COMMAND="ssh -o StrictHostKeyChecking=no" git clone "$GITHUB_REPO" "$LOCAL_SYNC_PATH"
cd "$LOCAL_SYNC_PATH"
git lfs track "*.tar.gz" && git add .gitattributes
git config user.name "$GIT_USER_NAME" && git config user.email "$GIT_USER_EMAIL"
git commit -m "Init LFS"
else
cd "$LOCAL_SYNC_PATH" && git pull origin main --rebase
fi
TAG=$(date +%Y%m%d_%H%M%S)
DIR="/root/docker_backups/backup_$TAG"
mkdir -p "$DIR"
echo "--- 正在抓取本地数据 ---"
for vol in $(docker volume ls -q); do
tar -zcf "$DIR/vol_$vol.tar.gz" -C $(docker volume inspect $vol --format '{{.Mountpoint}}') .
done
tar -zcf "$DIR/1panel_apps_config.tar.gz" /opt/1panel/apps
echo "--- 正在清理本地 7 天前的旧备份 ---"
find /root/docker_backups/ -maxdepth 1 -name "backup_*" -type d -mtime +7 -exec rm -rf {} +
echo "--- 正在同步到 GitHub ---"
cp "$DIR"/*.tar.gz "$LOCAL_SYNC_PATH/"
cd "$LOCAL_SYNC_PATH"
git add .
git commit -m "Auto Backup $TAG"
git push origin main
echo "--- 完美!所有任务已完成 ---"
EOF
chmod +x /usr/local/bin/docker-sync
コード内のメッセージは元の運用スクリプトのままですが、処理は大きく六つです。
git-lfsがなければインストール- 初回だけバックアップリポジトリを clone し、LFS を初期化
- Docker Volume を列挙して一つずつ
tar.gzにする /opt/1panel/appsも圧縮- 7 日より古いローカルバックアップを削除
- 新しい圧縮ファイルを Git リポジトリへコピーして push
Shell、Git、Git LFS、Docker という既存の道具だけで作っているため、どこで失敗したかを追いやすいのが利点です。
注意したいのは次の二点です。
- 変更がない場合、
git commitは失敗する docker volume ls -qはすべての Volume を対象にする
本番運用するなら、この二つは自分の環境に合わせて調整した方が安全です。
1Panel のスケジュールタスクには長いスクリプトを置かない
私は 1Panel 側には処理本体を書かず、呼び出しだけを置きます。
- SSH で
docker-syncを手動実行して成功させる - 1Panel でスケジュールタスクを作成
- 種類は Shell script
- 例えば毎日 03:00 に実行
- 内容は次だけにする
docker-sync
こうすると失敗したとき、SSH で同じ docker-sync を実行すればログをそのまま確認できます。
管理画面に長いスクリプトを貼り付けていると、修正やデバッグの場所が分散しやすくなります。
バックアップより復旧手順の方が重要
バックアップファイルを作るだけでは十分ではありません。
実際に障害が起きたときに必要なのは「どう戻すか」です。
サーバーを失った場合は、おおよそ次の流れになります。
- 新しいサーバーでバックアップリポジトリを clone
- 必要な時点の圧縮ファイルを選ぶ
- 対応する
vol_xxx.tar.gzを展開 docker volume createで Volume を作る- データをその Volume の
Mountpointに戻す - コンテナを再作成して Volume をマウント
1Panel の設定も同じで、設定ディレクトリを戻してから新しい環境へ再配置します。
ここで本当に困るのは tar の展開方法より、「どの Volume がどのサービスに対応していたか分からない」ことです。
そのため、Volume 名とサービスの対応は普段から記録しておく方が、復旧時の時間を大きく減らせます。
普段よく使う確認コマンド
| 目的 | コマンド |
|---|---|
| 今すぐ手動バックアップ | docker-sync |
| ローカルバックアップ容量 | du -sh /root/docker_backups |
| バックアップ一覧 | ls -lh /root/docker_backups |
| 最近の同期履歴 | cd /root/github_sync_space && git log -n 5 |
| 保持日数の変更 | nano /usr/local/bin/docker-sync |
7 日を 14 日に変えるなら、find ... -mtime +7 の値を変えるだけです。
失敗しやすいポイント
実際には圧縮処理より、次の部分の方が失敗しやすいです。
- サーバーから GitHub への SSH 認証が未完成
git-lfsが未導入、または未初期化- 初回同期ディレクトリの権限が合っていない
- 新しいファイルがなく、
git commitが非ゼロ終了する
また、GitHub Private リポジトリは、小さめの DB Volume、設定ファイル、一般的なアプリデータには使いやすい一方、バックアップ量が大きくなり続ける用途には向きません。
容量が増えた段階で、オブジェクトストレージや専用バックアップ先へ移行する方が自然です。
この構成の位置付けは「最終的な企業向け DR」ではなく、まず 1Panel / Docker サーバーに、毎日動く復旧可能なバックアップを持たせることです。