Move mode-specific steps into references so SKILL.md only keeps routing and fail-closed rules.
6.6 KiB
Compose 轨道
同步文件、远程 docker compose、装 deb、新增/下线服务。Argo CD 不走本文件。
目录
两种布局
A. 独立配置中心仓库:仓库根即部署根,DEPLOYER_ROOT=/path/to/repo 指定后按仓库内相对路径操作:
repo/
├── _config.yaml # 可选,全局默认
├── vyyo1/_config.yaml # node: vyyo1(主机目录)
│ └── naiveproxy/ # 服务目录:compose.yaml + 可选 _config.yaml
└── unused/
远程目录名 = 目录末级名:vyyo1/naiveproxy → /opt/app/naiveproxy。
B. 项目内环境布局:项目根放 .pouch/deployer/{prod,test,dev}/,每个环境一个目录。从项目内任意位置运行脚本即自动发现(也可用 DEPLOYER_ROOT 显式指定):
my-project/
├── src/ ...
└── .pouch/deployer/
├── _config.yaml # 三个环境共享默认(node/base_path 等)
├── argocd.yaml # 可选,Argo CD 指针(不是 compose 环境)
├── prod/
│ ├── compose.yaml
│ └── _config.yaml # 环境级覆盖
├── test/compose.yaml
└── dev/compose.yaml
项目模式下远程目录名自动加项目前缀 {git仓库名}-{env}(如 my-project-prod);_config.yaml 写 name: 可显式指定。
定位部署根
scripts/deploy/ 是通用工具链,不依赖具体项目路径。部署根顺序:
- 环境变量
DEPLOYER_ROOT(独立配置中心仓库用这个) - 从当前目录向上找
.pouch/deployer/(项目内环境布局) - skill 安装位置兜底(仅查看,没有可部署服务)
# <skill-dir> = 本 skill 的 SKILL.md 所在目录
# 布局 A
export DEPLOYER_ROOT=/path/to/your-compose-repo
python3 <skill-dir>/scripts/deploy/list.py
# 布局 B:cwd 在项目里即可
python3 <skill-dir>/scripts/deploy/list.py
列出服务
list.py 输出全部服务与节点分布;新增环境/服务后重跑确认被发现。项目布局下 prod/test/dev 各显示为 {项目名}-{env}。argocd.yaml 不会被当成 compose 服务。
查看单个服务的 node、远程路径、排除规则:
python3 <skill-dir>/scripts/deploy/sync.py <service-path>
或读服务目录及祖先的 _config.yaml。
命令选择
语义严格区分,必须按单服务执行:
| 意图 | 命令 |
|---|---|
| 只同步文件,不动容器 | sync.py <svc> |
| 应用 compose/配置变更 | sync.py <svc> && remote.py <svc> up |
| 改配置后强制重建 | remote.py <svc> recreate(配合前置 sync) |
| 镜像 tag 变更升级 | sync.py <svc> && remote.py <svc> upgrade |
| 仅重启,不同步文件 | remote.py <svc> restart |
| 排查 | remote.py <svc> ps / remote.py <svc> logs |
若项目有 Makefile 封装,命令形如 make deploy TGT=<服务路径>。没有 Makefile 时直接调 python 脚本,不要新建封装层。
sync.py 使用 rsync -avz --delete;本机无 rsync 时 tar over SSH 兜底。运行时数据必须放在默认排除的 data/、_data/,或 compose 挂载的远程绝对路径,否则会被清掉。
新增服务 / 环境
独立仓库布局:
- 在合适分类目录创建服务文件夹,写
compose.yaml - 在服务目录或祖先目录放
_config.yaml(至少能解析出node) - 有运行时目录 → 加进
sync_exclude - 远程首次建目录:
ssh <node> "mkdir -p <base_path>/<name>" - 首次部署:sync + up
- 验证:ps + logs,必要时 curl/ssh 检查端口
项目环境布局:
- 项目根建
.pouch/deployer/{env}/(env 通常为 prod/test/dev) - 每个环境写
compose.yaml;共享的 node/base_path 放.pouch/deployer/_config.yaml - 环境有差异 → 在该环境的
_config.yaml覆盖 - 同名冲突或需要固定远程目录名 →
_config.yaml写name: - 首次部署前确认目标主机的远程目录不存在旧内容(rsync
--delete会清掉)
下线服务
独立仓库布局:配置移入 unused/(自动脱离发现体系),远程按需手动清理:
ssh <node> "cd <base_path>/<name> && docker compose down",数据卷按需保留或删除。
项目环境布局:删除对应 .pouch/deployer/{env}/ 目录即可脱离发现体系,远程清理同上。
安装 deb
deb.py 把 deb 包发到节点并安装。目标两种写法:仓库内目录(复用 _config.yaml 继承链解析 node/port/identity_file,如 hosts/web1),或裸 SSH 别名 / user@host(须在 ~/.ssh/config 中,可加 --port/--identity)。
# 本地 .deb → scp 上传 → 远程 apt 安装(失败自动 apt -f 修依赖),成功后删暂存包
python3 <skill-dir>/scripts/deploy/deb.py <target> push ./foo_1.0_amd64.deb --yes
# 仅上传到远程暂存目录(默认 {base_path}/.debs;裸主机为 /tmp/deployer-debs)
python3 <skill-dir>/scripts/deploy/deb.py <target> scp ./foo_1.0_amd64.deb
# 安装该节点暂存目录里已上传的全部 .deb
python3 <skill-dir>/scripts/deploy/deb.py <target> dpkg --yes
# 远程直接从 URL 下载安装
python3 <skill-dir>/scripts/deploy/deb.py <target> apt https://example.com/foo_1.0_amd64.deb --yes
- 非 root 用户走
sudo -n(需免密 sudo);--yes传-y。没配 sudo 免密时会直接失败。 - 升级同版本号前可
ssh <node> "dpkg -I <暂存路径>";装完验证:ssh <node> "dpkg -l | grep <pkg>"。
NAS / rsync 失败
部分 NAS 的 SSH 用户禁用 rsync 协议(Permission denied)。表现是 sync 报错但 ssh 正常。处理顺序:
- 该节点
_config.yaml写真实base_path(如/volume1/docker,避开符号链接路径) - 仍失败则手动 tar over SSH:
tar czf - -C <服务目录> . --exclude='data' --exclude='_data' \
| ssh <node> "mkdir -p <base_path>/<name> && cd <base_path>/<name> && tar xzf -"
ssh <node> "cd <base_path>/<name> && /usr/local/bin/docker compose up -d"
tar 不会删除远程多余文件;需清理旧文件时手动 SSH 删除。Synology 上 docker 路径可能是 /usr/local/bin/docker。
验证
list.py输出全部服务与节点分布,数量与预期一致- 每次 sync/deploy 后
remote.py <svc> ps容器 Up、logs无报错 - 升级后额外确认镜像 tag 与
compose.yaml一致 - 改 Traefik/Caddy 路由后 curl 对应域名验证生效