refactor(skills): slim ack/builder/deployer for layered loading

Move mode-specific steps into references so SKILL.md only keeps routing and fail-closed rules.
This commit is contained in:
2026-08-26 11:26:58 +08:00
parent 2be0964d73
commit ef22c6829e
6 changed files with 308 additions and 784 deletions
+33 -292
View File
@@ -1,23 +1,15 @@
---
name: deployer
description: >-
初始化或检查项目部署配置,并管理两类部署:多机 Docker Compose仓库存
compose.yaml 与静态配置,本 skill 脚本同步到 SSH 节点后 docker compose 应用),
以及 Argo CD GitOps(改 GitOps 仓库清单、开 PR/MR,用户合并后由 Argo CD 同步)
当用户要求初始化 deployer、接入测试/生产环境、检查 .pouch/deployer 是否齐全;
或部署、同步、升级、重启远程 Compose 服务,向节点装 deb,新增/迁移/下线服务,
梳理节点清单,make deploy TGT、_config.yaml、rsync、tar over SSH、NAS 部署失败;
或要求 ArgoCD / GitOps / K8s 部署、更新 Application、升镜像 tag、开 MR 让用户
合并部署;或 ACK 要求拉起/重布项目测试环境时使用。
初始化或检查项目部署配置;管理多机 Docker Compose脚本同步后远程
compose)与 Argo CD GitOps(改清单开 MR,用户合并后同步)。触发词:初始化
deployer、部署、sync、升级、装 deb、ArgoCD、GitOps;ACK 拉起测试环境时也可使用
---
# deployerCompose 节点与 Argo CD GitOps
两条轨道,配置都在仓库里,方法由本 skill 提供。
- **Compose**:本地改 `compose.yaml` → 脚本同步到 SSH 节点 → 远程 `docker compose`
- **Argo CD**:改 GitOps 仓库清单 → 开 PR/MR → 用户合并 → Argo CD 同步。不要用
Compose 的 `sync.py`/`remote.py` 去推集群。
- **Argo CD**:改 GitOps 仓库清单 → 开 PR/MR → 用户合并 → Argo CD 同步。不要用 Compose 的 `sync.py`/`remote.py` 去推集群。
开始时解析当前 `SKILL.md` 所在目录,记为 `<skill-dir>`。优先
`git rev-parse --show-toplevel` 解析项目根。不要创建 `.pouch/deployer/` 之外的
@@ -25,114 +17,39 @@ description: >-
## 选择模式
- 用户要求初始化、接入 deployer,或给新项目建测试/生产环境:执行初始化
- 用户要求检查 `.pouch/deployer`、node、compose 是否齐全:执行检查
- 用户要求部署、同步、升级、重启、装 deb、开 GitOps MR:执行下面对应轨道步骤
发现不了服务或解析不出 node 时停止,转入“初始化”。不要静默初始化
- 初始化、接入 deployer,或给新项目建测试/生产环境:执行初始化
- 检查 `.pouch/deployer`、node、compose 是否齐全:执行检查
- 部署、同步、升级、重启、装 deb、新增/下线服务:执行「Compose 操作」。发现不了服务或解析不出 node 时停止,转入「初始化」。不要静默初始化
- ArgoCD / GitOps / 开 MR 部署:执行「Argo CD」。步骤见 [argocd.md](references/argocd.md)
- 两者都有且意图不清:先问。
- 不适用:单机 docker、Nomad、常规 `kubectl apply`、构建并推送镜像(走 builder)。
## 何时使用
## 边界
- 部署 / 同步 / 升级 / 重启某个远程 Docker Compose 服务
- 向节点安装 deb 包:scp 上传本地 .deb 后 dpkg/apt 安装,或从 URL 远程拉取安装
- 新增、迁移、下线一个服务;梳理「哪台机器跑什么」
- sync 失败排查、证书丢失、改了配置不生效等运维问题
- 提到 `make deploy TGT=...``TGT=``_config.yaml`、rsync/tar 同步
- Argo CD / GitOps / 集群部署:新增 Application、改清单、升镜像 tag、开 MR 等用户合并
- ACK Coordinator 拉起或重布项目测试环境(`.pouch/deployer/<env>`
- 初始化 deployer、给项目接上 test/prod、检查部署配置缺什么
## 不适用
- 单机 docker 日常使用(无多机同步诉求)
- Nomad,或绕过 GitOps 用 `kubectl apply` 当常规发布
- 构建并推送镜像(走 builder);本 skill 只改 GitOps 里对该镜像的引用
---
## 核心模型(先读懂再动手)
### 轨道选择
| 信号 | 轨道 |
|------|------|
| ArgoCD / GitOps / 集群 / 开 MR 部署 / 项目有 `.pouch/deployer/argocd.yaml` | Argo CD,见 [argocd.md](references/argocd.md) |
| sync、`TGT=`、某台机器、`compose.yaml` | Compose(下文布局与步骤) |
| 两者都有且意图不清 | 先问 |
### Compose
- **仓库只放数据**`compose.yaml`、Caddyfile、Traefik 动态配置等静态配置进 Git;
运行时数据(证书、数据库、上传文件)永不进 Git,也永不参与同步范围。
- **每个可部署服务目录必须有 `compose.yaml`**,且能解析出目标节点 `node`
(来自该目录、部署根或祖先目录的 `_config.yaml`,或父目录名恰为 SSH Host 别名)。
- **`node` 即 SSH Host 别名**`~/.ssh/config`),支持 `user@host` 形式。
- `unused/` 下不参与自动发现与部署。
### Argo CD
源项目 `.pouch/deployer/argocd.yaml``repo` 写 Git 地址(部署时浅 clone),或加 `repo_dir` 用已有 checkout。
改 GitOps 清单,不要改 Compose 脚本。密钥不入库。两种接法见 skill README,步骤见 [argocd.md](references/argocd.md)。
### 两种 Compose 布局
**A. 独立配置中心仓库**(如 app00):仓库根即部署根,
`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 # 生产 compose 与配置
│ └── _config.yaml # 环境级覆盖
├── test/compose.yaml
└── dev/compose.yaml
```
项目模式下远程目录名自动加项目前缀 `{git仓库名}-{env}`
(如 `my-project-prod`),防止同主机多项目的同名环境互相覆盖;
`_config.yaml``name:` 可显式指定。
- 所有 sync/up/recreate/upgrade/restart 必须按单服务执行,禁止节点级批量。
- `rsync``--delete`:运行时数据必须在 `data/``_data/` 或远程绝对路径挂载,否则会被清掉。
- 仓库只放静态配置;证书、数据库、上传文件不进 Git,也不进同步范围。`unused/` 不参与发现与部署。
- `node``~/.ssh/config` 的 Host 别名(可用 `user@host`)。用户没给别名就不要写假 node。
- 密钥不入库。Compose 优先放远程 `.env`Argo CD 的 dockerconfigjson / TLS 私钥只存在集群 Secret。
- `--force` 推送、不硬 reset,除非用户明确要求。Argo CD 不直接推默认分支。
- 镜像固定 tag,不用 `:latest`;成对升级的服务要同步升。
- ACK 调用不能把范围扩到生产环境、Argo 合入或节点级批量。
## 初始化
独立配置中心仓库(已设 `DEPLOYER_ROOT`)只做检查,不要改成项目内布局。
独立配置中心仓库(已设 `DEPLOYER_ROOT`)只做检查,不要改成项目内布局。`_config.yaml` 字段见 [config-reference.md](references/config-reference.md)。
1. 探测:`.pouch/deployer/`、根目录 `compose.yaml`/`docker-compose.yml`
`Dockerfile`、ACK `intents.testEnvironment``.pouch/deployer/argocd.yaml`
1. 探测:`.pouch/deployer/`、根目录 compose`Dockerfile`、ACK `intents.testEnvironment``argocd.yaml`
2. Compose 与 Argo 都有且意图不清:先问。两边都要也可以,必须分开确认。
3. **Compose / 新项目**ACK 默认需要 `test`):
- 问环境:默认只建 `test``prod`/`dev` 用户点名再加。不默默建空的 prod
- 问 SSH Host 别名(必须在 `~/.ssh/config`)。没给就**不要写假 node**;
目录可以建,`_config.yaml` 列为待配置。
- 有根目录 compose:提议迁到 `.pouch/deployer/<env>/`,确认后才动。
- 只有 Dockerfile:可给**单服务** compose 草稿(镜像名来自仓库名),用户确认
后写入。不发明多服务网格。
4. **Argo**:只问 GitOps `repo`(或 `repo_dir`),写 `.pouch/deployer/argocd.yaml`
不 clone、不开 MR、不 `kubectl apply`
3. Compose / 新项目(ACK 默认需要 `test`):默认只建 `test``prod`/`dev` 用户点名再加。问 SSH Host 别名;没给不要写假 node,目录可建、列为待配置。有根目录 compose:提议迁到 `.pouch/deployer/<env>/`,确认后才动。只有 Dockerfile:可给单服务 compose 草稿,用户确认后写入,不发明多服务网格。
4. Argo:只问 GitOps `repo`(或 `repo_dir`),写 `.pouch/deployer/argocd.yaml`。不 clone、不开 MR、不 `kubectl apply`
5. 运行(不 SSH、不 up):
```bash
python3 -I -S <skill-dir>/scripts/deploy/check.py --project <project-root>
```
```bash
python3 -I -S <skill-dir>/scripts/deploy/check.py --project <project-root>
```
6. 按下面格式报告。缺 `node` / compose / ssh 别名 = 部分完成或阻塞。
不覆盖已有 compose/`_config.yaml`。除非用户明确要求,不部署、不提交。
6.`node` / compose / ssh 别名 = 部分完成或阻塞。不覆盖已有 compose/`_config.yaml`。除非用户明确要求,不部署、不提交。
```text
## deployer 初始化:完成 | 部分完成 | 阻塞
@@ -143,194 +60,18 @@ my-project/
下一步: 一句话
```
`_config.yaml` 示例(`node` 必须是用户给出的 SSH Host 别名):
```yaml
# .pouch/deployer/_config.yaml
node: my-vps
base_path: /opt/app
```
## 检查
只读。运行 `scripts/deploy/check.py --project <project-root>`,用同一报告格式,
标题改为 `## deployer 检查:…`。不写文件、不 SSH 连接。用户明确要求修复后再转入
初始化。
只读。运行 `scripts/deploy/check.py --project <project-root>`,用同一报告格式,标题改为 `## deployer 检查:…`。不写文件、不 SSH。用户明确要求修复后再转入初始化。
## 被 ACK 调用
ACK 的「运行测试环境」和回归前布环境会加载本 skill,对项目
`.pouch/deployer/<env>`(通常是 `test`)按下面 Compose 轨道执行。ACK 只负责何时
布、把访问地址写入 `deliveryRuns`;不要把本 skill 的脚本复制进 ACK。生产环境、
Argo CD 合入和节点级批量操作仍须用户明确要求,不能因为 ACK 调用就扩大范围。
ACK 的「运行测试环境」和回归前布环境会加载本 skill,对 `.pouch/deployer/<env>`(通常是 `test`)按「Compose 操作」执行。ACK 只负责何时布、把访问地址写入 `deliveryRuns`;不要把本 skill 的脚本复制进 ACK。生产环境、Argo CD 合入和节点级批量仍须用户明确要求。
## 步骤
## Compose 操作
### Compose 轨道
读 [compose.md](references/compose.md)。用 `list.py` 摸底,再按意图对**单个服务**执行 sync/up/recreate/upgrade/restart。解析 `_config.yaml` 见 [config-reference.md](references/config-reference.md)。sync 报错但 ssh 正常时,按 compose.md 的 NAS 兜底处理。每次操作后 `remote.py <svc> ps` / `logs` 验证。
#### 0. 定位部署根
## Argo CD
skill 目录下的 `scripts/deploy/` 是通用部署工具链(lib/sync/remote/list),
不依赖具体项目路径。部署根按以下顺序解析:
1. 环境变量 `DEPLOYER_ROOT` 显式指定(独立配置中心仓库用这个)
2. 从当前目录向上找 `.pouch/deployer/`(项目内环境布局自动发现)
3. skill 安装位置兜底(仅用于查看,没有可部署服务)
```bash
# <skill-dir> = 本 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
```
#### 1. 摸底:列出服务与节点
上一步的 `list.py` 输出全部服务与节点分布;新增环境/服务后重跑确认被发现。
项目布局下 `prod/test/dev` 各显示为 `{项目名}-{env}`。`argocd.yaml` 不会被 list.py 当成 compose 服务。
#### 2. 解析单个服务
```bash
# 查看 node、远程路径、排除规则(sync.py 干跑会打印这些信息)
python3 <skill-dir>/scripts/deploy/sync.py <service-path>
```
或直接读服务目录及祖先的 `_config.yaml`。
#### 3. 命令选择(语义严格区分)
| 意图 | 命令 |
|------|------|
| 只同步文件,不动容器 | `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` |
#### 4. 项目侧 Makefile(可选薄封装)
若项目有 Makefile 封装,命令形如 `make deploy TGT=<服务路径>`。
没有 Makefile 时直接调 python 脚本即可,不要新建封装层。
#### 5. 新增服务 / 环境 checklist
独立仓库布局:
1. 在合适分类目录创建服务文件夹,写 `compose.yaml`
2. 在服务目录或祖先目录放 `_config.yaml`(至少能解析出 `node`
3. 有运行时目录 → 加进 `sync_exclude`
4. 远程首次建目录:`ssh <node> "mkdir -p <base_path>/<name>"`
5. 首次部署:sync + up
6. 验证:ps + logs,必要时 curl/ssh 检查端口
项目环境布局:
1. 项目根建 `.pouch/deployer/{env}/`env 通常为 prod/test/dev
2. 每个环境写 `compose.yaml`;三个环境共享的 node/base_path 放
`.pouch/deployer/_config.yaml`
3. 环境有差异(不同主机、不同排除项)→ 在该环境的 `_config.yaml` 覆盖
4. 同名冲突或需要固定远程目录名 → `_config.yaml` 写 `name:`
5. 首次部署前确认目标主机的远程目录不存在旧内容(rsync `--delete` 会清掉)
#### 6. 下线服务
独立仓库布局:配置移入 `unused/`(自动脱离发现体系),远程按需手动清理:
`ssh <node> "cd <base_path>/<name> && docker compose down"`,数据卷按需保留或删除。
项目环境布局:删除对应 `.pouch/deployer/{env}/` 目录即可脱离发现体系,远程清理同上。
#### 7. 向节点安装 deb 包
`deb.py` 把 deb 包发到节点并安装。目标两种写法:仓库内目录
(复用 `_config.yaml` 继承链解析 node/port/identity_file,如 `hosts/web1`),
或裸 SSH 别名 / `user@host`(须在 `~/.ssh/config` 中,可加 `--port`/`--identity`)。
```bash
# 本地 .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(配合 scp 分步操作)
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>"`。
### Argo CD 轨道
完整步骤与 `argocd.yaml` 字段见 [argocd.md](references/argocd.md)。
1. 读项目 `.pouch/deployer/argocd.yaml`(无则只问 Git 地址,写成 `repo:`)。
有 `repo_dir` 则用该目录;否则把 `repo` 浅 clone 到临时目录,用完删除。
2. 在工作副本里按**已有应用惯例**新增 Application,或只改镜像 tag / 清单。
3. 从最新默认分支拉出分支,commit、push,用 `glab`/`gh`/`tea` 开 MRCLI 对项目 404 则把
`git push` 给出的网页建单链接交给用户。
4. **停在 MR**,不合并、不 `kubectl apply` 工作负载。
5. 无 app-of-apps 时提醒用户首次 `kubectl apply` 那份 `application.yaml`。
6. Harbor 拉镜像 Secret、TLS Secret 不入库;只在工作负载所在 ns 准备,可从其他 ns 拷贝。
---
## 注意事项
- **禁止节点级批量操作**:所有 sync/up/recreate/upgrade/restart 必须按单服务执行。
批量升级风险过高,逐个来。
- **rsync 带 `--delete`**:远程多余文件会被删除。运行时数据必须放在
默认排除的 `data/`、`_data/`,或 compose 挂载的远程绝对路径
(如 `/data01/docker/<svc>/`),否则会被清掉。
- **镜像固定 tag**,不用 `:latest` 漂移;成对升级的服务(如 proxy 客户端/服务端)要同步升。
- **密钥**Compose 优先放远程 `.env`Argo CD 的 dockerconfigjson / TLS 私钥只存在集群 Secret。
不要提交新密钥进 Git。
- **Git 安全**:不 `--force` 推送、不硬 reset,除非用户明确要求。Argo CD 轨道不直接推默认分支。
- **NAS / Synology 特例**:部分 NAS 的 SSH 用户禁用 rsync 协议(Permission denied)。
表现是 sync 报错但 ssh 正常。处理顺序:
1. 该节点 `_config.yaml` 写真实 `base_path`(如 `/volume1/docker`,避开符号链接路径)
2. 仍失败则手动 tar over SSH 推送:
```bash
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 删除。
3. Synology 上 docker 路径可能是 `/usr/local/bin/docker`
## 验证
- Compose`list.py` 输出全部服务与节点分布,数量与预期一致
- 每次 sync/deploy 后 `remote.py <svc> ps` 容器 Up、`logs` 无报错
- 升级后额外确认镜像 tag 与 compose.yaml 一致
- 改 Traefik/Caddy 路由后 curl 对应域名验证生效
- Argo CD:MR 可打开且含本次清单;用户合并后 Application Synced;有 Ingress 则 curl healthz
## scripts/
| 文件 | 用途 |
|------|------|
| `scripts/deploy/lib.py` | 解析服务目录、合并继承 `_config.yaml`、SSH/rsync/scp 参数构造 |
| `scripts/deploy/sync.py` | rsync -avz --delete 同步;无 rsync 时 tar over SSH 兜底 |
| `scripts/deploy/remote.py` | SSH 远程 docker composeup/recreate/restart/upgrade/ps/logs |
| `scripts/deploy/deb.py` | deb 包分发安装:push(scp+apt)/scp/dpkg/apt(URL) |
| `scripts/deploy/list.py` | 扫描全部可部署服务 |
| `scripts/deploy/check.py` | 只读就绪检查:布局、compose、node、ssh config、工具链 |
## references/
| 文件 | 用途 |
|------|------|
| `references/config-reference.md` | `_config.yaml` 字段完整说明与继承合并规则 |
| `references/argocd.md` | Argo CD 轨道:`argocd.yaml`、新增/升级、开 MR、ns 级 Secret |
读 [argocd.md](references/argocd.md)。读 `.pouch/deployer/argocd.yaml`(无则只问 Git 地址写成 `repo:`)。按已有应用惯例改清单,从默认分支拉出分支开 MR。**停在 MR**,不合并、不 `kubectl apply` 工作负载。无 app-of-apps 时提醒用户首次 apply 那份 `application.yaml`。Harbor / TLS Secret 不入库。
+161
View File
@@ -0,0 +1,161 @@
# Compose 轨道
同步文件、远程 `docker compose`、装 deb、新增/下线服务。Argo CD 不走本文件。
## 目录
- [两种布局](#两种布局)
- [定位部署根](#定位部署根)
- [列出服务](#列出服务)
- [命令选择](#命令选择)
- [新增服务 / 环境](#新增服务--环境)
- [下线服务](#下线服务)
- [安装 deb](#安装-deb)
- [NAS / rsync 失败](#nas--rsync-失败)
- [验证](#验证)
## 两种布局
**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/` 是通用工具链,不依赖具体项目路径。部署根顺序:
1. 环境变量 `DEPLOYER_ROOT`(独立配置中心仓库用这个)
2. 从当前目录向上找 `.pouch/deployer/`(项目内环境布局)
3. skill 安装位置兜底(仅查看,没有可部署服务)
```bash
# <skill-dir> = 本 skill 的 SKILL.md 所在目录
# 布局 A
export DEPLOYER_ROOT=/path/to/your-compose-repo
python3 <skill-dir>/scripts/deploy/list.py
# 布局 Bcwd 在项目里即可
python3 <skill-dir>/scripts/deploy/list.py
```
## 列出服务
`list.py` 输出全部服务与节点分布;新增环境/服务后重跑确认被发现。项目布局下 `prod/test/dev` 各显示为 `{项目名}-{env}``argocd.yaml` 不会被当成 compose 服务。
查看单个服务的 node、远程路径、排除规则:
```bash
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 挂载的远程绝对路径,否则会被清掉。
## 新增服务 / 环境
独立仓库布局:
1. 在合适分类目录创建服务文件夹,写 `compose.yaml`
2. 在服务目录或祖先目录放 `_config.yaml`(至少能解析出 `node`
3. 有运行时目录 → 加进 `sync_exclude`
4. 远程首次建目录:`ssh <node> "mkdir -p <base_path>/<name>"`
5. 首次部署:sync + up
6. 验证:ps + logs,必要时 curl/ssh 检查端口
项目环境布局:
1. 项目根建 `.pouch/deployer/{env}/`env 通常为 prod/test/dev
2. 每个环境写 `compose.yaml`;共享的 node/base_path 放 `.pouch/deployer/_config.yaml`
3. 环境有差异 → 在该环境的 `_config.yaml` 覆盖
4. 同名冲突或需要固定远程目录名 → `_config.yaml``name:`
5. 首次部署前确认目标主机的远程目录不存在旧内容(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`)。
```bash
# 本地 .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 正常。处理顺序:
1. 该节点 `_config.yaml` 写真实 `base_path`(如 `/volume1/docker`,避开符号链接路径)
2. 仍失败则手动 tar over SSH
```bash
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 对应域名验证生效