自分で 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

コード内のメッセージは元の運用スクリプトのままですが、処理は大きく六つです。

  1. git-lfs がなければインストール
  2. 初回だけバックアップリポジトリを clone し、LFS を初期化
  3. Docker Volume を列挙して一つずつ tar.gz にする
  4. /opt/1panel/apps も圧縮
  5. 7 日より古いローカルバックアップを削除
  6. 新しい圧縮ファイルを Git リポジトリへコピーして push

Shell、Git、Git LFS、Docker という既存の道具だけで作っているため、どこで失敗したかを追いやすいのが利点です。

注意したいのは次の二点です。

  • 変更がない場合、git commit は失敗する
  • docker volume ls -q はすべての Volume を対象にする

本番運用するなら、この二つは自分の環境に合わせて調整した方が安全です。

1Panel のスケジュールタスクには長いスクリプトを置かない

私は 1Panel 側には処理本体を書かず、呼び出しだけを置きます。

  1. SSH で docker-sync を手動実行して成功させる
  2. 1Panel でスケジュールタスクを作成
  3. 種類は Shell script
  4. 例えば毎日 03:00 に実行
  5. 内容は次だけにする
docker-sync

こうすると失敗したとき、SSH で同じ docker-sync を実行すればログをそのまま確認できます。

管理画面に長いスクリプトを貼り付けていると、修正やデバッグの場所が分散しやすくなります。

バックアップより復旧手順の方が重要

バックアップファイルを作るだけでは十分ではありません。

実際に障害が起きたときに必要なのは「どう戻すか」です。

サーバーを失った場合は、おおよそ次の流れになります。

  1. 新しいサーバーでバックアップリポジトリを clone
  2. 必要な時点の圧縮ファイルを選ぶ
  3. 対応する vol_xxx.tar.gz を展開
  4. docker volume create で Volume を作る
  5. データをその Volume の Mountpoint に戻す
  6. コンテナを再作成して 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 サーバーに、毎日動く復旧可能なバックアップを持たせることです。