多服务器 Docker 管理方案:镜像缓存 + 更新监测 + 统一面板
多服务器 Docker 管理方案:镜像缓存 + 更新监测 + 统一面板
适用场景:多台 VPS + 本地 PVE + KVM 虚拟机,需要统一管理 Docker 容器、缓存镜像、监测更新。
目录
总览:三个工具解决三个问题
| 痛点 | 工具 | 一句话 |
|---|---|---|
| 每台服务器重复拉镜像,浪费带宽还触发 Docker Hub 限速 | docker-registry-proxy | 内网缓存代理,拉一次,全节点共享 |
| 不知道哪些容器有新版本,半夜偷偷更新把服务炸了 | WUD(What’s Up Docker) | 扫描所有主机,有更新推送到手机,手动决定升不升 |
| 多台机器东一个西一个,切来切去管理 | Komodo | 一个 Web 面板管所有 Docker 主机,支持 Git 自动部署 |
三件套全部 Docker 化,自身也跑在 Docker 里,不冲突,可共存。
位置选择:本地 vs 云端
先回答最重要的部署位置问题。
docker-registry-proxy(镜像缓存)
瓶颈是物理距离。 Docker 镜像动辄几百 MB,缓存的意义就是” 离得近”。
- 放本地 → 本地 PVE / KVM 秒取;荷兰 VPS 走国际链路,慢
- 放荷兰 VPS → VPS 秒取;本地走国际链路,慢
结论:双边部署,一边一个。 缓存代理几乎不耗 CPU,内存几十 MB,磁盘看你给多少(建议 20-50GB)。每台服务器指向离自己最近的那个 proxy。
WUD(更新监测)
WUD 需要连接 Docker socket 扫描容器。Docker socket 绝不能暴露在公网上(等同于 root 权限外泄)。
结论:部署在本地。 远程 VPS 通过 Tailscale 内网暴露 Docker API 给它。
Komodo(多机管理面板)
Komodo 架构是 Core(Web 面板)+ Periphery Agent(每台被管机器装一个)。Agent 主动连 Core,Core 不需要去连 Agent—— 天然穿越 NAT。
结论:放本地,24 小时开机的机器上。 你的 NUC9(fnOS)就是最佳位置。
前提:Tailscale 打通内网
所有服务间的通信都走 Tailscale 内网,不暴露任何端口到公网。
# 每一台机器执行curl -fsSL https://tailscale.com/install.sh | shtailscale up装完后每台机器获得 100.x.x.x 的内网 IP,后续所有配置用这个 IP。
如果已有 WireGuard 或其他 VPN,可以直接复用,原理一样。
镜像缓存:docker-registry-proxy
基于 nginx 的 MITM 缓存代理。工作方式:代理拦截 Docker 的 HTTPS 请求,把下载过的 layer / blob 缓存到本地磁盘。第二次拉同一层,直接从磁盘返回。
部署(本地 NUC9 上一份)
mkdir -p /opt/docker-registry-proxy/opt/docker-registry-proxy/docker-compose.yml:
services: registry-proxy: image: rpardini/docker-registry-proxy:0.6.5 container_name: docker-proxy restart: unless-stopped ports: - "3128:3128" environment: # 开启 manifest 缓存(防 Docker Hub 限速的关键) ENABLE_MANIFEST_CACHE: "true" # 磁盘缓存上限 CACHE_MAX_SIZE: "50g" # 额外要缓存的 registry(Docker Hub 默认包含,无需额外声明) REGISTRIES: "ghcr.io quay.io registry.k8s.io mcr.microsoft.com" # Docker Hub 认证 —— 用自己的账号,彻底告别限速10 collapsed lines
# username 用 Docker ID(不是邮箱) # password 建议用 Access Token(Docker Hub → Account Settings → Security) AUTH_REGISTRIES: "auth.docker.io:你的DockerHub用户名:你的AccessToken" DISABLE_IPV6: "true" # nginx 超时适当放大,应对大镜像 PROXY_READ_TIMEOUT: "600" PROXY_SEND_TIMEOUT: "600" volumes: - ./cache:/docker_mirror_cache - ./certs:/cacd /opt/docker-registry-proxy && docker compose up -d部署(荷兰 VPS 上同样一份)
直接 scp -r /opt/docker-registry-proxy 你的VPS:/opt/,端口冲突就改一下映射。
让其他服务器使用代理
在每台机器上编辑 /etc/docker/daemon.json:
{ "registry-mirrors": ["https://100.x.x.x:3128"]}
100.x.x.x是运行 proxy 那台机器的 Tailscale IP。本地机器指向本地 proxy,荷兰 VPS 指向 VPS 上那个 proxy。
systemctl restart docker验证:
docker pull alpine# 第一次正常拉取# 再拉一次,观察 proxy 日志:docker logs -f docker-proxy# 应该看到 "HIT" 字样,表示命中缓存注意事项
- 证书:proxy 自签 CA,首次连接需要把证书加入信任。重启 docker daemon 时会自动处理。
- 私有 registry:如果你的项目用到私有 registry(如 Harbor、GitLab Registry),在
AUTH_REGISTRIES里加上对应凭据即可。 - 磁盘清理:缓存目录会持续增长,可配合 cron 定期清理(proxy 自身会根据
CACHE_MAX_SIZE淘汰旧数据,一般不用手动管)。
多机管理:Komodo
Komodo 是近两年快速崛起的开源 Docker 管理面板。相比 Portainer:
- 完全开源(Apache 2.0),没有商业版功能锁
- 内置 CI / CD(监听 Git 仓库自动部署)
- 原生多服务器支持
- 现代 UI
架构
┌─────────────────┐ WebSocket ┌─────────────────┐│ Komodo Core │◄──────────────────────►│ Periphery Agent ││ (Web面板+DB) │ 加密长连接 │ (每台被管机器) ││ 放 NUC9 │ │ │ 独立部署 │└─────────────────┘ │ └─────────────────┘ │ ┌──────┴──────┐ │ Periphery │ │ Agent │ ... 每台一个 └─────────────┘Agent 主动连 Core,所以:
- Core 不需要公网 IP,NAT 后面也 OK
- Agent 不需要开放端口
- 通信全走 Tailscale 内网,安全
部署 Core(NUC9)
mkdir -p /opt/komodo/opt/komodo/docker-compose.yml:
services: komodo-core: image: ghcr.io/mbecker20/komodo:latest container_name: komodo-core restart: unless-stopped ports: - "9120:9120" environment: # 替换为你的随机长字符串(两处不要相同) KOMODO_PASSKEY: "生成一个32位以上的随机字符串" KOMODO_JWT_SECRET: "生成另一个32位以上的随机字符串" # 面板标题 KOMODO_TITLE: "我的HomeLab" KOMODO_DATA_PATH: "/data" KOMODO_DATABASE_ADDRESS: "mongo:27017"13 collapsed lines
volumes: - ./data:/data # 挂载本机 Docker socket —— 可以顺便管 NUC9 自己的容器 - /var/run/docker.sock:/var/run/docker.sock depends_on: - mongo
mongo: image: mongo:7 container_name: komodo-mongo restart: unless-stopped volumes: - ./mongo-data:/data/db生成随机密钥:
openssl rand -hex 32cd /opt/komodo && docker compose up -d访问 http://NUC9的Tailscale_IP:9120。首次打开会提示创建管理员账号。
部署 Periphery Agent(每台被管机器)
在 Komodo Web UI → Servers → Add Server,会生成一段命令。到对应的机器上执行即可。
本质上是:
docker run -d \ --name komodo-periphery \ --restart unless-stopped \ --network host \ -v /var/run/docker.sock:/var/run/docker.sock \ -e PERIPHERY_PASSKEY="你的KOMODO_PASSKEY" \ -e PERIPHERY_CORE_ADDRESS="http://NUC9的Tailscale_IP:9120" \ ghcr.io/mbecker20/periphery:latest用 --network host 是因为 Agent 需要访问 Docker socket 和 Core,host 模式最省事。
Komodo 日常用法
- Stack 管理:直接编辑 docker-compose.yml,点 Deploy
- Git 自动部署:配好 Git 仓库 → 推代码自动构建部署
- 容器终端:面板里点一下直接进容器 Shell
- 日志查看:实时流,不卡
- 资源监控:CPU/内存/磁盘图表
更新监测:WUD
WUD 的工作流程:
Watcher 扫描 Docker 主机 → 查 Registry 是否有新版本 → 有更新 → Trigger 通知你不自动更新。 这是刻意的设计 —— 更新决策应该由人来做,尤其是在生产环境。
部署(NUC9)
mkdir -p /opt/wud/opt/wud/docker-compose.yml:
services: wud: image: getwud/wud:latest container_name: wud restart: unless-stopped ports: - "3000:3000" volumes: - /var/run/docker.sock:/var/run/docker.sock:ro - ./data:/data environment: # ===== Watcher 配置 ===== # 1. 扫描本机(NUC9 自己) WUD_WATCHER_LOCAL_HOST: "/var/run/docker.sock" WUD_WATCHER_LOCAL_CRON: "0 0 * * * *" # 每小时查一次38 collapsed lines
# 2. 扫描远程 VPS(通过 Tailscale) # 远程 Docker 需要开启 TCP API —— 见下方说明 WUD_WATCHER_VPS1_TYPE: "tcp" WUD_WATCHER_VPS1_HOST: "tcp://100.xxx.xxx.xxx:2375" # VPS 的 Tailscale IP WUD_WATCHER_VPS1_CRON: "0 0 * * * *"
# 3. 第二台 VPS(如果有) WUD_WATCHER_VPS2_TYPE: "tcp" WUD_WATCHER_VPS2_HOST: "tcp://100.xxx.xxx.xxx:2375" WUD_WATCHER_VPS2_CRON: "0 0 * * * *"
# 4. 本地 PVE(同上) WUD_WATCHER_PVE_TYPE: "tcp" WUD_WATCHER_PVE_HOST: "tcp://100.xxx.xxx.xxx:2375" WUD_WATCHER_PVE_CRON: "0 0 * * * *"
# ===== 通知方式(选一个) ===== # 方案 A:ntfy(推荐)—— 免费,手机上装 ntfy app,订阅同一个频道 WUD_TRIGGER_NTFY_DEFAULT_URL: "https://ntfy.sh/你的私有频道名" WUD_TRIGGER_NTFY_DEFAULT_PRIORITY: "default" WUD_TRIGGER_NTFY_DEFAULT_TEMPLATE: | 📦 **{{name}}** 有新版本 当前: `{{current}}` → 最新: `{{latest}}` 主机: {{host}}
# 方案 B:Gotify —— 自建推送服务 # WUD_TRIGGER_GOTIFY_DEFAULT_URL: "http://你的gotify地址" # WUD_TRIGGER_GOTIFY_DEFAULT_TOKEN: "你的gotify token"
# ===== 排除规则(可选) ===== # 某些容器不希望监测(比如自己 build 的、开发中的) # WUD_WATCHER_LOCAL_WATCHER.EXCLUDE: "dev-*,test-*"
# ===== Web UI 访问控制 ===== WUD_AUTH_GITEA_CLIENTID: "false" WUD_UI_BASICAUTH_USER: "admin" WUD_UI_BASICAUTH_PASSWORD: "改个强密码"cd /opt/wud && docker compose up -d访问 http://NUC9的Tailscale_IP:3000,登录后能看到所有主机上哪些容器需要更新。
关于 cron 表达式:
"0 0 * * * *"是每小时整点扫描。WUD 用的 cron 是 6 位(多了秒位)。想改成每天凌晨 3 点:"0 0 3 * * *"。
远程 Docker 开启 TCP API(安全做法)
关键:只绑定 Tailscale 内网 IP,不绑定公网 IP。
VPS 上编辑 /etc/docker/daemon.json:
{ "hosts": [ "unix:///var/run/docker.sock", "tcp://100.x.x.x:2375" ]}注意:
100.x.x.x是这台 VPS 自己的 Tailscale IP。公网上根本无法路由到这个地址。
如果 Docker 是 systemd 管理的,直接改 hosts 可能会和 systemd 的 socket 冲突。需要 override:
mkdir -p /etc/systemd/system/docker.service.dcat > /etc/systemd/system/docker.service.d/override.conf << 'EOF'[Service]ExecStart=ExecStart=/usr/bin/dockerdEOFsystemctl daemon-reloadsystemctl restart docker验证:
# 从 NUC9 上测试连通性(用 Tailscale IP)curl http://100.x.x.x:2375/version# 返回 JSON 说明成功通知效果
手机上装 ntfy app,订阅你的频道名。当 WUD 发现有容器可以更新时,你会收到:
📦 nginx 有新版本当前: 1.25.3 → 最新: 1.27.0主机: vps-hh然后你自己判断要不要升、什么时候升。
最终拓扑图
荷兰 VPS ×2 本地局域网 ┌──────────────────┐ ┌──────────────────────────┐ │ Periphery Agent │ │ NUC9 (fnOS) - 24h 常开 │ │ docker-registry- │ │ ┌─────────────────────┐ │ │ proxy │ │ │ Komodo Core (9120) │ │ │ Docker TCP API │ │ │ WUD (3000) │ │ └────────┬─────────┘ │ │ docker-registry- │ │ │ │ │ proxy (3128) │ │ │ Tailscale 内网 │ └──────────┬──────────┘ │ ├────────────────────────┤ │ │ │ 加密 WireGuard │ ┌──────┴──────┐ │ │ │ │ PVE (KVM) │ │ ┌────────┴─────────┐ │ │ Agent+Proxy │ │ │ 第二台 VPS │ │ └─────────────┘ │ │ Agent+Proxy │ └──────────────────────────┘13 collapsed lines
└──────────────────┘
───── 镜像拉取路径 ───── 本地机器 → 本地 proxy (3128) → 命中缓存,秒取 VPS → VPS proxy (3128) → 命中缓存,秒取
───── 管理通信路径 ───── Komodo Agent ──WebSocket──▶ Komodo Core (一切走 Tailscale 内网) WUD Watcher ──TCP:2375──▶ 远程 Docker API
───── 更新通知路径 ───── WUD 发现更新 → ntfy.sh → 手机推送快速部署清单
按顺序执行:
| 步骤 | 操作 | 在哪台机器 |
|---|---|---|
| 1 | 装 Tailscale 并加入网络 | 所有机器 |
| 2 | 部署 docker-registry-proxy | NUC9 + 荷兰 VPS |
| 3 | 配置 daemon.json 指向 proxy | 所有机器(各自指向最近的 proxy) |
| 4 | 部署 Komodo Core + Mongo | NUC9 |
| 5 | 部署 Komodo Periphery Agent | 每台被管机器 |
| 6 | 配置远程 Docker TCP API(仅 Tailscale IP) | 需要被 WUD 扫描的远程机器 |
| 7 | 部署 WUD | NUC9 |
| 8 | 手机上装 ntfy | 手机 |
日常运维流程
部署完成后,日常的 Docker 管理就变成:
- 部署新服务:打开 Komodo → 写 compose → 点 Deploy
- 看日志:Komodo → 点容器 → Logs
- 进容器调试:Komodo → 点容器 → Terminal
- 收到更新通知:手机弹出 ntfy → 看一眼 changelog → 决定更不更
- 拉镜像:自动走 proxy 缓存,不用管
- 新增机器:装 Tailscale + Komodo Agent + 配 daemon.json,五分钟加入管理
相关链接
| 工具 | 地址 |
|---|---|
| docker-registry-proxy | https://github.com/rpardini/docker-registry-proxy |
| Komodo | https://komo.do |
| WUD | https://getwud.github.io/wud |
| ntfy | https://ntfy.sh |
| Tailscale | https://tailscale.com |