Skip to content

Dockerfile常用参数

核心概念:

  • Dockerfile: 一个文本文件,包含一系列用于构建 Docker 镜像的指令。
  • 镜像层: 每条指令(除了极少数如ARG)在执行时都会在基础镜像之上创建一个新的只读层。
  • 构建上下文: 运行 docker build 时指定的路径(或 URL)。Docker 守护进程在构建开始时会将整个上下文(递归地)发送给它。指令如 COPYADD 操作的文件必须位于此上下文中。

一、基础与必备指令

FROM

  • 用途: 指定基础镜像。这是 Dockerfile 的第一条有效指令(ARG 可以在它之前,用于定义后续 FROM 使用的变量)。
  • 语法:
    dockerfile
    FROM [--platform=<platform>] <image>[:<tag>] [AS <name>]
  • 说明:
    • <image>: 基础镜像名称(如 ubuntu, python, nginx)。
    • <tag>: 镜像标签(如 20.04, 3.9-slim, latest)。强烈建议指定明确版本,避免因 latest 变化导致构建失败或不一致。
    • [AS <name>]: 在多阶段构建中,为当前构建阶段命名,方便后续阶段引用。
    • --platform: 指定目标平台(如 linux/amd64, linux/arm64)。
  • 示例:
    dockerfile
    FROM ubuntu:22.04
    FROM python:3.11-slim-bullseye AS builder
    FROM --platform=linux/arm64 nginx:1.23-alpine

