# Python API Docker Packager

> 为 Python FastAPI 算法接口工程设计、审查、生成和修复可复现的 Docker/Compose 打包链路。用于创建或更新 Dockerfile、docker-compose.dev.yaml、docker-compose.yaml、.dockerignore、.gitattributes、.env.production、uv/requirements 依赖、原生库或源码补丁、健康检查、start-dev/package-image 脚本、镜像导出归档和跨平台部署；尤其适用于需要以 `.\scripts\start-dev.ps1 .\.env.production` 作为最终构建、启动和健康验收入口的项目。

- Skill: `codeboy-bot/python-api-docker-packager` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds@latest add codeboy-bot/python-api-docker-packager`
- Raw SKILL.md: https://api.skillmd.com/api/skills/codeboy-bot/python-api-docker-packager/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: DevOps & Infra
- Author: Codeboy-bot (https://skillmd.com/u/codeboy-bot)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/codeboy-bot/python-api-docker-packager

---


# Python API Docker Packager

把“Python API 能运行”整理成可复现、可启动、可验收、可归档的镜像交付链路。以项目真实入口和真实依赖为准，不套用固定的 `uvicorn main:app` 模板。

## 核心原则

- 先读工程，再改打包文件。确认应用入口、监听地址、健康端点、依赖锁、原生库、运行目录和数据挂载。
- 区分两条链路：`start-dev` 负责构建、启动和健康验收；`package-image` 负责版本递增、镜像导出和离线归档。
- Compose 配置可解析只是静态检查，不等于镜像构建成功、容器健康或挂载可写。
- 开发 Compose 可以含 `build`；生产 Compose 默认只消费指定镜像，避免在部署机隐式构建。
- `.env.production` 只放非敏感部署参数。密码、令牌和私钥使用 secrets、宿主机注入或外部配置。
- 不凭报错直接修改业务代码。先区分应用/构建错误、Compose 配置错误与 Docker daemon/存储错误。

## 先建立文件依赖图

逐个检查下列文件；缺失时再按工程需要生成：

1. 应用入口与配置：`main.py`、包内 `app.py`、健康端点、路径环境变量。
2. Python 依赖：`pyproject.toml` + `uv.lock`，或 `requirements*.txt`。
3. 原生依赖：系统包、源码版本、校验和、编译参数、补丁与模型运行资源。
4. 镜像：`Dockerfile`、`.dockerignore`、`.gitattributes`。
5. 编排：`docker-compose.dev.yaml`、`docker-compose.yaml`、`.env.production`。
6. 入口脚本：`scripts/start-dev.ps1`，必要时保持 `scripts/start-dev.sh` 等价。
7. 发布脚本：`scripts/package-image.ps1` / `.sh`、buildx/bake 配置和归档产物。
8. 文档：README 中的实际命令、端口、镜像名、版本策略和挂载说明。

遇到含原生算法、源码补丁、离线镜像归档或 `start-dev` 统一入口的工程时，完整阅读 [打包链路参考](references/start-dev-packaging-pattern.md)。

## 工作流

### 1. 识别真实运行契约

- 找到容器真正执行的模块或脚本，确认它是否自行调用 Uvicorn/Gunicorn。
- 确认容器内监听 `0.0.0.0`，并从代码或配置中取得真实内部端口。
- 找到轻量健康端点；现有 `/` 足够稳定时可以复用，不强行改成 `/healthz`。
- 记录输入目录、输出目录、日志文件、背景数据和模型可执行文件等运行时契约。
- 判断哪些路径只读、哪些必须可写，禁止把 Windows 宿主机路径传入容器内应用配置。

### 2. 固化依赖和原生构建

- 优先使用锁文件安装：uv 工程使用 `uv sync --locked --no-dev`；requirements 工程使用固定版本和哈希策略。
- 多阶段构建中将编译器、头文件和源码留在 builder；runtime 只复制运行库、可执行文件和应用必需文件。
- 固定上游源码 tag/commit、下载地址、SHA256 和关键构建参数。不要只依赖浮动分支或 `latest`。
- 在镜像构建中先执行补丁 dry check，再应用补丁。补丁必须以 LF 进入构建上下文，并用 `.gitattributes` 固化 `*.patch text eol=lf`。
- 对 Python 模块、原生动态库、算法可执行文件和必需资源增加构建期存在性/导入检查。

### 3. 生成或修正 Dockerfile

- 固定基础镜像版本，必要时固定 digest。
- 优化层缓存：稳定依赖文件先复制，频繁变化的业务源码后复制。
- 显式创建运行目录、复制必要资源并配置运行用户；非特权可行时使用非 root 用户。
- `CMD`/`ENTRYPOINT` 必须匹配第 1 步识别的真实入口。
- 健康检查使用项目真实端点和内部端口，不依赖宿主机映射端口。
- 注入版本、构建时间和 VCS revision 等 OCI 元数据时，确保发布脚本与 Dockerfile 参数同名。

### 4. 对齐 Compose 与环境文件

- `docker-compose.dev.yaml` 包含 `build`，承载本地构建、挂载、端口和健康检查。
- `docker-compose.yaml` 默认只包含 `image`，生产环境避免隐式构建；离线场景可设置合适的 pull 策略。
- `.env.production` 提供镜像仓库/标签、容器名、宿主端口、宿主挂载目录和容器内 Linux 路径。
- 启动脚本如果自动选择端口并回写环境文件，README 必须说明这一行为。
- 指定唯一发布版本源（通常为 `pyproject.toml`），并定义是否添加 `v`、架构后缀等标签转换。比较锁文件、Dockerfile 版本参数、Compose 默认值、`.env.production`、归档脚本和 README 示例；发现未声明为部署覆盖的漂移时阻断发布。

### 5. 把 start-dev 作为统一验收入口

`scripts/start-dev.ps1` 至少应完成：

1. 解析并导入指定 env 文件。
2. 规范化 Windows 宿主路径，保留容器内 Linux 路径。
3. 解析 Compose config，并断言目标服务存在、输入挂载只读、输出/日志挂载可写、挂载 target 与容器路径变量一致。
4. 可选地检测端口占用；只有真实启动流程可以把最终端口回写到同一个 env 文件。
5. 执行 `docker compose up -d --build`。
6. 等待容器健康；失败时输出状态和容器日志并返回非零退出码。
7. 明确打印最终镜像完整 tag/image ID、容器名、宿主端口和访问 URL。

先运行不构建、不启动容器的配置验收：

```powershell
.\scripts\start-dev.ps1 -EnvFile .\.env.production -ConfigOnly
```

`ConfigOnly` 必须在 `docker compose build/up` 和任何 env 文件回写之前退出。若审查到现有脚本会在此模式下改写 `APP_PORT` 等配置，不得宣称它“无副作用”；应优先调整执行顺序，调整前要告知用户该写副作用。

最终打包/启动验收使用用户指定的统一入口；当 `EnvFile` 是首个位置参数时，下列两种写法等价：

```powershell
.\scripts\start-dev.ps1 .\.env.production
.\scripts\start-dev.ps1 -EnvFile .\.env.production
```

生成的 README 和交付说明优先使用带 `-EnvFile` 的显式写法。真实执行会构建镜像、创建或更新容器并可能回写端口，执行前取得用户许可。

### 6. 单独处理发布归档

- `package-image` 与 `start-dev` 不互相冒充：前者产生可分发 TAR/ZIP，后者证明镜像在 Compose 契约下能健康运行。
- 发布脚本应支持 DryRun，显示版本变化、镜像标签、构建参数和输出路径。
- 版本递增后同步锁文件、Dockerfile 构建参数和需要固化版本的部署文件。
- 构建后检查镜像架构、入口、关键环境变量和 OCI 标签，再导出并校验归档内容。
- 显式指定目标平台，并断言 RepoTag、architecture、Entrypoint/CMD、OCI version/revision labels。打开导出的 TAR，检查 `manifest.json` 指向目标镜像，而不只检查 ZIP 中存在某个 TAR 文件名。
- 归档镜像必须就是通过 `start-dev` 健康验收的 image ID/digest；若发布脚本使用另一标签或重新构建，必须比较 ID/digest，或对最终发布镜像重新执行同等 Compose 健康验收。
- 覆盖既有归档、删除中间 TAR 或更新版本文件前，遵循用户授权；可行时把中间文件移入回收站。
- 不把 `.env.production`、数据目录、日志、输出结果、虚拟环境或已有镜像归档复制进镜像上下文。

### 7. 分层验证和诊断

按成本从低到高验证：

1. 静态语法与文件存在性。
2. `docker compose ... config` 或 `start-dev -ConfigOnly`。
3. Dockerfile 构建和构建期 smoke checks。
4. `start-dev` 启动、健康等待和日志检查。
5. API 最小请求、挂载读写、重启行为与镜像归档校验。

诊断时至少区分：

- Compose/环境错误：缺变量、路径格式、端口、服务名或挂载不匹配。
- 镜像构建错误：锁文件、系统包、源码校验、补丁换行、编译或复制路径失败。
- 应用错误：入口、模块导入、配置、算法运行或结果解析失败。
- Docker 基础设施错误：layer extract I/O、daemon 连接、磁盘/WSL 存储损坏。此类错误先验证 daemon 和存储，不通过修改业务代码掩盖。

## 完成标准

- 所有打包文件共同表达同一个应用入口、内部端口、镜像标签和路径契约。
- 唯一版本源、标签转换和允许的部署覆盖已声明；其他版本漂移会阻断发布。
- `.dockerignore` 没有排除 Dockerfile 构建所需的补丁、源码或资源。
- 原生构建可复现，补丁换行和上游版本已固化。
- `start-dev -ConfigOnly` 通过。
- 经用户许可后，`.\scripts\start-dev.ps1 -EnvFile .\.env.production` 构建成功、容器健康并输出最终 URL。
- 若要求离线交付，归档镜像与已验收镜像的 ID/digest 一致，或最终发布镜像已重新通过同等健康验收；目标 TAR/ZIP 的 manifest 与元数据已验证，且文档中的命令与实际脚本一致。

