Docker 命令 之 Dockerfile
摘要
-
本文介绍 Docker 命令 中 Dockerfile 的使用方法
Dockerfile 是什么?
-
Docker可以通过读取
Dockerfile
中的指令来自动构建镜像。 -
Dockerfile
是一个文本文档,其中包含用户可以在命令行上调用以组装镜像的所有指令。 -
可以在Dockerfile中使用的指令:
指令 | 中文描述 |
---|---|
ADD | 将本地或远程的文件/目录添加到镜像中,支持自动解压 .tar 文件和使用 URL 下载远程资源。通常推荐使用 COPY ,除非需要这些高级功能。 |
ARG | 定义构建阶段使用的变量,可在 docker build 命令中通过 --build-arg 传入,变量仅在构建时有效,不会保留在最终镜像中。 |
CMD | 指定容器默认执行的命令和参数,容器运行时若未指定命令,则使用该指令设置的命令。如果配置了多个CMD ,则只有最后一个生效。和ENTRYPOINT 共同使用时,作为传递给ENTRYPOINT 的参数。可被 docker run 提供的命令覆盖。 |
COPY | 将构建上下文中的文件或目录复制到镜像中。相比 ADD 更简单、安全,推荐优先使用。 |
ENTRYPOINT | 指定容器启动时的主命令,不容易被 docker run 中的命令覆盖。可与 CMD 配合使用,用于提供默认参数。 |
ENV | 设置环境变量,变量将在构建和容器运行时均可使用。例如:配置应用参数或系统路径等。 |
EXPOSE | 声明容器运行时将开放的端口,仅用于文档说明或与容器编排工具配合,不会自动进行端口映射。 |
FROM | 指定基础镜像,是 Dockerfile 的起点。也可以用于多阶段构建,通过多次使用 FROM 指令创建多个构建阶段。 |
HEALTHCHECK | 定义容器健康检查命令,用于定期检测容器内部服务的健康状态,可结合容器编排系统实现故障自动恢复。 |
LABEL | 为镜像添加键值对形式的元数据,例如版本、维护者、用途说明等,方便镜像管理与自动化处理。 |
MAINTAINER | (已弃用)用于指定镜像维护者信息,推荐改用 LABEL 来设置作者信息。 |
ONBUILD | 定义一个触发指令,当当前镜像作为基础镜像被其他 Dockerfile 使用时自动执行。常用于基础镜像的预设行为。 |
RUN | 执行一条命令并提交结果作为新镜像层,常用于安装软件包、复制文件、设置权限等构建操作。 |
SHELL | 更改 Dockerfile 中后续 RUN 、CMD 、ENTRYPOINT 等指令的默认 shell(如使用 sh 或 powershell )。 |
STOPSIGNAL | 设置容器终止时发送的系统信号(如 SIGTERM ),用于优雅关闭应用。 |
USER | 设置执行后续命令时所使用的用户和用户组,增强容器的安全性,避免使用 root 权限。 |
VOLUME | 定义容器内的挂载点,用于持久化数据或与宿主机/其他容器共享数据。运行容器时可指定挂载路径。 |
WORKDIR | 设置工作目录,相当于执行 cd ,用于简化后续命令中的路径。若目录不存在则自动创建。 |
-
构建阶段指令:FROM, ARG, ENV, COPY, ADD, RUN, WORKDIR, LABEL, USER, SHELL, ONBUILD
-
启动配置指令:CMD, ENTRYPOINT, HEALTHCHECK, EXPOSE, VOLUME, STOPSIGNAL
Dockerfile 指令介绍
FROM
-
FROM 指令用于指定基础镜像(base image),是每一个 Dockerfile 中必须的第一条指令。所有后续指令都是基于这个基础镜像构建的。
-
语法
1 | FROM <image>[:<tag>] [AS <stage-name>] |
-
示例
1 | # 使用最新版本的镜像(默认标签是 latest) |
WORKDIR
-
WORKDIR 指定了工作目录,即后续所有指令(如 RUN、CMD、ENTRYPOINT、COPY、ADD 等)所运行的当前路径(working directory)。
-
如果目录不存在,Docker 会自动创建它。
-
每个 WORKDIR 都会创建一层镜像(layer),所以不要重复设置无意义的路径。
-
语法
1 | WORKDIR <path> |
-
示例
1 | # 设置绝对路径 |
ARG
-
ARG 用于在 构建镜像时(build-time)传入参数。这些参数只在 构建阶段有效,不会出现在最终镜像中,也不会在容器运行时被保留。
-
语法
1 | ARG <name>[=<default_value>] |
-
示例
1 | # 定义一个参数,在构建镜像时必须传入参数,--build-arg APP_ENV=development |
ENV
-
ENV 指令用于在镜像构建过程中定义环境变量(Environment Variables)。这些变量可以在之后的构建步骤(比如 RUN、CMD 等)中使用,也会在容器运行时生效。
-
语法
1 | # 两种语法 |
-
示例
1 | # 定义一个环境变量 |
-
注意:ENV 指令定义的环境变量在构建阶段和运行阶段都会生效,但运行阶段会覆盖构建阶段定义的变量。
LABEL
-
LABEL 用于为镜像添加元数据标签,以
key=value
的形式存在。这些标签可以是作者信息、版本描述、用途说明、构建时间等。 -
旧的
MAINTAINER
指令现在已被废弃,推荐使用LABEL
来代替。 -
每个 LABEL 都会创建一层镜像(layer),推荐一次设置多个。
-
语法
1 | LABEL <key>=<value> [<key>=<value>...] |
-
示例
1 | # 添加一个标签 |
USER
-
USER 指令用于指定后续指令(如 RUN、CMD、ENTRYPOINT、COPY 等)以哪个用户身份来执行。
-
默认情况下,Docker 容器中的命令以 root 用户运行,这虽然灵活但不安全。使用 USER 可以让我们切换到普通用户,从而提升容器的安全性,防止潜在的权限滥用。
-
语法
1 | USER <user>[:<group>] |
-
示例
1 | # 设置用户 |
-
如果基础镜像中没有你想要的用户,需要在 Dockerfile 中手动创建
1 | # 创建用户和组 |
ADD
-
ADD 用于将本地文件或目录、远程文件(URL) 或 压缩包 复制到镜像中的指定位置。
-
它的功能类似于 COPY,但比 COPY 多几个功能(解压、拉取远程文件等)。
-
语法
1 | ADD <src>... <dest> |
-
示例
1 | # 从本地文件复制 |
-
最佳实践是优先使用 COPY,只有在需要 ADD 的额外功能时才使用它。
COPY
-
COPY 指令用于将主机上的文件或目录复制到镜像的文件系统中。它是构建镜像过程中最常用的数据引入方式之一。
-
与 ADD 类似,但功能更简单、明确、安全
-
推荐优先使用 COPY,除非你确实需要 ADD 提供的自动解压或远程下载功能。
-
语法
1 | COPY <src>... <dest> |
-
示例
1 | # 复制单个文件 |
RUN
-
RUN 指令用于在镜像构建阶段执行命令,结果会被打包进镜像层中。
-
它可以用于安装依赖、编译代码、运行命令等。
-
每一条 RUN 指令会创建一层镜像(layer),合并多个命令成一条 RUN,可以减少镜像层数(例如使用 && 串联)。
-
语法
1 | # 第一种格式:实际运行的是:/bin/sh -c "<命令字符串>" |
-
示例
1 | # 命令字符串 |
CMD
-
CMD 用于指定容器启动时默认执行的命令及其参数。
-
如果用户在运行容器时没有手动指定其他命令,Docker 就会使用 CMD 提供的内容。
-
它可以定义多个,但只有最后一个会被使用。
-
语法
1 | # Shell 形式(字符串) |
-
示例
1 | # 简单 shell 命令 |
-
用户可以覆盖 CMD:
1 | docker run <myapp> npm run test |
ENTRYPOINT
-
ENTRYPOINT 定义容器启动时执行的主命令,相比 CMD,它不容易被覆盖,更适合制作“专用型”容器(如 nginx、python 脚本等)。
-
你可以把 ENTRYPOINT 理解为容器的“主程序”,而 CMD 是为它提供的默认“命令行参数”。
-
语法
1 | # Shell 形式(字符串) |
-
示例
1 | # 简单 shell 命令 |
EXPOSE
-
EXPOSE 用于声明容器将会监听的端口,让使用该镜像的人知道应该对外开放哪些端口。
-
⚠️ 注意:EXPOSE 并不会真的开放端口,只是“声明”这个容器监听了这些端口。
-
要让端口真正暴露出来,还需要在运行容器时加上
-p
或--publish
参数。 -
语法
1 | EXPOSE <port> [<port>/<protocol>...] |
-
示例
1 | EXPOSE 8080 |
VOLUME
-
VOLUME 指令用于声明一个或多个容器中的挂载点(mount point),用于持久化数据或与宿主机/其他容器共享数据。
-
语法:
1 | VOLUME ["/path/in/container", ...] |
-
示例
1 | # 声明一个挂载点 |
-
当容器运行时,可以将镜像中声明的挂载点映射到宿主机上,从而实现持久化数据。
1 | docker run -v /host/path:/app/public myimage |
-
如果你没有手动绑定挂载,Docker 会自动创建一个匿名卷,卷的内容默认保存在宿主机的
/var/lib/docker/volumes
下。
HEALTHCHECK
-
HEALTHCHECK 用来定义容器运行时的健康检查命令,定期检测容器内服务的状态,帮助编排工具(Docker Swarm、Kubernetes 等)判断容器是否健康。
-
如果健康检查失败,Docker 会将容器标记为 unhealthy,便于自动重启或替换。
-
语法
1 | HEALTHCHECK <options> CMD <command> |
-
可选参数(OPTIONS)
参数 | 说明 | 默认值 |
---|---|---|
--interval=DURATION |
两次健康检查之间的时间间隔 | 30s |
--timeout=DURATION |
单次检测命令的超时时间 | 30s |
--start-period=DURATION |
容器启动后,开始健康检查前的等待时间 | 0s |
--retries=N |
连续失败几次后判定容器不健康 | 3 |
-
示例
1 | # 使用 curl 检测 Web 服务是否响应 |
-
运行容器后,可以用命令查看健康状态
1 | # 如果镜像中有健康检查,可以查看容器状态(STATUS) |
SHELL
-
SHELL 指令用来自定义后续 RUN、CMD 和 ENTRYPOINT 指令所使用的默认 shell 程序和参数。
-
默认情况下:
- 在 Linux 镜像中,Docker 使用 /bin/sh -c
- 在 Windows 镜像中,使用 cmd /S /C
-
使用 SHELL,你可以替换为其他 shell,如 Bash、PowerShell、zsh 等。
-
语法
1 | SHELL ["executable", "param1", "param2", ...] |
-
示例
1 | # 切换到 bash |
STOPSIGNAL
-
STOPSIGNAL 指定当容器收到
docker stop
命令时,发送给容器主进程的信号类型。 -
默认情况下,Docker 会向容器的主进程发送
SIGTERM
信号,让它有机会优雅地退出(在超时时未退出则发SIGKILL
强制终止)。 -
默认情况,大多数程序(如 nginx),不需要设置(默认 SIGTERM)
-
但有些程序可能需要使用不同的信号,比如 SIGINT、SIGHUP,这时你可以通过 STOPSIGNAL 来修改。
-
语法
1 | STOPSIGNAL <signal> |
-
示例
1 | # 这是默认行为,不写也一样。 |
ONBUILD
-
ONBUILD 用于定义延迟执行的构建指令,即这些命令不会在当前 Dockerfile 构建时执行,而是在 以当前镜像为基础的子镜像中构建时触发执行。
-
它的典型用途是:构建一个“通用基础镜像”,让使用者在自己的 Dockerfile 中 FROM 它时自动继承一些操作(比如 COPY、RUN 等)。
-
ONBUILD 是一种设计模式,方便基础镜像作者预先定义“未来子镜像构建时一定要执行的步骤”,而不是在基础镜像中“硬编码”那些步骤。
-
语法
1 | ONBUILD <INSTRUCTION> |
-
示例
1 | # 基础镜像中使用 ONBUILD |
-
ONBUILD 是一种“构建钩子”机制
- ONBUILD 可以理解成“钩子”或“触发器”:
- 在基础镜像构建时不执行
- 但当某人以这个基础镜像为起点写自己的 Dockerfile,并构建时,这些 ONBUILD 里的指令自动插入执行
- 这样:
- 基础镜像只负责定义环境(node、npm版本、系统依赖等),保持轻量
- 下游项目可以不用写重复的代码复制和安装指令,自动继承基础镜像预定义的构建步骤
- 代码复制和依赖安装在下游镜像构建时执行,使用自己的上下文(也就是项目代码)
- ONBUILD 可以理解成“钩子”或“触发器”:
-
ONBUILD
总结
特性 | 说明 |
---|---|
⏱ 延迟执行 | 构建基础镜像时不会执行,在子镜像构建时触发 |
✅ 支持指令 | 例如 RUN , COPY , ADD , CMD , WORKDIR , ENV 等 |
❌ 不支持 | FROM , ONBUILD , HEALTHCHECK , SHELL , STOPSIGNAL |
👎 不推荐滥用 | 会隐藏构建行为,降低可维护性 |
✅ 推荐场景 | 团队共享模板、构建“标准开发镜像” |
Dockerfile 示例: Spring Boot 应用
-
目录结构
1 | my-springboot-app/ |
-
Dockerfile
1 | # 使用轻量级 Alpine 版本的 OpenJDK 17 官方镜像,适合部署 Spring Boot 应用 |
-
构建镜像
1 | # 构建镜像时用 --build-arg 指定构建参数,如果需要多个,就配置多个 --build-arg |
-
运行容器
1 | docker run -d --name my-springboot-app \ |