KEEL · 龙骨 · A CURRICULUM FOR THE AI ERA

03 · 构建上下文 — keel 龙骨

类型:主题概念 · 应用课对应:01 章 §三、§四

类型:主题概念 · 应用课对应:01 章 §三、§四

这一页只回答四件事:它为什么会出现、它是什么、它长什么样、它怎么工作。

一、它为什么会出现

构建要按一份 Dockerfile 把文件装进镜像里,那"这些文件从哪儿来"就必须有一个明确的答案。答案就是构建上下文——docker build 后面那个路径。

它之所以经常出问题,是因为"我传了什么"和"我以为我传了什么"是两件事:

① 每次 docker build 都要等四分钟,明明只改了一行注释
② .env / .git / 本地日志一起被传进了构建过程,后来发现镜像里带着密钥

它面对的需求是:构建需要一个"输入目录",但这个目录里不全是该给构建器的东西。

二、它是什么

一句话:构建上下文 = docker build <路径> 里那个路径下的全部文件,被打包、跨进程送给构建器的那一段字节。

三个"不是":

三、它长什么样

它长成一个目录,外加一份排除清单:

app/
├─ src/                ← 要的
├─ package.json        ← 要的
├─ node_modules/       ← 不要(容器里会重装)
├─ .git/               ← 不要(版本历史,含完整提交内容)
├─ debug.log           ← 不要(本地日志,内容每次都在变)
└─ .dockerignore       ← 就是这份清单
# .dockerignore
node_modules
.git
*.log
.env

应用课里有一份实测:同一个目录,加上 .dockerignore 前后,上下文体积从 3337.2 KB 收缩到 1.1 KB。

四、它怎么工作

① 过滤   docker CLI 读 .dockerignore,把该排除的排掉
② 打包   把剩下的文件打成一个 tar 流
③ 传输   ← 唯一跨进程的一跳:这段字节从 CLI 交给构建器
④ 取用   Dockerfile 里的 COPY / ADD 只能从这个上下文里取文件

第 ③ 步是唯一一次跨进程,上下文的大小决定的就是这一跳的成本。

第 ① 步还有一层不那么直观的作用:COPY 产出的那一层,身份取决于被复制文件的内容。所以一个每天都在变的日志文件留在上下文里,代价不只是"多传了几 KB",而是让那一层每次都作废。构建变慢的真正原因常常在这里,而不在 Dockerfile 的指令顺序上。

五、它会带出哪些概念

六、回到应用课

应用课里的那句话 现在你知道它为什么成立
".dockerignore 在上传前生效" 过滤发生在 CLI 进程里、排在"打包"之前——被排除的东西从未跨进程
". 里的东西不等于源码" 上下文是路径下的全部文件,而不是"源码"这个概念
"上下文大不只慢,还是一个安全边界" 跨进程送过去的东西,构建器就可能把它写进某一层;而层是不可变的,写进去就一直在

这一页改变了你的哪个判断:构建慢或镜像莫名其妙地大的时候,第一件事不是去调 Dockerfile 的指令顺序,而是先问**"这次传过去的目录里都有什么"**——顺序优化只对已经传过去的东西有效。

自测题

  1. 一个 5 KB 的日志文件留在上下文里,为什么它带来的代价远大于 5 KB?
  2. "把文件传过去、再在 Dockerfile 里删掉"和"用 .dockerignore 排除掉",结果差在哪?

进入 keel 阅读