外观
Dockerfile 指令与参数详解
约 5656 字大约 19 分钟
2026-05-28
本文是第 4 课《Dockerfile 构建自定义 Web 应用镜像》的课后参数说明文档。它不承担课堂引导任务,而是作为后续编写、审查和优化 Dockerfile 时的专业参考。
本文内容根据 2026-05-28 查阅的 Docker 官方文档整理,重点覆盖 Dockerfile 的指令、常用参数、构建上下文、缓存规则、多阶段构建与安全注意事项。
一、基础概念
| 术语 | 含义 | 为什么重要 |
|---|---|---|
| Dockerfile | 描述镜像构建过程的纯文本文件,默认文件名为 Dockerfile。 | 它把环境安装、文件复制、默认启动命令等步骤固化为可复现的构建定义。 |
| Image | 镜像,容器运行前的只读模板。 | docker build 的产物是镜像,docker run 会基于镜像创建容器。 |
| Layer | 镜像层,构建过程中由部分指令生成的只读文件系统差异。 | 分层决定了镜像复用、缓存命中和最终体积。 |
| Build Context | 构建上下文,执行 docker build 时传给构建器的一组文件。 | COPY 和 ADD 默认只能读取构建上下文中的文件。 |
.dockerignore | 构建上下文的排除规则文件。 | 它可以避免把 .git、缓存、日志、密钥等无关文件发送给构建器。 |
| BuildKit | Docker 当前推荐的构建后端。 | 它支持更好的缓存、并行构建、RUN --mount、secret 挂载等能力。 |
| Shell form | 字符串形式命令,例如 RUN npm install。 | 会经过默认 shell 解释,适合使用管道、变量展开和多命令组合。 |
| Exec form | JSON 数组形式命令,例如 CMD ["node", "server.js"]。 | 不经过 shell,参数边界更清晰,适合作为容器主进程启动方式。 |
二、Dockerfile 的解析规则
1. Dockerfile 不是普通 shell 脚本
Dockerfile 由一系列指令组成,每条指令描述一个构建动作或镜像元数据。常见格式如下:
INSTRUCTION arguments例如:
FROM python:3.12-slim
WORKDIR /app
COPY app/requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt
CMD ["python", "app.py"]需要注意:
- 指令名通常使用大写,便于与参数区分。
- Dockerfile 中的命令不是在宿主机上直接执行,而是在构建器创建的临时构建环境中执行。
RUN会在构建阶段执行;CMD和ENTRYPOINT是容器运行阶段的默认行为。- 并不是所有指令都会产生文件系统层。
RUN、COPY、ADD通常会改变文件系统;LABEL、EXPOSE、ENV、CMD等更多是修改镜像配置或元数据。
2. Parser directive
Parser directive 是写在 Dockerfile 顶部的特殊注释,用于影响 Dockerfile 前端解析方式。
常见写法:
# syntax=docker/dockerfile:1推荐在使用 BuildKit 相关能力时显式声明:
# syntax=docker/dockerfile:1
FROM python:3.12-slim
RUN --mount=type=cache,target=/root/.cache/pip \
pip install requests常见 directive:
| Directive | 作用 | 建议 |
|---|---|---|
syntax | 指定 Dockerfile frontend 版本。 | 使用 RUN --mount、COPY --link 等新特性时建议显式声明。 |
escape | 改变换行转义字符,主要用于 Windows Dockerfile。 | Linux 场景通常不需要修改。 |
check | 控制 Dockerfile build checks。 | 需要统一团队检查规则时再使用。 |
3. Shell form 与 exec form
RUN、CMD、ENTRYPOINT 都支持两类命令形式。
Shell form:
RUN echo "$APP_ENV"
CMD python app.pyExec form:
RUN ["python", "-m", "pip", "install", "-r", "requirements.txt"]
CMD ["python", "app.py"]对比:
| 对比项 | Shell form | Exec form |
|---|---|---|
| 写法 | 一段字符串 | JSON 数组 |
| 是否经过 shell | 是,Linux 默认使用 /bin/sh -c | 否 |
| 环境变量展开 | shell 负责展开 | 不由 shell 自动展开 |
| 参数边界 | 需要依赖 shell 解析 | 每个数组元素都是明确参数 |
| 推荐场景 | 构建阶段安装依赖、使用管道或多命令 | 容器主进程、明确的可执行程序和参数 |
容器入口命令优先使用 exec form,因为它更容易让应用进程成为 PID 1,从而正确接收 docker stop 发送的停止信号。
三、构建上下文与 .dockerignore
执行:
docker build -t flask-demo:v1 .最后的 . 表示把当前目录作为构建上下文。Dockerfile 中的:
COPY app /app不是从宿主机任意路径复制文件,而是从构建上下文里的 app 路径复制文件。
推荐在项目根目录维护 .dockerignore:
.git/
.env
*.log
__pycache__/
*.pyc
.venv/
venv/
node_modules/
dist/
build/
coverage/设计原则:
- 不要把密钥、令牌、
.env、私有证书放入构建上下文。 - 不要把依赖缓存、构建产物、日志、测试截图等无关文件发送给构建器。
- 多个 Dockerfile 共存时,可以使用
DockerfileName.dockerignore为不同 Dockerfile 设置专属忽略规则。
四、镜像缓存规则
Docker 构建镜像时,会按 Dockerfile 顺序处理指令,并尝试复用旧构建结果。缓存失效的典型情况包括:
RUN指令文本发生变化。COPY或ADD涉及的文件内容、权限等属性发生变化。- 上方某一层已经失效,后续依赖它的层也会随之失效。
推荐排序:
FROM python:3.12-slim
WORKDIR /app
COPY app/requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt
COPY app/ ./
CMD ["python", "app.py"]原因是 requirements.txt 通常比业务源码变化更少。先复制依赖清单并安装依赖,可以提高后续改动源码时的缓存命中率。
五、常用指令速查
| 指令 | 作用阶段 | 主要作用 | 是否常用 |
|---|---|---|---|
FROM | 构建阶段 | 指定基础镜像,开启一个构建阶段。 | 必用 |
ARG | 构建阶段 | 定义构建参数。 | 常用 |
ENV | 构建与运行阶段 | 设置镜像内环境变量,并持久化到镜像配置。 | 常用 |
WORKDIR | 构建与运行阶段 | 设置后续指令的工作目录。 | 常用 |
COPY | 构建阶段 | 从构建上下文、阶段或镜像复制文件。 | 常用 |
ADD | 构建阶段 | 类似 COPY,额外支持本地 tar 自动解包、远程源等能力。 | 谨慎使用 |
RUN | 构建阶段 | 执行构建命令,例如安装依赖、编译代码。 | 常用 |
CMD | 运行阶段 | 设置容器默认命令或默认参数。 | 常用 |
ENTRYPOINT | 运行阶段 | 设置容器默认入口程序。 | 常用 |
EXPOSE | 运行阶段元数据 | 声明容器内应用监听端口。 | 常用 |
USER | 构建与运行阶段 | 切换后续命令和容器默认运行用户。 | 常用 |
LABEL | 元数据 | 写入镜像标签信息。 | 常用 |
HEALTHCHECK | 运行阶段 | 定义容器健康检查命令。 | 视场景使用 |
VOLUME | 运行阶段元数据 | 声明挂载点。 | 谨慎使用 |
STOPSIGNAL | 运行阶段 | 设置停止容器时发送的信号。 | 视场景使用 |
SHELL | 构建阶段 | 修改 shell form 使用的默认 shell。 | 特殊场景使用 |
ONBUILD | 下游构建阶段 | 为派生镜像注册触发指令。 | 谨慎使用 |
六、核心指令详解
1. FROM
语法:
FROM [--platform=<platform>] <image>[:<tag>] [AS <name>]
FROM [--platform=<platform>] <image>[@<digest>] [AS <name>]作用:
- 指定基础镜像。
- 开启一个新的构建阶段。
- 多阶段构建中可以通过
AS <name>给阶段命名。
参数说明:
| 参数 | 含义 | 示例 |
|---|---|---|
<image> | 基础镜像名称。 | python、nginx、alpine |
<tag> | 镜像标签。 | 3.12-slim、1.27-alpine |
<digest> | 镜像内容摘要,用于更严格锁定版本。 | @sha256:... |
--platform | 指定目标平台。 | --platform=linux/amd64 |
AS <name> | 命名当前构建阶段。 | AS builder |
示例:
FROM golang:1.22 AS builder
WORKDIR /src
COPY . .
RUN go build -o /out/app .
FROM alpine:3.20
COPY --from=builder /out/app /usr/local/bin/app
ENTRYPOINT ["app"]实践建议:
- 避免生产环境直接使用
latest,因为它会随上游变化而漂移。 - 尽量选择官方镜像或组织内部维护的可信基础镜像。
- 对稳定性要求高的生产镜像,可以用 digest 锁定基础镜像内容。
- 多阶段构建中,给阶段命名比依赖阶段序号更可维护。
2. ARG
语法:
ARG <name>[=<default value>]作用:
- 定义构建时变量。
- 可以通过
docker build --build-arg传入。 - 适合控制版本号、构建目标、代理地址等构建期参数。
示例:
ARG PYTHON_VERSION=3.12
FROM python:${PYTHON_VERSION}-slim
ARG APP_VERSION=dev
RUN echo "building version: ${APP_VERSION}"构建:
docker build \
--build-arg PYTHON_VERSION=3.12 \
--build-arg APP_VERSION=2026.05.28 \
-t flask-demo:2026.05.28 .关键规则:
ARG从声明所在行开始生效。- 写在第一个
FROM之前的ARG可以用于FROM行。 ARG的值不适合存放密码、令牌、私钥等敏感信息,因为构建参数可能出现在镜像历史或构建证明材料中。
3. ENV
语法:
ENV <key>=<value> [<key>=<value>...]作用:
- 设置环境变量。
- 值会持久化到镜像配置中,容器运行时默认可见。
- 可被后续
RUN、CMD、ENTRYPOINT等指令使用。
示例:
ENV APP_ENV=production \
PYTHONUNBUFFERED=1
CMD ["python", "app.py"]与 ARG 的区别:
| 对比项 | ARG | ENV |
|---|---|---|
| 主要阶段 | 构建阶段 | 构建阶段与运行阶段 |
| 是否持久化到镜像配置 | 通常不作为运行环境变量持久化 | 是 |
是否可被 docker run -e 覆盖 | 不适用 | 可以 |
| 适合内容 | 版本号、构建开关、代理参数 | 应用运行默认配置 |
| 是否适合放密钥 | 不适合 | 不适合 |
4. WORKDIR
语法:
WORKDIR /path/to/workdir作用:
- 设置后续
RUN、CMD、ENTRYPOINT、COPY、ADD的工作目录。 - 如果目录不存在,构建器会自动创建。
示例:
FROM node:22-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
CMD ["node", "server.js"]实践建议:
- 使用绝对路径,例如
WORKDIR /app。 - 不要依赖基础镜像中未知的默认工作目录。
- 多次使用相对
WORKDIR时,后一次会基于前一次路径继续拼接,容易造成误解。
5. COPY
语法:
COPY [OPTIONS] <src>... <dest>
COPY [OPTIONS] ["<src>", ... "<dest>"]作用:
- 从构建上下文复制文件到镜像。
- 在多阶段构建中,也可以从前一阶段、外部镜像或命名上下文复制文件。
常用参数:
| 参数 | 作用 | 示例 |
|---|---|---|
--from=<stage> | 从指定构建阶段、镜像或命名上下文复制。 | COPY --from=builder /out/app /app |
--chown=<user>:<group> | 设置复制后文件的所有者。 | COPY --chown=appuser:appuser . /app |
--chmod=<mode> | 设置复制后文件权限。 | COPY --chmod=755 start.sh /usr/local/bin/start.sh |
--link | 使用独立层复制文件,有助于部分缓存和重用场景。 | COPY --link . /app |
示例:
FROM golang:1.22 AS builder
WORKDIR /src
COPY . .
RUN go build -o /out/app .
FROM alpine:3.20
COPY --from=builder /out/app /usr/local/bin/app
ENTRYPOINT ["app"]常见错误:
COPY /Users/me/project/app /app问题在于 COPY 默认不能读取构建上下文之外的任意宿主机路径。正确做法是从项目根目录执行构建,并使用相对路径:
COPY app /app实践建议:
- 本地普通文件复制优先使用
COPY,语义更明确。 - 使用
.dockerignore控制构建上下文。 - 对依赖清单和业务源码分开
COPY,提高缓存命中率。 - 多阶段构建中使用
COPY --from=<stage>复制最终产物,不复制编译器和源码。
6. ADD
语法:
ADD [OPTIONS] <src>... <dest>
ADD [OPTIONS] ["<src>", ... "<dest>"]作用:
- 复制文件,基础能力与
COPY接近。 - 额外支持一些特殊来源和行为,例如本地 tar 包自动解包、远程 URL、Git 仓库等。
常用参数:
| 参数 | 作用 | 示例 |
|---|---|---|
--checksum=<checksum> | 校验远程资源内容,降低供应链风险。 | ADD --checksum=sha256:... https://example.com/file.tar.gz /tmp/ |
--chown=<user>:<group> | 设置文件所有者。 | ADD --chown=appuser:appuser app.tar.gz /app/ |
--chmod=<mode> | 设置文件权限。 | ADD --chmod=755 tool /usr/local/bin/tool |
--keep-git-dir=<bool> | 从 Git 源添加内容时保留 .git 目录。 | ADD --keep-git-dir=true ... |
--exclude=<pattern> | 添加时排除指定路径。 | ADD --exclude=*.md . /app |
实践建议:
- 普通文件复制使用
COPY。 - 只有确实需要
ADD的特殊能力时才使用ADD。 - 从远程 URL 添加文件时应结合校验、固定版本和可信源,不要下载可变的未校验脚本直接执行。
7. RUN
语法:
RUN <command>
RUN ["executable", "param1", "param2"]作用:
- 在构建阶段执行命令。
- 常用于安装依赖、编译程序、创建用户、整理文件权限。
示例:
RUN apt-get update \
&& apt-get install -y --no-install-recommends curl ca-certificates \
&& rm -rf /var/lib/apt/lists/*BuildKit 常用参数:
| 参数 | 作用 | 示例 |
|---|---|---|
--mount=type=cache | 挂载构建缓存,适合包管理器缓存。 | RUN --mount=type=cache,target=/root/.cache/pip pip install -r requirements.txt |
--mount=type=secret | 构建时临时挂载密钥,不写入最终镜像层。 | RUN --mount=type=secret,id=pip_conf,target=/etc/pip.conf pip install -r requirements.txt |
--mount=type=ssh | 构建时访问 SSH agent,适合私有 Git 依赖。 | RUN --mount=type=ssh git clone git@github.com:org/repo.git |
--network=<type> | 控制构建步骤的网络模式。 | RUN --network=none make test |
使用 secret 的构建命令示例:
docker build \
--secret id=pip_conf,src=./pip.conf \
-t secure-python-app:v1 .Dockerfile:
# syntax=docker/dockerfile:1
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt ./
RUN --mount=type=secret,id=pip_conf,target=/etc/pip.conf \
pip install --no-cache-dir -r requirements.txt实践建议:
- 把高频变化步骤放在 Dockerfile 下方。
- 安装依赖后清理包管理器缓存,减少镜像体积。
- 不要在
RUN中写入明文密钥。 - 能用官方包管理器安装的依赖,不要从不可信 URL 下载脚本直接执行。
8. CMD
语法:
CMD ["executable", "param1", "param2"]
CMD ["param1", "param2"]
CMD command param1 param2作用:
- 设置容器默认命令或默认参数。
docker run IMAGE <command>可以覆盖CMD。- 一个 Dockerfile 中可以写多个
CMD,但只有最后一个生效。
示例:
CMD ["python", "app.py"]与 ENTRYPOINT 配合时,CMD 常作为默认参数:
ENTRYPOINT ["python"]
CMD ["app.py"]运行:
docker run image-name
docker run image-name -m http.server 8080第二条命令会把 CMD 的默认参数替换为 -m http.server 8080,但仍使用 ENTRYPOINT ["python"]。
9. ENTRYPOINT
语法:
ENTRYPOINT ["executable", "param1", "param2"]
ENTRYPOINT command param1 param2作用:
- 设置容器默认入口程序。
- 适合把镜像设计成一个固定可执行程序。
- 可以用
docker run --entrypoint覆盖。
示例:
ENTRYPOINT ["nginx", "-g", "daemon off;"]CMD 与 ENTRYPOINT 的常见组合:
| 目标 | 推荐写法 | 说明 |
|---|---|---|
| 普通 Web 应用 | CMD ["python", "app.py"] | 允许运行时用其他命令覆盖。 |
| 固定工具镜像 | ENTRYPOINT ["kubectl"] + CMD ["--help"] | 默认显示帮助,也可追加子命令。 |
| 固定服务进程 | ENTRYPOINT ["nginx", "-g", "daemon off;"] | 镜像主要职责明确。 |
实践建议:
- 容器主进程优先使用 exec form。
- shell form 的
ENTRYPOINT会经过 shell,可能影响信号传递和参数追加。 - 如果入口脚本需要启动主进程,脚本末尾应使用
exec "$@"或exec app-command交出 PID 1。
10. EXPOSE
语法:
EXPOSE <port>
EXPOSE <port>/<protocol>作用:
- 声明容器内应用计划监听的端口。
- 属于镜像元数据,不会自动把端口发布到宿主机。
- 默认协议是 TCP,也可以写
udp。
示例:
EXPOSE 5000
EXPOSE 53/udp要让宿主机能访问服务,仍然需要运行时发布端口:
docker run -p 5000:5000 flask-demo:v1实践建议:
EXPOSE用于文档化镜像意图。- 对外访问能力由
docker run -p、Composeports或编排平台 Service 配置决定。
11. USER
语法:
USER <user>[:<group>]
USER <uid>[:<gid>]作用:
- 设置后续
RUN指令的执行用户。 - 设置容器运行时的默认用户。
示例:
RUN addgroup --system app && adduser --system --ingroup app app
USER app实践建议:
- 生产镜像尽量避免用
root作为默认运行用户。 - 切换用户前先处理好文件权限。
- 使用数字 UID/GID 可以减少运行环境中用户名解析差异,但可读性略差。
12. LABEL
语法:
LABEL <key>=<value> [<key>=<value>...]作用:
- 给镜像写入元数据。
- 常用于版本、维护者、源码地址、构建时间、许可证等信息。
示例:
LABEL org.opencontainers.image.title="flask-demo" \
org.opencontainers.image.version="1.0.0" \
org.opencontainers.image.source="https://example.com/repo"实践建议:
- 优先使用 OCI Image Spec 推荐的标签命名,例如
org.opencontainers.image.source。 - 旧指令
MAINTAINER已不推荐使用,应使用LABEL表达维护信息。
13. HEALTHCHECK
语法:
HEALTHCHECK [OPTIONS] CMD command
HEALTHCHECK NONE作用:
- 定义容器健康检查。
- 健康状态可为
starting、healthy、unhealthy。 - 如果基础镜像已经定义健康检查,可以用
HEALTHCHECK NONE禁用。
常用参数:
| 参数 | 默认值 | 作用 |
|---|---|---|
--interval | 30s | 两次健康检查之间的间隔。 |
--timeout | 30s | 单次检查最长允许执行时间。 |
--start-period | 0s | 容器启动宽限期。 |
--start-interval | 5s | 启动宽限期内的检查间隔,要求 Docker Engine 25.0 或更高版本。 |
--retries | 3 | 连续失败多少次后标记为不健康。 |
示例:
HEALTHCHECK --interval=30s --timeout=3s --start-period=20s --retries=3 \
CMD python -c "import urllib.request; urllib.request.urlopen('http://127.0.0.1:5000/', timeout=2)" || exit 1退出码含义:
| 退出码 | 含义 |
|---|---|
0 | 健康 |
1 | 不健康 |
2 | 保留,不应使用 |
实践建议:
- 健康检查应轻量、稳定、超时时间明确。
- 不要让健康检查依赖外部不稳定服务,否则容易误判应用自身状态。
- 一个 Dockerfile 中只有最后一个
HEALTHCHECK生效。
14. VOLUME
语法:
VOLUME ["/data"]
VOLUME /data作用:
- 声明容器内某个路径适合作为挂载点。
- 运行容器时,Docker 可以为该路径创建匿名卷。
示例:
VOLUME ["/var/lib/mysql"]实践建议:
- 数据库镜像、文件存储镜像可以使用
VOLUME表达持久化意图。 - 普通业务镜像不一定需要声明
VOLUME,因为实际挂载策略通常由 Compose、Kubernetes 或运行命令决定。 - 不要把应用代码目录随意声明为
VOLUME,否则运行时挂载可能遮蔽镜像内已有文件。
15. STOPSIGNAL
语法:
STOPSIGNAL signal作用:
- 设置
docker stop停止容器时发送给主进程的系统信号。 - 未指定时默认使用
SIGTERM。
示例:
STOPSIGNAL SIGTERM实践建议:
- 大多数 Linux Web 应用保持默认
SIGTERM即可。 - 只有应用明确要求其他停止信号时再修改。
- 修改信号不能替代正确的 PID 1 和优雅退出逻辑。
16. SHELL
语法:
SHELL ["executable", "parameters"]作用:
- 修改 shell form 的默认 shell。
- Linux 默认 shell 通常是
["/bin/sh", "-c"]。 - Windows 镜像中常用于切换
cmd与powershell。
示例:
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
RUN echo "hello" | tee /tmp/hello.txt实践建议:
- Linux 镜像中如需使用 Bash 特性,应确认基础镜像确实安装了 Bash。
- 修改
SHELL会影响后续 shell form 的RUN、CMD、ENTRYPOINT。
17. ONBUILD
语法:
ONBUILD <INSTRUCTION>作用:
- 为当前镜像注册触发器。
- 当下游 Dockerfile 使用该镜像作为基础镜像时,触发器会在下游构建中执行。
示例:
ONBUILD COPY . /app/src
ONBUILD RUN /usr/local/bin/build-app /app/src实践建议:
- 只适合制作框架型基础镜像或构建器镜像。
- 普通业务镜像不建议使用,容易让下游构建行为变得隐蔽。
ONBUILD ONBUILD不允许;ONBUILD也不能触发FROM或MAINTAINER。
七、多阶段构建参数
多阶段构建通过多个 FROM 拆分“构建环境”和“运行环境”。最终镜像只保留运行所需产物。
示例:
FROM golang:1.22 AS builder
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o /out/app .
FROM scratch
COPY --from=builder /out/app /app
EXPOSE 8080
ENTRYPOINT ["/app"]关键参数:
| 写法 | 含义 |
|---|---|
FROM golang:1.22 AS builder | 创建名为 builder 的构建阶段。 |
COPY --from=builder /out/app /app | 从 builder 阶段复制构建产物。 |
docker build --target builder . | 只构建到指定阶段,常用于调试中间产物。 |
FROM scratch | 使用空镜像作为最终阶段,适合静态编译产物。 |
实践建议:
- 对 Go、Rust、Java、Node 前端构建等场景,多阶段构建通常能显著减少最终镜像体积。
scratch镜像没有 shell、包管理器、证书和调试工具,只适合明确知道运行依赖的程序。- 如果程序需要 HTTPS 根证书、时区文件或动态链接库,应从构建阶段或基础运行镜像中显式复制,或选择
distroless、alpine等更合适的运行镜像。
八、完整示例:Flask 应用 Dockerfile
# syntax=docker/dockerfile:1
FROM python:3.12-slim
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1
WORKDIR /app
COPY app/requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt
COPY app/ ./
RUN addgroup --system app && adduser --system --ingroup app app
USER app
EXPOSE 5000
HEALTHCHECK --interval=30s --timeout=3s --start-period=20s --retries=3 \
CMD python -c "import urllib.request; urllib.request.urlopen('http://127.0.0.1:5000/', timeout=2)" || exit 1
CMD ["python", "app.py"]逐行说明:
| 行 | 说明 |
|---|---|
# syntax=docker/dockerfile:1 | 使用稳定 Dockerfile frontend。 |
FROM python:3.12-slim | 基于较小的 Python 官方镜像。 |
ENV ... | 设置 Python 运行环境默认行为。 |
WORKDIR /app | 固定应用目录,避免依赖基础镜像默认目录。 |
COPY app/requirements.txt ./ | 先复制依赖清单,为缓存优化做准备。 |
RUN pip install ... | 安装 Python 依赖,不保留 pip 下载缓存。 |
COPY app/ ./ | 再复制高频变化的业务源码。 |
RUN addgroup ... | 创建非 root 用户。 |
USER app | 让容器默认以低权限用户运行。 |
EXPOSE 5000 | 声明应用监听容器内 5000 端口。 |
HEALTHCHECK ... | 定义本地 HTTP 健康检查。 |
CMD ["python", "app.py"] | 设置默认启动命令。 |
九、审查清单
编写或评审 Dockerfile 时,可以逐项检查:
十、常见误区
| 误区 | 正确理解 |
|---|---|
EXPOSE 5000 后宿主机就能访问容器端口。 | EXPOSE 只是声明元数据,宿主机访问还需要 docker run -p 5000:5000。 |
COPY 可以复制宿主机任意绝对路径。 | COPY 默认只能读取构建上下文中的文件。 |
ARG 可以安全保存密码。 | ARG 不适合保存秘密信息,构建参数可能被历史记录或构建证明暴露。 |
CMD 和 ENTRYPOINT 完全一样。 | CMD 更像默认命令或默认参数,ENTRYPOINT 更像固定入口程序。 |
| 多阶段构建一定适合所有语言。 | 对编译型语言收益明显;对 Python、PHP 等运行时依赖较重的语言,收益取决于依赖形态。 |
scratch 是最好的运行镜像。 | scratch 极小但几乎没有系统能力;需要证书、shell、动态库或调试能力时并不合适。 |