RUN

  • 用途: 在构建过程中执行命令。这些命令在构建时运行,用于安装软件包、编译代码、配置环境等。每条 RUN 都会创建一个新的镜像层。

  • 语法 (两种形式):

    • Shell 形式: RUN <command> (默认在 /bin/sh -c 下执行)
    dockerfile
    RUN apt-get update && apt-get install -y curl
    RUN echo "Hello from the build process" > /tmp/greeting.txt
    • Exec 形式: RUN ["executable", "param1", "param2"] (直接执行可执行文件,不通过 shell 解析)
      dockerfile
      RUN ["/bin/bash", "-c", "echo 'Exec form' > /tmp/exec.txt"]
  • 区别与最佳实践:

    • Shell 形式更常见,更易读。 可以使用环境变量、管道 |、逻辑运算符 &&||;
    • Exec 形式 避免 shell 字符串解析可能带来的意外行为(特别是当参数包含空格或特殊字符时),并且明确指定了要运行的二进制文件。 对于不依赖 shell 功能的简单命令或需要避免 shell 干扰的场景更合适。
    • 关键点: 将多个命令合并到一个 RUN 指令中(使用 &&\ 换行),减少不必要的镜像层数量。安装后记得清理缓存(如 rm -rf /var/lib/apt/lists/*)。
  • 示例:

    dockerfile
    RUN apt-get update \
        && apt-get install -y --no-install-recommends \
            git \
            build-essential \
            ca-certificates \
        && rm -rf /var/lib/apt/lists/* \
        && pip install --no-cache-dir some-package

CMD

  • 用途: 为容器提供默认的启动命令和参数。在容器启动时执行。一个 Dockerfile 中只能有一个有效的 CMD (如果写了多个,只有最后一个生效)。
  • 语法 (三种形式):
    • Exec 形式 (推荐): CMD ["executable","param1","param2"]
    • Shell 形式: CMD command param1 param2 (会被包装成 /bin/sh -c)
    • 作为 ENTRYPOINT 的参数: CMD ["param1","param2"] (必须与 ENTRYPOINT 的 Exec 形式结合使用)
  • 说明与行为:
    • CMD 定义的是默认行为。用户在 docker run 命令行中指定的任何参数都会覆盖整个 CMD
    • Exec vs Shell 形式: 推荐使用 Exec 形式,原因与 RUN 类似:避免不必要的 shell 介入,信号处理更直接(容器中的 PID 1 是应用程序本身,能正确接收 SIGTERM 等信号)。
    • CMD 的主要目的是让容器运行一个默认的进程。如果该进程退出,容器也会停止。
  • 示例:
    dockerfile
    CMD ["nginx", "-g", "daemon off;"] # 推荐写法,直接运行 nginx 主进程
    CMD python app.py # Shell 形式,PID 1 是 /bin/sh
    CMD ["/bin/bash"] # 启动 bash shell

ENTRYPOINT

  • 用途: 配置容器启动时运行的可执行文件。可以理解为容器的主程序。
  • 语法 (两种形式):
    • Exec 形式 (推荐): ENTRYPOINT ["executable", "param1", "param2"]
    • Shell 形式: ENTRYPOINT command param1 param2 (会被包装成 /bin/sh -c)
  • 说明、行为与联系 (CMD & ENTRYPOINT):
    • ENTRYPOINT 定义的是容器启动时必须运行的命令。
    • CMD 定义的参数可以作为 ENTRYPOINT默认参数
    • 组合使用 (最常见模式):
    • ENTRYPOINT 定义要执行的程序。
    • CMD 定义该程序的默认参数。
    • 用户在 docker run 命令行中指定的参数会覆盖 CMD 的内容,并作为 ENTRYPOINT 的参数。
      • 覆盖规则:
    • 用户可以在 docker run 中使用 --entrypoint 标志覆盖 ENTRYPOINT
    • 用户在 docker run 命令行末尾指定的参数会覆盖 CMD
      • Exec vs Shell 形式: 强烈推荐使用 Exec 形式。Shell 形式会使你的程序成为 shell 的子进程(PID 不是 1),导致无法正确接收 Unix 信号(如 SIGTERM),并且 docker stop 可能无法正常停止容器。
  • 示例:
    dockerfile
    ENTRYPOINT ["/usr/bin/wc"]
    CMD ["--help"] # 默认运行 `wc --help`。用户运行 `docker run myimage -l` 实际执行 `/usr/bin/wc -l`
    ENTRYPOINT ["top", "-b"] # 直接运行 top 命令,忽略 CMD 和用户命令行参数。用户运行 `docker run myimage -H` 会报错,因为 -H 被当作 top 的参数,而 top 可能不支持 -H。

COPY vs ADD

  • 共同用途: 从构建上下文复制文件或目录到镜像中

  • 语法:

    dockerfile
    COPY [--chown=<user>:<group>] [--chmod=<perms>] <src>... <dest>
    ADD [--chown=<user>:<group>] [--chmod=<perms>] <src>... <dest>
    • <src>: 构建上下文中的源路径(文件或目录)。支持通配符 (*, ?)。必须在构建上下文中!
    • <dest>: 镜像中的目标绝对路径,或相对于 WORKDIR 的路径。
    • --chown, --chmod: 设置复制后文件的所有权/权限 (仅在 Linux 容器中有效)。
  • 关键区别:

    特性COPYADD
    核心功能仅复制本地文件/目录 (来自构建上下文)COPY 功能基础上增加了两个功能:
    额外功能1自动解压:如果 <src> 是本地压缩文件 (tar, gzip, bzip2, xz) 且目标路径不以斜杠结尾,则自动解压到
    <dest>
    额外功能2远程 URL 支持<src> 可以是 URL。Docker 会下载该 URL 的内容到 <dest>。**注意:下载的文件不会被自动解压!
    **
  • 最佳实践与选择:

    • COPY 是首选: 对于简单的复制本地文件/目录需求,总是使用 COPY。它的行为更清晰、更可预测。
    • 何时使用 ADD
    • 需要自动解压本地压缩文件到镜像中时。
    • 需要从 URL 下载文件并直接放入镜像中(且不需要解压时)。注意: 通常更推荐在 RUN 指令中使用 curlwget 下载文件,因为这样可以更好地控制下载过程(如处理失败、校验和)、清理下载缓存以及利用 Docker 的层缓存机制。
      • 一般建议: 除非你明确需要 ADD 的自动解压或 URL 下载功能,否则坚持使用 COPY

WORKDIR

  • 用途: 为后续的 RUN, CMD, ENTRYPOINT, COPY, ADD 指令设置工作目录。如果目录不存在,会被自动创建。
  • 语法: WORKDIR /path/to/workdir
  • 说明:
    • 可以多次使用。后续路径如果是相对路径,将基于前一个 WORKDIR 设置。
    • 非常重要! 它使得 Dockerfile 中的路径引用更加清晰和安全,避免了在 RUN 等指令中写冗长的绝对路径。
    • 相当于 cd 命令的效果,但效果是持久的(影响后续指令)。
  • 示例:
    dockerfile
    WORKDIR /app
    COPY . . # 将构建上下文当前目录复制到镜像的 /app 目录下
    RUN python setup.py install
    CMD ["python", "main.py"] # 在 /app 下执行 main.py
    WORKDIR /logs
    RUN touch output.log # 在 /logs 下创建 output.log

ENV

  • 用途: 设置环境变量。这些变量在构建阶段和容器运行阶段都可用。
  • 语法:
    dockerfile
    ENV <key>=<value> ... # 一次设置一个或多个变量 (推荐)
    ENV <key> <value> # 旧式写法 (一次设置一个变量)
  • 说明:
    • 使用 <key>=<value> 形式可以清晰地一次设置多个变量。
    • 设置的环境变量可以在后续的 Dockerfile 指令(如 RUN)和运行中的容器内部访问。
    • 常用于配置应用程序所需的参数(如数据库连接字符串、日志级别、路径)。
  • 示例:
    dockerfile
    ENV APP_VERSION=1.0.0 \
        NODE_ENV=production \
        PATH=/usr/local/myapp/bin:$PATH
    RUN echo "Building version $APP_VERSION for $NODE_ENV" # 构建阶段使用
    CMD ["myapp"] # 运行时 myapp 可以访问 NODE_ENV 等变量

二、其他重要指令

ARG

  • 用途: 定义在构建时传递给 Docker 构建器的变量。只在构建阶段 (docker build) 有效,在容器运行阶段 (docker run) 不可用。有作用域限制(声明后生效,直到构建阶段结束或下一个 FROM 指令)。
  • 语法:
    dockerfile
    ARG <name>[=<default value>]
  • 说明与联系 (ENV):
    • 使用 docker build --build-arg <varname>=<value> 在构建时覆盖默认值或提供值。
    • 常用于控制构建过程的参数化,如指定要下载的软件版本、选择不同的构建配置。
    • ENV 的关键区别:ARG构建时变量,构建完成后消失;ENV运行时环境变量(也在构建时可用)。
    • ARG 值可以在构建时通过 ENV 指令转换成运行时的环境变量。
  • 示例:
    dockerfile
    ARG USERNAME=defaultuser
    ARG APP_VERSION=latest
    RUN useradd -ms /bin/bash $USERNAME
    ENV APP_VERSION=$APP_VERSION # 将 ARG 的值传递给 ENV,使其在运行时可用
    COPY --chown=$USERNAME app-$APP_VERSION.tar.gz /app/
    bash
    docker build --build-arg USERNAME=produser --build-arg APP_VERSION=2.1.0 -t myapp:2.1.0 .

USER

  • 用途: 设置运行后续指令 (RUN, CMD, ENTRYPOINT) 以及容器运行时的默认用户名或 UID
  • 语法: USER <user>[:<group>]USER <UID>[:<GID>]
  • 说明:
    • 安全最佳实践! 强烈建议不要一直以 root 用户运行容器。使用 USER 切换到非 root 用户,遵循最小权限原则。
    • 确保在切换用户之前,该用户(和组)已经通过 RUN(如 useradd)在镜像中创建好。
    • 影响 COPY--chown 默认行为(如果不指定 --chown,文件所有权由 USER 决定)。
  • 示例:
    dockerfile
    RUN groupadd -r appuser && useradd -r -g appuser appuser
    WORKDIR /app
    COPY --chown=appuser:appuser . . # 明确设置所有权
    USER appuser
    CMD ["python", "app.py"] # 以 appuser 身份运行

EXPOSE

  • 用途: 声明容器在运行时监听的网络端口。这是一个文档性指令和元数据设置,并不实际发布端口或导致网络连接。
  • 语法: EXPOSE <port> [<port>/<protocol>...]
  • 说明:
    • 默认协议是 TCP。如需 UDP,需明确指定 (如 EXPOSE 53/udp)。
    • 主要作用:
      • 告知镜像使用者/运维人员该容器设计上会监听哪些端口。
      • 在使用 docker run -P 时,Docker 会自动将容器中所有 EXPOSE 的端口映射到宿主机的高位随机端口。
      • docker network 连接容器时,EXPOSE 的端口信息有助于服务发现。
        • 实际发布端口(使外部可访问)必须在 docker run 时使用 -p-P 标志显式完成。
  • 示例: EXPOSE 80/tcp 443/tcp 8080

VOLUME

  • 用途: 创建一个具有指定名称的挂载点,并将其标记为从宿主机或其他容器挂载外部卷的位置。
  • 语法: VOLUME ["/data"]VOLUME /data /otherdata
  • 说明:
    • 主要目的是数据持久化和共享。存储在 VOLUME 指定路径下的数据不会被打包进镜像层,并且在容器停止后仍然存在。
    • docker run 时,如果没有显式使用 -v--mount 绑定宿主机目录或命名卷,Docker 会自动创建一个匿名的数据卷绑定到这个挂载点。
    • 在 Dockerfile 中使用 VOLUME 可以明确告知用户镜像中哪些路径是设计用于存放持久化数据的。
    • VOLUME 之后对该路径的修改(RUNCOPY不会生效(因为挂载发生在运行时,会覆盖镜像层中的内容)。最佳实践: 确保 VOLUME 指令你需要将文件复制到该目录的操作(如 COPY之后声明。
  • 示例:
    dockerfile
    COPY initial-data.json /data/ # 将初始数据复制到 /data
    VOLUME /data # 声明 /data 为卷。运行时,如果用户不绑定卷,Docker 会创建匿名卷,initial-data.json 会被复制到这个匿名卷中。如果用户绑定了一个宿主机目录(可能为空)到 /data,则 initial-data.json 会被隐藏。

三、总结与对比表

指令主要用途作用阶段是否创建层关键点/区别/联系
FROM指定基础镜像构建必须是第一条有效指令。多阶段构建核心。
RUN在构建时执行命令构建合并命令减少层。Shell vs Exec 形式。
CMD容器默认启动命令/参数容器运行定义默认行为,可被 docker run 覆盖。常与 ENTRYPOINT 配合 (提供默认参数)。
ENTRYPOINT容器主启动程序容器运行定义容器主程序。可被 --entrypoint 覆盖。常与 CMD 配合 (CMD 作默认参数)。
COPY复制本地文件/目录 (上下文 -> 镜像)构建首选复制方式。行为明确。
ADD复制 + 自动解压本地压缩包 + 下载 URL 文件构建功能多于 COPY (解压、下载)。仅在需要这些额外功能时使用。
WORKDIR设置后续指令的工作目录构建 & 运行影响后续 RUN/CMD/ENTRYPOINT/COPY/ADD 的路径。相当于持久化的 cd
ENV设置环境变量构建 & 运行构建和运行时均可用。用于配置应用程序。
ARG定义构建时变量仅构建只在 docker build 时有效。可通过 --build-arg 传递。常转为 ENV 供运行时用。
USER设置运行用户 (UID/GID)构建 & 运行安全最佳实践! 切换到非 root 用户。需确保用户已创建。
EXPOSE声明容器监听端口元数据文档性/声明性。不实际发布端口。-P 依赖它。-p 才是实际发布。
VOLUME声明数据卷挂载点元数据声明性。用于持久化和共享数据。运行时自动创建匿名卷或需用户绑定。

核心联系:

  1. ENTRYPOINT & CMD: 共同定义容器启动时的行为。ENTRYPOINT 是主程序,CMD 是其默认参数。用户 docker run 参数覆盖 CMD
  2. COPY & ADD: ADDCOPY 的超集,增加了自动解压和 URL 下载功能。简单复制用 COPY
  3. ENV & ARG: ARG 用于构建时参数化,构建后消失;ENV 设置的环境变量在构建和运行时都可用。可以将 ARG 的值赋给 ENV 使其在运行时保留。
  4. WORKDIR:RUN, CMD, ENTRYPOINT, COPY, ADD 提供相对路径的基准。
  5. 层创建 (RUN, COPY, ADD): 这些指令会创建新的镜像层。优化原则是:合并相关操作(尤其是 RUN ),清理不必要的临时文件,减少最终镜像层数和大小。

最佳实践总结:

  • 使用明确的 FROM 标签。
  • 合并 RUN 指令,清理缓存。
  • 优先使用 COPY 而非 ADD
  • 使用 WORKDIR 设置绝对路径。
  • CMDENTRYPOINT 使用 Exec 形式
  • 利用 ENTRYPOINTCMD 的组合。
  • 使用 ENV 设置配置。
  • 使用 ARG 参数化构建。
  • 始终使用非 root 用户 (USER) 运行容器。
  • 使用 EXPOSE 声明端口。
  • 使用 VOLUME 声明持久化数据位置。
  • 注意指令顺序(如 VOLUME 在复制初始数据之后)。

掌握这些指令及其区别联系,你就能编写出高效、安全、可维护的 Dockerfile 了。

/src/technology/docker/Dockerfile%E5%B8%B8%E7%94%A8%E5%8F%82%E6%95%B0.html