第 35 节 · Docker 速通:运行容器 + 写 Dockerfile
一句话回答
Docker = 把你的 Agent + 依赖 + 运行环境打成一个"集装箱"。 本地能跑只是第一步;要让 CI、CNB Pipeline 和 NPC 稳定运行,就必须把环境也一起交付。
为什么需要 Docker

你 Day6 的 Agent 在本地能跑,但:
- 队友电脑上 Python 版本不一样 → 跑不起来
- CNB 流水线要启动你的 Agent → 不知道怎么装依赖
- 你重装系统后 → 环境没了
- NPC 要在云端响应评论 → 需要一个可重复启动的运行时
Docker 解法:代码、依赖、系统工具、入口脚本一起打进镜像里,到哪儿都一样。
5 个核心概念(大二够用)
| 概念 | 一句话 | 类比 |
|---|---|---|
| 镜像 Image | 打包好的"模板" | 做好的蛋糕模具 |
| 容器 Container | 镜像跑起来的一个实例 | 用模具做出来的一个蛋糕 |
| Dockerfile | 描述"怎么做这个模具"的说明书 | 蛋糕配方 |
| Registry | 存放镜像的仓库 | 蛋糕模具商店 |
| Volume | 容器里的持久化文件夹 | 蛋糕店的冷柜 |
今天只需要掌握前三个:Dockerfile → image → container。
Dockerfile 速通
我们的 Dockerfile 用两阶段构建(生产里很常见):
dockerfile
# ==== Stage 1: 构建 ====
FROM python:3.11-slim-bookworm AS builder
WORKDIR /build
COPY . /build
RUN pip install --no-cache-dir openai numpy pyinstaller
RUN pyinstaller --onefile --name my-agent main.py
# ==== Stage 2: 运行 ====
FROM debian:bookworm-slim AS runtime
RUN apt-get update \
&& apt-get install -y --no-install-recommends ca-certificates git bash curl jq \
&& rm -rf /var/lib/apt/lists/*
COPY --from=builder /build/dist/my-agent /usr/local/bin/my-agent
COPY npc-entrypoint.sh /usr/local/bin/npc-entrypoint
ENTRYPOINT ["/usr/local/bin/npc-entrypoint"]为什么两阶段
| 阶段 | 包含什么 | 特点 |
|---|---|---|
| builder | Python + pip + pyinstaller + 全部源码 | 适合编译,体积大 |
| runtime | 只有运行所需二进制 + git / bash 等工具 | 适合部署,体积小 |
最终推送到 Registry 的主要是 runtime 层——通常会明显更小,也少带很多不需要的构建工具。
2026 年 Python 镜像的几个实践
| 实践 | 原因 |
|---|---|
优先用 slim,谨慎用 Alpine | Python 生态里很多包有 C 扩展,Alpine 可能导致编译慢或兼容坑 |
apt-get install --no-install-recommends | 少装不必要依赖 |
安装完清理 /var/lib/apt/lists/* | 减少镜像层体积 |
pip install --no-cache-dir | 不要把 pip 下载缓存塞进镜像 |
用 .dockerignore | 不要把 .git、虚拟环境、缓存、日志复制进构建上下文 |
| 不要把 Secrets 写进镜像 | API key 应该运行时从平台 Secrets 注入 |
| 构建后 smoke test | 镜像能 build 不代表入口真的能跑 |
这些不是炫技,是为了让镜像小、快、可复现、少泄密。
关键坑:glibc 版本必须对齐
builder 用
python:3.11-slim-bookworm,runtime 也尽量用debian:bookworm-slim。 如果 builder 用了更新的 Debian(比如 trixie),编译出的二进制可能依赖更新 glibc, 但 runtime 里没有 → 运行时报GLIBC_2.xx not found。
这类问题最烦,因为 Docker build 阶段可能成功,真正跑 NPC 时才炸。所以课程模板刻意让 builder / runtime 都基于 bookworm。
我们的 NPC 镜像还多了什么
课程模板还会额外处理两件事:
dockerfile
FROM docker.cnb.cool/looc/git-cnb:latest AS gitcnb
FROM debian:bookworm-slim AS runtime
COPY --from=gitcnb /app/git-cnb /usr/local/bin/git-cnb
COPY --from=builder /build/dist/my-agent /usr/local/bin/my-agent
COPY npc-entrypoint.sh /usr/local/bin/npc-entrypoint| 文件 | 作用 |
|---|---|
my-agent | 你的 Coding Agent 二进制 |
git-cnb | 回写 Issue / PR 评论 |
npc-entrypoint | 把 CNB 事件翻译成 my-agent --solo exec |
跑一下试试
bash
# 构建镜像(在包含 Dockerfile 的目录里执行)
docker build -t my-agent:latest .
# 跑一下看看 help
docker run --rm --entrypoint /usr/local/bin/my-agent my-agent:latest --help
# 用交互模式进容器看看里面有什么
docker run --rm -it --entrypoint bash my-agent:latest如果镜像默认 ENTRYPOINT 是 npc-entrypoint,直接 docker run my-agent:latest --help 可能会走 NPC 逻辑;调试时可以用 --entrypoint 覆盖。
动手试试
- 用提供的 Dockerfile 模板,改一下
COPY . /build路径(如果你的目录结构不同) - 本地
docker build -t my-agent:latest .构建一次 - 用
--entrypoint /usr/local/bin/my-agent确认二进制能跑 - 用
--entrypoint bash进容器确认my-agent、git-cnb、npc-entrypoint都在
不要从零写 Dockerfile——今天重点是 Skills + NPC,Docker 只是"交通工具"。
小结
- Docker = 打包环境的"集装箱"
- Dockerfile = 构建说明书,两阶段构建让 runtime 更小、更稳定
- Python 镜像优先 slim;不要把 Secrets、缓存、虚拟环境打进去
- 关键坑:builder 和 runtime 的 glibc 版本要对齐
- NPC 镜像必须同时包含 Agent、回写工具和入口脚本