3.7 KiB
3.7 KiB
Composer
多租户 Docker Compose 编排工具。扫描 users/ 下的用户目录,校验每个用户的 compose.yml,生成注入网络配置的快照,然后启动所有服务。
目录结构
<root>/
├── 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/<prio>-<name>/
7. 拷贝所有文件:compose.yml 注入网络配置,.gpg 文件解密
8. ── 快照失败则退出 ──
9. 在每个快照目录执行 docker compose up --remove-orphans --build --detach
网络注入
快照中的 compose.yml 会被注入:
networks:
cloud: # --network 参数值
external: true
alice: # 用户名
name: alice
services:
app:
networks: [cloud, alice]
每个 service 的 networks 会被覆盖为 [<network>, <username>]。
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