# Composer 多租户 Docker Compose 编排工具。扫描 `users/` 下的用户目录,校验每个用户的 `compose.yml`,生成注入网络配置的快照,然后启动所有服务。 ## 目录结构 ``` / ├── users/ │ ├── 10-alice/ # 优先级-用户名 │ │ ├── compose.yml # 必需 │ │ ├── .env # 可选(明文) │ │ ├── .env.gpg # 可选(加密,二选一即可) │ │ ├── app/ │ │ │ └── Dockerfile │ │ └── ... │ └── 20-bob/ │ └── ... └── snapshots/ # 自动生成(每次覆盖) ├── 10-alice/ │ └── compose.yml # 已注入网络配置的版本 └── 20-bob/ ``` - 目录名格式:`<数字优先级>-<用户名>` - 用户名:`[a-z0-9]+` - 优先级数字越小越先处理 ## CLI 参数 | 参数 | 必需 | 默认值 | 说明 | |------|------|--------|------| | `--root` | | `.` | 项目根目录 | | `--network` | | `cloud` | 注入到 services 的外部网络名 | | `--volume-parent` | ✓ | | 卷挂载路径白名单前缀 | | `--dry` | | `false` | 只打印操作,不实际执行 | ## compose.yml 约束 ### 允许的顶层字段 只有 `services` 被识别。如果 YAML 中有 `networks`、`volumes`、`version` 等额外顶层键,会触发 **WARN** —— 它们会被 Pydantic 静默丢弃,可能与网络注入冲突。 ### 允许的 service 字段 `build` `image` `volumes` `command` `depends_on` `entrypoint` `env_file` `environment` `build` 可以是字符串(指向含 Dockerfile 的目录)或对象 `{context, dockerfile, args}`。其他键同样触发 WARN。 ### 卷约束 所有 volume 的宿主机路径必须以 `--volume-parent` 为前缀,且只允许 `ro` 模式。 ### 环境文件 - 支持明文 `.env` 或 GPG 加密 `.env.gpg` - 只校验明文文件的内容格式(`KEY=value` 或 `export KEY=value`) - 如果只存在 `.env.gpg` 则跳过内容校验 ## 运行流程 ``` 1. 扫描 users/ → 解析优先级和用户名 2. 加载每个 compose.yml → Pydantic 校验 3. 检测注入干扰字段(WARN) 4. 校验 service 引用、Dockerfile 存在性、卷路径、env_file 5. ── 有错则退出 ── 6. 为每个用户创建 snapshots/-/ 7. 拷贝所有文件:compose.yml 注入网络配置,.gpg 文件解密 8. ── 快照失败则退出 ── 9. 在每个快照目录执行 docker compose up --remove-orphans --build --detach ``` ## 网络注入 快照中的 `compose.yml` 会被注入: ```yaml networks: cloud: # --network 参数值 external: true alice: # 用户名 name: alice services: app: networks: [cloud, alice] ``` 每个 service 的 `networks` 会被**覆盖**为 `[, ]`。 ## GPG 解密 快照拷贝时,`.gpg` 后缀的文件会调用系统 `gpg --decrypt --batch` 解密,输出到去掉 `.gpg` 后缀的路径。原 `.gpg` 文件不进入快照。 要求运行环境已配置好 GPG 密钥,且能无交互解密。 ## Dry-run 模式 `--dry` 执行全部校验,但只打印操作摘要: ``` [dry] would snapshot users/10-alice -> snapshots/10-alice [dry] inject networks: .networks.cloud.external=true, ... [dry] would run: docker compose -f snapshots/10-alice/compose.yml up ... ``` 不创建目录、不写文件、不解密、不启动容器。 ## 错误处理 - **校验阶段有错** → 打印错误并 `exit 1`(不创建快照) - **快照创建失败**(单个用户)→ 标记错误,跳过该用户,继续处理其他用户;全部完成后 `exit 1` - **compose up 失败**(单个用户)→ 标记错误,继续启动其他用户;全部完成后 `exit 1`