Docker 資料卷自動備份到 GitHub:適合 1Panel 的低成本容災方案
自己跑 Docker 服務,平時最容易忽略的一件事,就是你以為“容器都在正常執行”,所以備份這件事可以晚點再說。真正出問題時,麻煩往往不是把容器重新拉起來,而是卷裡的資料、面板裡的設定、還有你自己改過的那些東西,到底還能不能找回來。
我最後定了一套比較剋制的方案,不追求很重的備份系統,也不先上物件儲存。思路很簡單:每天把 Docker 卷和 1Panel 設定打包一份,本地只留最近 7 天,再把壓縮包同步到 GitHub 私有儲存庫。這樣做不花哨,但它至少把“最近幾天能快速還原”和“遠端還有一份兜底”這兩件事先解決了。
如果你現在正好在搜這些關鍵詞,比如 Docker 自動備份、Docker 卷備份到 GitHub、1Panel 備份方案,這篇文章基本就是圍繞這幾個問題展開的。
我為什麼沒把它做成一套很重的備份系統
很多人一提備份,第一反應就是物件儲存、版本歸檔、異地多副本、專門備份平臺。方向當然沒問題,但對個人伺服器或者小團隊機器來說,真正卡住的往往不是“方案不夠先進”,而是根本沒有一套能穩定每天跑的東西。
我更在意的是三件事:
- 先自動跑起來,不靠人記著手工執行
- 出問題時最近幾天能快速還原
- 備份檔案別隻放在當前這臺伺服器上
所以這次沒有把鏈路做得特別複雜,而是壓成了下面這個結構:
Docker 卷 / 1Panel 配置
↓
docker-sync 脚本
↓
本地生成 backup_<timestamp>
↓
删除 7 天前旧备份
↓
复制压缩包到 Git 仓库目录
↓
Git LFS 跟踪 .tar.gz
↓
推送到 GitHub 私有仓库
它不適合特別大的備份量,也不是嚴格意義上的企業級容災。但如果你現在是用 1Panel 跑幾個站、幾個資料庫、幾個服務,這種“7 天本地 + GitHub 私有儲存庫同步”的組合其實挺實用。
先把 GitHub 信任打通,不然後面都白搭
這件事我建議先做,而且一定要先手工驗證一次。原因很簡單,後面無論你用 Shell、1Panel 計劃任務還是別的自動化方式,最終都得落到“這臺伺服器能不能把東西推到 GitHub”。
在伺服器上先執行:
ssh-keygen -t ed25519 -C "[email protected]"
cat ~/.ssh/id_ed25519.pub
ssh -T [email protected]
第一條是生成金鑰,第二條把公鑰拷出來放進 GitHub 的 SSH keys,第三條是第一次手工驗證連線。
這一步別偷懶。很多自動任務一開始就失敗,不是腳本有問題,而是 SSH 壓根沒通。你把這件事提前確認掉,後面排查會省很多時間。
順手說一下,備份儲存庫最好單獨建,不要和業務程式碼混在一起。我這裡用的是這種形式:
[email protected]:kuangyongjie/my-docker-backup.git
儲存庫最好設成 Private,這個沒什麼好猶豫的。
我把整個流程壓成了一個 docker-sync 命令
如果備份邏輯只是臨時放在某個腳本目錄裡,過兩個月你大機率就忘了它到底在哪、該怎麼跑、改了什麼。我的習慣是,能長期維護的東西,入口最好固定。
所以我最後直接把它封裝成了一個系統命令:
/usr/local/bin/docker-sync
這樣無論是我自己手工執行,還是後面讓 1Panel 排程,呼叫方式都一樣。下面這段腳本就是核心:
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
這段腳本其實沒那麼複雜,拆開看就六件事
很多人一看到長一點的 Shell 腳本就不想看了,但這段邏輯其實挺直白。
它無非就是:
- 如果沒裝
git-lfs,先裝 - 第一次執行時,克隆備份儲存庫並初始化 LFS
- 遍歷 Docker 卷,把每個卷單獨打成
tar.gz - 順手把
/opt/1panel/apps也打進去 - 清理 7 天前的本地備份目錄
- 把壓縮包複製到同步目錄,提交併推到 GitHub
這裡我比較喜歡的一點是,鏈路沒有額外引入很重的依賴。Shell、Git、Git LFS、Docker 卷路徑,這些東西本來就在機器上或者很容易裝。後面哪一步壞了,也比較容易定位。
真正需要注意的反而不是“腳本長不長”,而是兩個細節:
git commit在沒有新檔案變更時會直接失敗docker volume ls -q會把所有卷都掃進去,所以你最好知道自己這臺機器上到底有哪些卷
如果你後面要繼續打磨,可以先從這兩個點入手。
1Panel 這邊別塞長腳本,計劃任務只負責呼叫
我不太建議把一大段備份腳本直接貼進 1Panel 計劃任務裡。短期看似乎省事,長期維護會很煩,尤其是你以後要改儲存庫地址、保留天數、使用者資訊的時候。
更省心的方式是:
- 先在命令列裡把
docker-sync手工跑通 - 再進 1Panel 建立計劃任務
- 任務型別選 Shell 腳本
- 每天跑一次,比如凌晨
03:00 - 腳本內容只寫:
docker-sync
這樣後面如果某天備份失敗,你只需要 SSH 上去手工跑一次 docker-sync,馬上就能看日誌,不用先回面板裡翻長腳本。
真要還原的時候,流程其實比備份更重要
很多備份方案寫到最後,只停在“檔案已經存起來了”。但實際出事時,你最關心的是下一步怎麼還原,而不是備份當初多優雅。
如果伺服器掛了,還原大致就是這條線:
- 在新伺服器克隆備份儲存庫
- 找到你要的那個時間點壓縮包
- 解壓對應的
vol_xxx.tar.gz - 用
docker volume create重新建立目標卷 - 把資料拷回這個卷的
Mountpoint - 重新建立容器並掛載這個卷
1Panel 相關設定也是類似思路,先把設定目錄拿回來,再重新掛到新的執行環境裡。
這裡真正麻煩的不是“會不會解壓”,而是你平時有沒有把卷、服務、用途對應清楚。否則到了還原現場,檔案在,但你不知道哪個卷對應哪個服務,時間照樣會被拖很久。
我自己會常看的幾個命令
平時維護時,我比較常用的其實就這幾個:
| 需求 | 命令 |
|---|---|
| 手動立即備份 | 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 天,或者改成 3 天,直接改 find ... -mtime +7 那一段就行,不需要重構整個腳本。
這套方案最容易翻車的地方
先說結論,通常不是壓縮命令本身有多難,而是下面這些地方最容易出問題:
- 伺服器到 GitHub 的 SSH 信任沒配完整
git-lfs沒裝或者沒初始化- 本地同步目錄第一次初始化時權限不對
- 計劃任務能跑,但儲存庫裡其實沒有新檔案,所以
git commit失敗
還有一個現實問題也得提前接受:GitHub 私有儲存庫可以拿來做這種 Docker 備份同步,但它更適合設定、小型資料庫卷、常見應用資料這類體量還算可控的場景。真要是備份越來越大,後面遲早還是要往物件儲存或者專門的備份介質遷。
所以這套方案的定位我覺得要看準一點,它不是“最終版容災體系”,而是“先讓你的 1Panel / Docker 伺服器真正擁有一套穩定可用的自動備份”。