一行一行垒起 Dockerfile
本实验在真正的 VM 中运行
这个环境不是 Pod,而是由 KubeVirt 启动的虚拟机。Linux 内核独立运行,systemd 真正管理服务,docker 也不是模拟工具,而是真正的 Docker 引擎。通过 docker run 启动的容器会成为实际进程,docker exec 和 docker logs 也都能照常工作。
过去,这个实验在 Pod 中运行。由于该环境放弃了所有内核权限,启动容器的步骤无法进行,因此只能学习直接解开镜像归档的变通方法。现在不再需要绕路了。
有两点需要了解。
- **首次启动大约需要 1 分钟。**因为 VM 需要启动并安装 Docker,比 Pod 实验(通常 40 秒)更慢。
- **没有浏览器预览。**进入 VM 的连接只开放评分端口。如果启动了 Web 服务器,请在 VM 内使用
curl检查。
目标
逐一添加 Dockerfile 指令,通过 inspect 确认每条指令改变了镜像的哪个部分,最终编写出能通过评审检查清单的文件。
为什么重要
Dockerfile 看起来像配置文件,实际上是一个顺序具有含义的构建脚本。即使是相同的指令,其位置不同也会增加层、破坏缓存或将密钥永久写入镜像。本实验的目的不是背诵指令,而是养成每次都区分“这一行是在创建层,还是在写入配置”的习惯。仅凭这种区分,就能预防大多数体积和安全问题。
步骤
每一步都使用新标签构建,以便保留前一步的结果。
- 创建
/root/build1,将/root/build1/Dockerfile的第一行写成FROM alpine:3.20。 - 构建为
labhub/app:v1。 - 创建
/root/build1/app.sh,使其输出app-running;在 Dockerfile 中添加WORKDIR /app和COPY app.sh /app/,构建为labhub/app:v2。 - 以 JSON 数组格式添加
CMD,使其执行app.sh,并构建为labhub/app:v3。运行时必须输出app-running。 - 添加
ENV APP_ENV=prod和ARG VERSION,将通过 ARG 接收的值写入LABEL app.version。使用--build-arg VERSION=2.1.0构建labhub/app:v4。 - 将
ENTRYPOINT设为数组格式,并将CMD ["default-arg"]设为默认值,使其不带参数运行时输出default-arg,传入override-arg时输出override-arg,然后构建为labhub/app:v5。 - 添加
LABEL org.opencontainers.image.title=labhub-app和EXPOSE 8080,构建为labhub/app:v6。 - 完善最终的
/root/build1/Dockerfile,使其满足以下五项要求,并构建为labhub/app:v7。FROM中的标签已固定,且不是latestWORKDIR位于第一次COPY之前ENTRYPOINT或CMD使用 JSON 数组ENV/ARG名称中不包含 TOKEN、SECRET、PASSWORD、API_KEY
参考
- 使用
docker image inspect labhub/app:v4 | jq '.[0].Config'可以一览各配置字段。 - 以
docker build --build-arg VERSION=2.1.0 -t labhub/app:v4 /root/build1的形式传入参数。 - 常见错误 1:如果像
CMD app.sh一样使用 Shell 格式,它会成为一个字符串,而不是数组。 - 常见错误 2:如果在第 5 步将 ARG 值传给 ENV,它会原样留在镜像中。请将其写入 LABEL。
固定基础镜像
创建 /root/build1,将 /root/build1/Dockerfile 的第一行写成 FROM alpine:3.20。
请在 FROM 中明确指定标签。latest 会导致昨天和今天的构建结果不同。
首次构建
构建为 labhub/app:v1。
构建上下文应指定 Dockerfile 所在的目录。如果不使用 -t 命名,之后会很难找到。
设置工作目录并复制文件
创建 /root/build1/app.sh,使其输出 app-running;在 Dockerfile 中添加 WORKDIR /app 和 COPY app.sh /app/,构建为 labhub/app:v2。
WORKDIR 会写入镜像配置(Config.WorkingDir),COPY 会创建层。两条指令的顺序决定相对路径的含义。
指定默认命令
以 JSON 数组格式添加 CMD,使其执行 app.sh,并构建为 labhub/app:v3。运行时必须输出 app-running。
使用 Shell 格式时,命令会被 /bin/sh -c 包裹,PID 1 将成为 Shell。你已经在前面的课程中了解了为何需要数组格式。
构建参数与环境变量的区别
添加 ENV APP_ENV=prod 和 ARG VERSION,将通过 ARG 接收的值写入 LABEL app.version。使用 --build-arg VERSION=2.1.0 构建 labhub/app:v4。
ARG 只在构建期间存在,ENV 则会留在镜像中。如果要将通过构建参数收到的值留在镜像中,请将其写入 LABEL。
组合 ENTRYPOINT 与 CMD
将 ENTRYPOINT 设为数组格式,并将 CMD ["default-arg"] 设为默认值,使其不带参数运行时输出 default-arg,传入 override-arg 时输出 override-arg,然后构建为 labhub/app:v5。
ENTRYPOINT 保持固定,CMD 会在运行时被参数替换。两者都请使用数组格式。
声明标准标签和端口
添加 LABEL org.opencontainers.image.title=labhub-app 和 EXPOSE 8080,构建为 labhub/app:v6。
OCI 标准标签键以 org.opencontainers.image. 开头。EXPOSE 不会开放端口,它是一条用于文档说明的指令。
通过评审检查清单
完善最终的 /root/build1/Dockerfile,使其满足以下五项要求,并构建为 labhub/app:v7。
FROM中的标签已固定,且不是latestWORKDIR位于第一次COPY之前ENTRYPOINT或CMD使用 JSON 数组ENV/ARG名称中不包含 TOKEN、SECRET、PASSWORD、API_KEY
请按照五项要求完善到目前为止的 Dockerfile。评分会同时检查文件内容和构建结果。