Dockerfile 与构建
定义
Dockerfile(或 Containerfile)是一份构建说明书。它从一条
FROM 指令指定的基础镜像出发,按顺序执行复制文件、运行命令、设置环境等步骤,最终得到新的镜像。build
命令读取该文件以及构建上下文(通常是当前目录),在内容寻址缓存的帮助下复用未变化的步骤。
构建的输出仍然是镜像,不是正在运行的容器。要运行构建产物,需要另一次
run。
问题背景
手工在一台已安装好的机器上「整理环境」,无法稳定地告诉另一台机器如何得到同一环境。把安装步骤写成可重复的指令,有两个直接效果:同一份文件在不同主机上应得到同一摘要;某一步失败时,可以定位到具体指令,而不是一整台不可描述的机器。
分层缓存进一步降低重复成本。若只有应用代码变化,基础系统与依赖层不必重做。
机制说明
指令与层的对应关系
常见指令及其作用:
| 指令 | 作用 |
|---|---|
FROM |
指定基础镜像,构建的起点 |
COPY / ADD |
把构建上下文中的文件放入镜像 |
RUN |
在前一层之上执行命令,结果成为新层 |
ENV |
设置镜像配置中的环境变量 |
WORKDIR |
设置后续指令与容器启动时的工作目录 |
EXPOSE |
声明容器意图监听的端口,本身不发布端口 |
CMD / ENTRYPOINT |
指定默认入口进程 |
EXPOSE
经常被误解为「自动打开端口」。它只是元数据。真正把宿主端口映射到容器,要靠
run -p 或 Compose 中的 ports,见容器网络与端口发布。
构建上下文与缓存
build 发送的上下文默认是 Dockerfile 所在目录(可用
.dockerignore 排除无关文件)。COPY . /app
会把上下文中的文件纳入该层的摘要。因此,上下文里多一个无关的日志文件,也可能使缓存失效。
缓存命中的条件是:前一层摘要相同,且本条指令及其输入相同。一旦某一步未命中,其后所有步骤通常都要重做。把变化频繁的
COPY 尽量放在后面,是控制构建时间的基本方法。
构建不等于运行
构建阶段执行的 RUN
发生在构建环境中,目的是产生层。这些命令的过程输出不是生产日志。生产入口由
CMD 或 run 时覆盖的命令决定。把密钥写进
Dockerfile 的 ENV 或
RUN echo,会使密钥进入镜像层,随后随镜像分发;这是构建阶段最常见的泄密方式。
在 Box 中的位置
- 构建实现位于
src/runtime/src/oci/build/,CLI 入口为src/cli/src/commands/build.rs。 - Box 支持选定的 Dockerfile / Containerfile 子集,并使用内容寻址缓存。不被支持的指令在构建或运行前失败,而不是被静默忽略。
- 构建产物随后可被
a3s-box run使用。镜像准备仍由 Box 完成;执行隔离由 MicroVM 或 OCI Runtime 承担。
验证命令
a3s-box build -t local/app:dev . |
若当前目录没有 Dockerfile,build
应在产生镜像之前失败。这是「不支持的输入不得进入状态」这一原则在构建路径上的表现。
相关与易混
- 相关:镜像与层、镜像仓库 Registry、Docker 式 CLI
- 易混:Dockerfile 不是 Compose
文件。前者描述如何生成一个镜像;后者描述如何同时运行多个已存在的镜像。
EXPOSE也不是端口发布。