4.2 Dockerfile 常用指令
如果需要更复杂的定制,可以在 Dockerfile 中添加更多指令,Dockerfile 常用指令如下表所示。
| 命令 | 描述 |
|---|---|
| FROM | 指定基础镜像,用于后续指令构建。 |
| LABEL | 添加镜像的元数据,使用键值对的形式。 |
| RUN | 创建镜像时,在镜像中要执行的命令。 |
| CMD | 指定容器启动时默认要执行的命令(可以被覆盖)。如果执行 docker run 后面跟启动命令会被覆盖掉。 |
| ENTRYPOINT | 设置容器创建时的主要命令(不可被覆盖)。 |
| SHELL | 覆盖Docker中默认的shell,用于RUN、CMD和ENTRYPOINT指令。 |
| EXPOSE | 声明容器运行时监听的特定网络端口。 |
| ENV | 设置环境变量 |
| COPY | 将文件或目录复制到镜像中。 |
| ADD | 将文件、目录或远程 URL 复制到镜像中。 |
| WORKDIR | 指定工作目录 |
| VOLUME | 为容器创建挂载点或声明卷。 |
| USER | 切换执行后续命令的用户和用户组,但这个用户必需首先已使用 RUN 的命令进行创建好了。 |
| ARG | 定义在构建过程中传递给构建器的变量,可使用 "docker build" 命令设置。 |
| ONBUILD | 当该镜像被用作另一个构建过程的基础时,添加触发器。 |
| STOPSIGNAL | 设置发送给容器以退出的系统调用信号。 |
| HEALTHCHECK | 定义周期性检查容器健康状态的命令。 |
FROM 指令:FROM 指令用于指定基础镜像,必须是 Dockerfile 的第一个指令。基础镜像可以是官方镜像如
ubuntu:20.04,也可以是用户自定义的镜像。如果不指定标签,默认使用latest标签。例如FROM nginx表示基于最新版 nginx 镜像构建。每个 Dockerfile 可以有多个 FROM 指令用于构建多阶段镜像,但最终只会保留最后一个 FROM 生成的镜像层。基础镜像的选择直接影响最终镜像的大小和安全性,通常推荐使用官方维护的最小化镜像如alpine版本。最后的AS name可以选择为新生成阶段指定名称。
- FROM 指令格式:
FROM <image>[:<tag>] [AS <name>]- 参数说明:
<image>:必需,指定基础镜像名称。:<tag>:可选,指定镜像版本标签。AS <name>:可选,为构建阶段命名。
- FROM 指令示例:
FROM nginx:1.23
FROM python:3.9-alpine
FROM ubuntu:20.04 AS builderLABEL 指令:用于添加元数据到镜像,采用键值对格式。
- LABEL 指令格式:
LABEL <key>=<value>- LABEL 指令示例:
LABEL version="1.0.1"
LABEL maintainer="admin@example.com"RUN 指令:在镜像构建过程中执行命令,每条 RUN 指令都会创建一个新的镜像层。RUN 有两种格式:Shell 格式(
RUN <command>)和 Exec 格式(RUN ["executable", "param1", "param2"])。Shell 格式默认使用/bin/sh -c执行,Exec 格式直接调用可执行文件。为了减少镜像层数,建议将多个命令合并到单个 RUN 指令中,用&&连接命令,用\换行。例如安装软件包时应该先更新包列表再安装,最后清理缓存。
- RUN 指令格式:
# Shell 格式
RUN <command>
# Exec 格式
RUN ["executable", "param1", "param2"]- RUN 指令示例:
RUN yum -y install wget
RUN apt-get update && apt-get install -y \
git \
curl \
&& rm -rf /var/lib/apt/lists/*
RUN ["/bin/bash", "-c", "echo Hello, Docker!"]
RUN ["yum", "-y", "install", "wget"]CMD 指令:指定容器启动时的默认命令,一个 Dockerfile 只能有一个有效的 CMD 指令。如果
docker run指定了命令,CMD 会被覆盖。CMD 有三种格式:Exec 格式(推荐)、Shell 格式和作为 ENTRYPOINT 的参数。Exec 格式直接调用可执行文件,不经过 shell 处理环境变量;Shell 格式会通过/bin/sh -c执行。例如运行 Python 应用时可以使用CMD ["python", "app.py"]。
- CMD 指令格式:
# Exec 格式(推荐)
CMD ["executable","param1","param2"]
# Shell 格式
CMD command param1 param2
# 作为 ENTRYPOINT 的参数
CMD ["param1","param2"]- CMD 指令示例:
# Shell 格式示例: 运行 Python 脚本
CMD python app.py
# Exec 格式示例: 运行 Nginx
CMD ["nginx", "-g", "daemon off;"]
# 作为 ENTRYPOINT 参数
CMD ["--port=8080"]ENTRYPOINT 指令:用于设置容器启动时的主要命令,与 CMD 不同,它不会被 docker run 后面的命令覆盖。
- ENTRYPOINT 指令格式:
# Shell 格式
ENTRYPOINT command param1 param2
# Exec 格式
ENTRYPOINT ["executable", "param1", "param2"]- ENTRYPOINT 指令示例:
# Shell 格式示例: 运行 Python 脚本
ENTRYPOINT python app.py
# Exec 格式示例: 运行 Nginx
ENTRYPOINT ["nginx", "-g", "daemon off;"]SHELL 指令:用于覆盖 Docker 默认的 shell 程序。默认情况下 Linux 使用
["/bin/sh", "-c"],Windows 使用["cmd", "/S", "/C"]。这个指令会影响 RUN、CMD 和 ENTRYPOINT 的 shell 格式执行方式。
- SHELL 指令格式
SHELL ["executable", "parameters"]- SHELL 指令示例:
# 切换为 PowerShell
SHELL ["powershell", "-command"]
# 切换回默认 shell
SHELL ["/bin/sh", "-c"]EXPOSE 指令:声明容器运行时监听的网络端口,只是文档性质的说明,不会实际发布端口。实际端口映射需要在运行容器时通过
-p参数设置。EXPOSE 可以指定 TCP 或 UDP 协议,默认是 TCP。例如EXPOSE 80/tcp表示容器会监听 80 端口。这个指令主要作用是帮助使用者理解容器提供的服务端口,同时被一些编排工具如 Docker Compose 使用。
- EXPOSE 指令格式:
EXPOSE <port> [<port>/<protocol>...]- EXPOSE 指令示例:
# 声明单个端口
EXPOSE 80
# 声明多个端口
EXPOSE 80 443
# 指定协议
EXPOSE 53/udpENV 指令:设置环境变量,这些变量会在构建阶段和容器运行时生效。变量可以被后续的 RUN、CMD 等指令使用,也会持久化到容器中。定义的环境变量会出现在
docker inspect的输出中,也可以在容器运行时通过docker run --env参数覆盖。
- ENV 指令格式:
# 定义单个变量
ENV <key> <value>
# 一次性定义多个变量
ENV <key1>=<value1> <key2>=<value2>...- ENV 指令示例:
# 设置单个变量
ENV NODE_VERSION=18.15.0
# 设置多个变量
ENV NODE_VERSION=18.15.0 NODE_ENV=productionCOPY 指令:将文件或目录从构建上下文复制到镜像中,源路径必须是相对路径(相对于 Dockerfile 所在目录),不能使用绝对路径或
../父目录引用。目标路径可以是绝对路径或相对于 WORKDIR 的路径。COPY 会保留文件元数据(权限、时间戳),但不支持自动解压压缩包。与 ADD 指令相比,COPY 更推荐用于简单的文件复制操作,因为它的行为更可预测。例如复制项目代码到镜像的/app目录。
- COPY 指令格式:
COPY <src>... <dest>- COPY 指令示例:
# 复制单个文件
COPY requirements.txt /app/
# 复制整个目录
COPY src /app/src
# 使用通配符复制多个文件
COPY *.sh /scripts/ADD 指令:ADD 指令功能类似 COPY,但增加了自动解压压缩包和处理远程 URL 的能力。当源路径是本地压缩文件(如 .tar、.gz)时,ADD 会自动解压到目标路径。源路径也可以是 URL,Docker 会下载文件到镜像中。例如
ADD https://example.com/file.tar.gz /tmp会下载并解压文件。由于 ADD 行为较复杂,官方建议优先使用 COPY,除非明确需要解压或下载功能。
- ADD 指令格式:
ADD <src>... <dest>- ADD 指令示例:
# 添加本地文件
ADD app.jar /opt/app/
# 自动解压压缩包
ADD project.tar.gz /app
# 从 URL 下载文件
ADD https://example.com/data.json /dataWORKDIR 指令:设置工作目录,相当于
cd命令的效果,如果目录不存在会自动创建。后续的 RUN、CMD、COPY 等指令都会在此目录下执行。WORKDIR 可以多次使用,路径可以是相对路径(基于前一个 WORKDIR)。例如WORKDIR /app后接WORKDIR src最终路径是/app/src。使用 WORKDIR 可以避免在 RUN 指令中频繁使用cd命令,使 Dockerfile 更清晰。
- WORKDIR 指令格式:
WORKDIR <path>- WORKDIR 指令示例:
WORKDIR /usr/src
WORKDIR app
RUN pwd # 输出 /usr/src/appVOLUME 指令:创建挂载点或声明卷,会在容器运行时自动挂载匿名卷。主要用途是保留重要数据(如数据库文件)或共享目录。例如
VOLUME /data确保/data目录的数据持久化。实际挂载的主机目录可以通过docker inspect查看。VOLUME 指令不能在构建阶段向挂载点写入数据,因为这些数据在运行时会被覆盖。数据卷可以在容器间共享和重用,即使容器被删除,卷数据仍然存在。VOLUME 声明后,运行时可以通过 -v 参数覆盖,但无法在构建阶段向挂载点写入数据(会被运行时覆盖)。
- VOLUME 指令格式:
VOLUME ["<path1>", "<path2>", ...]- VOLUME 指令示例:
# 声明单个卷
VOLUME /data
# 声明多个卷
VOLUME ["/data", "/config"]USER 指令:切换执行后续指令的用户身份,用户必须已通过 RUN 指令创建。例如
USER nobody让后续命令以 nobody 身份运行,增强安全性。该用户需要有足够的权限访问所需文件。USER 会影响 RUN、CMD、ENTRYPOINT 的执行身份。在运行时可以通过docker run -u覆盖此设置。典型的用法是在安装软件包后创建非 root 用户并切换,避免容器以 root 权限运行。
- USER 指令格式:
USER <user>[:<group>]- USER 指令示例:
RUN groupadd -r app && useradd -r -g app appuser
USER appuser
CMD ["python", "app.py"]ARG 指令:指令定义构建时的变量。这些变量只在构建阶段有效,不会保留到容器运行时。可以通过
docker build --build-arg <name>=<value>覆盖默认值。例如ARG VERSION=latest定义版本变量。ARG 变量可以用于控制构建流程,如选择不同的软件版本。常见的预定义变量包括 HTTP_PROXY 等代理设置。
- ARG 指令格式:
ARG <name>[=<默认值>]- ARG 指令示例:
ARG NODE_VERSION=14
FROM node:${NODE_VERSION}ONBUILD 指令:设置触发器。当当前镜像被用作其他镜像的基础时,这些指令会被触发执行。例如
ONBUILD COPY . /app会在子镜像构建时自动复制文件。ONBUILD 常用于创建基础镜像模板,子镜像可以继承特定的构建步骤。通过docker inspect可以查看镜像的 ONBUILD 触发器。
- ONBUILD 指令格式:
ONBUILD <其他指令>- ONBUILD 指令示例:
ONBUILD RUN npm install
ONBUILD COPY . /appSTOPSIGNAL 指令:设置容器停止时发送的系统信号。信号可以是数字(如 9)或信号名(如 SIGKILL)。默认的信号是 SIGTERM,允许容器优雅退出。如果需要强制终止,可以设置为 SIGKILL。例如
STOPSIGNAL SIGTERM确保容器收到终止信号。这个设置会影响docker stop命令的行为。
- STOPSIGNAL 指令格式:
STOPSIGNAL <信号>- STOPSIGNAL 指令示例:
STOPSIGNAL SIGQUITHEALTHCHECK 指令:定义容器健康检查,Docker 会定期执行检查命令判断容器是否健康。检查命令返回 0 表示健康,1 表示不健康。选项包括
--interval(检查间隔)、--timeout(超时时间)、--start-period(启动宽限期)和--retries(重试次数)。例如HEALTHCHECK --interval=30s CMD curl -f http://localhost/每30秒检查Web服务是否响应。健康状态可以通过docker ps查看。
- HEALTHCHECK 指令格式:
HEALTHCHECK [OPTIONS] CMD <command>- HEALTHCHECK 指令示例:
HEALTHCHECK --interval=5m --timeout=3s \
CMD curl -f http://localhost/ || exit 1