# 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 的 SKILL.md 所在目录 # 布局 A export DEPLOYER_ROOT=/path/to/your-compose-repo python3 /scripts/deploy/list.py # 布局 B:cwd 在项目里即可 python3 /scripts/deploy/list.py ``` ## 列出服务 `list.py` 输出全部服务与节点分布;新增环境/服务后重跑确认被发现。项目布局下 `prod/test/dev` 各显示为 `{项目名}-{env}`。`argocd.yaml` 不会被当成 compose 服务。 查看单个服务的 node、远程路径、排除规则: ```bash python3 /scripts/deploy/sync.py ``` 或读服务目录及祖先的 `_config.yaml`。 ## 命令选择 语义严格区分,必须按**单服务**执行: | 意图 | 命令 | |------|------| | 只同步文件,不动容器 | `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` | 若项目有 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 "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` 会清掉) ## 下线服务 独立仓库布局:配置移入 `unused/`(自动脱离发现体系),远程按需手动清理: `ssh "cd / && 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 /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 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 "`。 ## 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 "mkdir -p / && cd / && tar xzf -" ssh "cd / && /usr/local/bin/docker compose up -d" ``` tar 不会删除远程多余文件;需清理旧文件时手动 SSH 删除。Synology 上 docker 路径可能是 `/usr/local/bin/docker`。 ## 验证 - `list.py` 输出全部服务与节点分布,数量与预期一致 - 每次 sync/deploy 后 `remote.py ps` 容器 Up、`logs` 无报错 - 升级后额外确认镜像 tag 与 `compose.yaml` 一致 - 改 Traefik/Caddy 路由后 curl 对应域名验证生效