LabHub
学习 学习路径 课程

构建镜像

一行一行垒起 Dockerfile

在 LabHub 中继续学习

本实验在真正的 VM 中运行

这个环境不是 Pod,而是由 KubeVirt 启动的虚拟机。Linux 内核独立运行,systemd 真正管理服务,docker 也不是模拟工具,而是真正的 Docker 引擎。通过 docker run 启动的容器会成为实际进程,docker execdocker logs 也都能照常工作。

过去,这个实验在 Pod 中运行。由于该环境放弃了所有内核权限,启动容器的步骤无法进行,因此只能学习直接解开镜像归档的变通方法。现在不再需要绕路了。

有两点需要了解。

目标

逐一添加 Dockerfile 指令,通过 inspect 确认每条指令改变了镜像的哪个部分,最终编写出能通过评审检查清单的文件。

为什么重要

Dockerfile 看起来像配置文件,实际上是一个顺序具有含义的构建脚本。即使是相同的指令,其位置不同也会增加层、破坏缓存或将密钥永久写入镜像。本实验的目的不是背诵指令,而是养成每次都区分“这一行是在创建层,还是在写入配置”的习惯。仅凭这种区分,就能预防大多数体积和安全问题。

步骤

每一步都使用新标签构建,以便保留前一步的结果。

  1. 创建 /root/build1,将 /root/build1/Dockerfile 的第一行写成 FROM alpine:3.20
  2. 构建为 labhub/app:v1
  3. 创建 /root/build1/app.sh,使其输出 app-running;在 Dockerfile 中添加 WORKDIR /appCOPY app.sh /app/,构建为 labhub/app:v2
  4. JSON 数组格式添加 CMD,使其执行 app.sh,并构建为 labhub/app:v3。运行时必须输出 app-running
  5. 添加 ENV APP_ENV=prodARG VERSION,将通过 ARG 接收的值写入 LABEL app.version。使用 --build-arg VERSION=2.1.0 构建 labhub/app:v4
  6. ENTRYPOINT 设为数组格式,并将 CMD ["default-arg"] 设为默认值,使其不带参数运行时输出 default-arg,传入 override-arg 时输出 override-arg,然后构建为 labhub/app:v5
  7. 添加 LABEL org.opencontainers.image.title=labhub-appEXPOSE 8080,构建为 labhub/app:v6
  8. 完善最终的 /root/build1/Dockerfile,使其满足以下五项要求,并构建为 labhub/app:v7
    • FROM 中的标签已固定,且不是 latest
    • WORKDIR 位于第一次 COPY 之前
    • ENTRYPOINTCMD 使用 JSON 数组
    • ENV/ARG 名称中不包含 TOKEN、SECRET、PASSWORD、API_KEY

参考

固定基础镜像

创建 /root/build1,将 /root/build1/Dockerfile 的第一行写成 FROM alpine:3.20

请在 FROM 中明确指定标签。latest 会导致昨天和今天的构建结果不同。

首次构建

构建为 labhub/app:v1

构建上下文应指定 Dockerfile 所在的目录。如果不使用 -t 命名,之后会很难找到。

设置工作目录并复制文件

创建 /root/build1/app.sh,使其输出 app-running;在 Dockerfile 中添加 WORKDIR /appCOPY 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=prodARG 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-appEXPOSE 8080,构建为 labhub/app:v6

OCI 标准标签键以 org.opencontainers.image. 开头。EXPOSE 不会开放端口,它是一条用于文档说明的指令。

通过评审检查清单

完善最终的 /root/build1/Dockerfile,使其满足以下五项要求,并构建为 labhub/app:v7

请按照五项要求完善到目前为止的 Dockerfile。评分会同时检查文件内容和构建结果。