--- name: deployer description: >- 管理两类部署:多机 Docker Compose(仓库存 compose.yaml 与静态配置,本 skill 脚本 同步到 SSH 节点后 docker compose 应用),以及 Argo CD GitOps(改 GitOps 仓库清单、 开 PR/MR,用户合并后由 Argo CD 同步)。当用户要求部署、同步、升级、重启远程 Compose 服务,向节点装 deb,新增/迁移/下线服务,梳理节点清单,make deploy TGT、 _config.yaml、rsync、tar over SSH、NAS 部署失败;或要求 ArgoCD / GitOps / K8s 部署、更新 Application、升镜像 tag、开 MR 让用户合并部署时使用。 --- # deployer:Compose 节点与 Argo CD GitOps 两条轨道,配置都在仓库里,方法由本 skill 提供。 - **Compose**:本地改 `compose.yaml` → 脚本同步到 SSH 节点 → 远程 `docker compose`。 - **Argo CD**:改 GitOps 仓库清单 → 开 PR/MR → 用户合并 → Argo CD 同步。不要用 Compose 的 `sync.py`/`remote.py` 去推集群。 --- ## 何时使用 - 部署 / 同步 / 升级 / 重启某个远程 Docker Compose 服务 - 向节点安装 deb 包:scp 上传本地 .deb 后 dpkg/apt 安装,或从 URL 远程拉取安装 - 新增、迁移、下线一个服务;梳理「哪台机器跑什么」 - sync 失败排查、证书丢失、改了配置不生效等运维问题 - 提到 `make deploy TGT=...`、`TGT=`、`_config.yaml`、rsync/tar 同步 - Argo CD / GitOps / 集群部署:新增 Application、改清单、升镜像 tag、开 MR 等用户合并 ## 不适用 - 单机 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:` 可显式指定。 ## 步骤 ### Compose 轨道 #### 0. 定位部署根 skill 目录下的 `scripts/deploy/` 是通用部署工具链(lib/sync/remote/list), 不依赖具体项目路径。部署根按以下顺序解析: 1. 环境变量 `DEPLOYER_ROOT` 显式指定(独立配置中心仓库用这个) 2. 从当前目录向上找 `.pouch/deployer/`(项目内环境布局自动发现) 3. skill 安装位置兜底(仅用于查看,没有可部署服务) ```bash # = 本 SKILL.md 所在目录,先解析出来记下 # 布局 A:显式指定仓库根 export DEPLOYER_ROOT=/path/to/your-compose-repo python3 /scripts/deploy/list.py # 布局 B:在项目内直接跑即可(cwd 在项目里) python3 /scripts/deploy/list.py ``` #### 1. 摸底:列出服务与节点 上一步的 `list.py` 输出全部服务与节点分布;新增环境/服务后重跑确认被发现。 项目布局下 `prod/test/dev` 各显示为 `{项目名}-{env}`。`argocd.yaml` 不会被 list.py 当成 compose 服务。 #### 2. 解析单个服务 ```bash # 查看 node、远程路径、排除规则(sync.py 干跑会打印这些信息) python3 /scripts/deploy/sync.py ``` 或直接读服务目录及祖先的 `_config.yaml`。 #### 3. 命令选择(语义严格区分) | 意图 | 命令 | |------|------| | 只同步文件,不动容器 | `sync.py ` | | 应用 compose/配置变更 | `sync.py && remote.py up` | | 改配置后强制重建 | `remote.py recreate`(配合前置 sync) | | 镜像 tag 变更升级 | `sync.py && remote.py upgrade` | | 仅重启,不同步文件 | `remote.py restart` | | 排查 | `remote.py ps` / `remote.py logs` | #### 4. 项目侧 Makefile(可选薄封装) 若项目有 Makefile 封装,命令形如 `make deploy TGT=<服务路径>`。 没有 Makefile 时直接调 python 脚本即可,不要新建封装层。 #### 5. 新增服务 / 环境 checklist 独立仓库布局: 1. 在合适分类目录创建服务文件夹,写 `compose.yaml` 2. 在服务目录或祖先目录放 `_config.yaml`(至少能解析出 `node`) 3. 有运行时目录 → 加进 `sync_exclude` 4. 远程首次建目录:`ssh "mkdir -p /"` 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 "cd / && 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 /scripts/deploy/deb.py push ./foo_1.0_amd64.deb --yes # 仅上传到远程暂存目录(默认 {base_path}/.debs;裸主机为 /tmp/deployer-debs) python3 /scripts/deploy/deb.py scp ./foo_1.0_amd64.deb # 安装该节点暂存目录里已上传的全部 .deb(配合 scp 分步操作) python3 /scripts/deploy/deb.py dpkg --yes # 远程直接从 URL 下载安装(机器能出网时免上传) python3 /scripts/deploy/deb.py apt https://example.com/foo_1.0_amd64.deb --yes ``` - 非 root 用户走 `sudo -n`(需配好免密 sudo);`--yes` 传 `-y` 免交互, 无终端交互能力,没配 sudo 免密/密钥时会直接失败。 - 升级同版本号前想先看包信息:`ssh "dpkg -I <暂存路径>"`; 装完验证:`ssh "dpkg -l | grep "`。 ### 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` 开 MR;CLI 对项目 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//`),否则会被清掉。 - **镜像固定 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 "mkdir -p / && cd / && tar xzf -" ssh "cd / && /usr/local/bin/docker compose up -d" ``` tar 不会删除远程多余文件;需清理旧文件时手动 SSH 删除。 3. Synology 上 docker 路径可能是 `/usr/local/bin/docker` ## 验证 - Compose:`list.py` 输出全部服务与节点分布,数量与预期一致 - 每次 sync/deploy 后 `remote.py 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 compose:up/recreate/restart/upgrade/ps/logs | | `scripts/deploy/deb.py` | deb 包分发安装:push(scp+apt)/scp/dpkg/apt(URL) | | `scripts/deploy/list.py` | 扫描全部可部署服务 | ## references/ | 文件 | 用途 | |------|------| | `references/config-reference.md` | `_config.yaml` 字段完整说明与继承合并规则 | | `references/argocd.md` | Argo CD 轨道:`argocd.yaml`、新增/升级、开 MR、ns 级 Secret |