跳转至

Dockerfile 参考文档

Dockerfile 是用于构建 Docker 镜像的文本文件,包含了一系列构建镜像所需的指令。

Format

Docker
1
2
3
# Comment
INSTRUCTION arguments
指令  参数

解析器指令(Parser Directives)

解析器指令是可选的,会影响 Dockerfile 中后续行的处理方式。解析器指令不向构建中添加层,也不显示为构建步骤。

解析器指令被写成一种特殊类型的注释,格式为 # directive=value。一个指令只能使用一次。

是 Dockerfile 中的一种特殊注释,用于在 Docker 开始解析 Dockerfile 中的指令之前,指示 Docker 引擎如何解释这个 Dockerfile 文件。

可以把它们理解为给 Docker 构建器的前置设置选项

关键特性

1.格式特殊

它们看起来像注释,但语法有严格要求。

  • 必须是 # directive=value 的形式
  • 必须放在 Dockerfile 的最顶端,在任何其他注释或指令之前
  • # 号和指令名之间不能有空格,但指令名和值之间的 = 号前后可以有空格
  • 字母必须小写

2.位置敏感

一旦 Dockerfile 中出现了第一条非解析指令的真正指令(如 FROM, RUN 等)或普通注释,之后的所有内容都不能再被识别为解析器指令,它们会被当作普通注释处理。

3.作用域

解析器指令只对当前这个 Dockerfile 有效。

支持的解析器指令

Dockerfile 支持以下解析器指令:

  1. syntax(语法指令)
  2. escape(转义符指令)
  3. check(检查指令)

syntax(语法指令)

  • 用途: 指定用于构建此 Dockerfile 的 Dockerfile 前端解析器。
  • : 是一个指向包含解析器的 Docker 镜像的地址。

为什么需要它?

  1. 使用实验性功能:允许在官方支持新功能之前,使用这些新功能。例如,当 RUN --mount 还是实验性功能时,就需要通过 syntax 指令来启用。
  2. 使用第三方增强功能:社区或第三方可能提供了功能更丰富或不同的构建器。

示例

Docker
# syntax=docker/dockerfile:1
FROM alpine:latest
RUN echo "使用稳定的官方解析器"

# syntax=docker/dockerfile:1-labs
FROM alpine:latest
# 使用 labs 版本以支持 --mount 等实验性功能
RUN --mount=type=cache,target=/var/cache/apt apt-get update

# syntax=my-company/our-custom-dockerfile-parser:1.0
FROM alpine:latest
# 可能支持一些自定义的指令或语法

escape(转义符指令)

  • 用途: 指定 Dockerfile 中使用的转义字符。这在 Windows 系统中特别有用,因为 Windows 路径中大量使用 \
  • 默认值: \
  • 可选值: `(反引号)

为什么需要它?

  • 在默认转义符是 \ 的系统中,如果你需要在 RUN 命令中使用 \ 作为路径分隔符(如 Windows),就会产生冲突。这时可以将其设置为反引号 `

示例

Docker
1
2
3
4
5
6
7
# escape=`
FROM microsoft/windowsservercore
# 在 Windows 的 Dockerfile 中,使用反引号作为转义符
RUN echo Hello > C:\path\to\file.txt
COPY testfile.txt C:\path\to\copy\file.txt

# 如果不设置 escape=`,上面的 C:\path... 中的每一个 \ 都需要写成 \\ 来转义,非常麻烦。

check(检查指令)(since Dockerfile v1.8.0)

  • 用途: 主要作用是控制 Docker 构建器(Builder)在解析 Dockerfile 时是否进行严格的语法和选项检查。
  • 默认行为: 运行所有检查,但如果检查失败(发现问题),仅将其视为警告(Warning),而不会导致构建失败。
  • 语法: # check=value
  • 选项: 指令主要通过两个选项来配置:skiperror

  • 跳过检查: skip 选项

用于禁用特定的检查项或全部检查。禁用特定检查,要跳过多个检查,用逗号分隔它们

Docker
# check=skip=all      # 禁用全部检查

# check=skip=<检查项名称>    # 指定跳过的检查选项

# 示例
# check=skip=JSONArgsRecommended,StageNameCasing

# 检查项含义
# JSONArgsRecommended  # JSON 数组格式的 CMD 指令
# StageNameCasing      # 阶段名称的大小写

# 检查选项参考:https://docs.docker.com/reference/build-checks/
  • 将警告视为错误: error 选项

用于改变构建失败的条件。默认情况下,检查失败只是警告,构建仍会成功。

Docker
1
2
3
4
5
6
# check=error=true    # 开启严格模式(失败则构建失败)

# 效果:只要任何未跳过的检查失败,整个构建过程就会失败并返回非零退出码。

# 最佳实践:如果使用 error=true,最好同时使用 syntax 指令将 Dockerfile 语法固定到一个特定版本。
# 否则,未来语法版本新增的检查项可能会让你的构建突然失败。
  • 组合使用选项: 同时使用 skiperror 选项,用分号 ; 分隔它们。
Docker
1
2
3
4
5
6
# check=skip=<某些检查>;error=true

# 示例
# check=skip=StageNameCasing;error=true

# 含义:跳过 "阶段名称大小写" 的检查,但对于所有其他未跳过的检查,一旦失败就立即使构建失败。

Environment Replacement(环境变量替换)

1. 基本语法

在 Dockerfile 中,使用 ENV 指令声明的环境变量可以通过以下方式引用。

  • $variable_name
  • ${variable_name} (推荐,尤其适用于变量名与其他字符连接的情况,如 ${name}_bar)

2. 高级 Bash 风格修饰符

Dockerfile 支持一些类似 Bash 的变量替换语法:

默认值替换

Bash
1
2
3
4
5
6
7
8
9
# 假设 未设置abc, def=hello
${variable:-word}
# 如果 variable 已设置,则使用其值;否则使用 word
# ${abc:-world} → world

${variable:+word}
# 如果 variable 已设置,则使用 word;否则使用空字符串
# ${def:+world} → world
# ${abc:+world} → `` (空字符串)

模式匹配删除

Bash
# 假设 str=foobarbaz

${variable#pattern}
# 从开头删除最短匹配 pattern 的部分。 ${str#f*b} → arbaz

${variable##pattern}
# 从开头删除最长匹配 pattern 的部分。 ${str##f*b} → az

${variable%pattern}
# 从结尾删除最短匹配 pattern 的部分。 ${str%b*} → foobar

${variable%%pattern}
# 从结尾删除最长匹配 pattern 的部分。 ${str%%b*} → foo

模式替换

Bash
1
2
3
4
5
${variable/pattern/repl}
# 将第一个匹配 pattern 的部分替换为 repl。 ${str/ba/fo} → fooforbaz

${variable//pattern/repl}
# 将所有匹配 pattern 的部分替换为 repl。 ${str//ba/fo} → fooforfoz

注意:

  • pattern 是通配模式,? 匹配单个字符,* 匹配任意多个字符
  • 转义使用 \?\*
  • 这些功能需要在使用 # syntax=docker/dockerfile-upstream:master 等预览语法时才可用

3. 转义

在变量前加反斜杠 \ 可以将其视为普通字符,而不是变量。

Bash
1
2
3
4
5
6
7
FROM busybox
ENV FOO=/bar
WORKDIR ${FOO}   # WORKDIR /bar
ADD . $FOO       # ADD . /bar
COPY \$FOO /quux # COPY $FOO /quux

# 复制名为`$FOO`的文件,而不是`/bar`目录下的文件

4. 作用范围与时机

  • 一条指令内的变量值固定:一条指令中对同一变量的所有引用,都会使用该指令开始执行时的值。
  • 后续指令生效:只有在 ENV 指令之后的下一条指令开始,新设置或修改的环境变量值才会生效。
Docker
1
2
3
ENV abc=hello
ENV abc=bye def=$abc # def的值为第一条指令设置的'hello'
ENV ghi=$abc         # ghi 的值为上一条指令设置的 'bye'

5.支持变量替换的指令

以下指令由 Docker 构建器(Builder)处理变量替换:

ADD, COPY, ENV, EXPOSE, FROM, LABEL, STOPSIGNAL, USER, VOLUME, WORKDIR,以及 ONBUILD 与上述指令结合时。

特殊说明 RUN, CMD, ENTRYPOINT

这三个指令的变量替换不是由构建器处理,而是由命令shell(如 /bin/sh)处理的。

Shell and exec form

RUN, CMD, 和 ENTRYPOINT 指令都有两种写法

1.Exec 形式 (JSON 数组形式)

语法INSTRUCTION ["executable", "param1", "param2", ...]

优点

  • 避免 shell 的字符串处理,参数清晰明确。
  • 不会自动调用命令 shell。
  • 是设置 ENTRYPOINT 的首选方式。

重要特性

  • 不会自动进行变量替换! 因为不调用 shell。RUN ["echo", "$HOME"] 会直接输出字符串 $HOME,而不是家目录路径。
  • 必须使用双引号。
  • 需要转义反斜杠(尤其在 Windows 路径中)。
    • 错误: RUN ["c:\windows\system32\tasklist.exe"]
    • 正确: RUN ["c:\windows\system32\tasklist.exe"]

如何在 Exec 形式中使用变量替换?

需要显式地调用一个 shell:

Docker
RUN ["/bin/sh", "-c", "echo $HOME"] 
# 此时 $HOME 的替换由 /bin/sh 完成

2.Shell 形式

语法INSTRUCTION command param1 param2

优点

  • 写法简单直观,易于阅读。
  • 自动调用命令 shell(默认是 /bin/sh -c)。
  • 自动进行变量替换、通配符扩展等所有 shell 功能。
  • 可以使用反斜杠 \ 换行,方便书写长命令。
  • 支持 Heredoc 语法,非常适合嵌入多行脚本。
Docker
1
2
3
4
5
6
7
8
9
# Shell 形式示例
RUN source $HOME/.bashrc && \
    echo $HOME # 变量替换和换行都正常工作

# Heredoc 示例
RUN <<EOF
source $HOME/.bashrc && \
echo $HOME
EOF

3.选择哪种形式?

使用 Shell 形式当:

  • 需要 shell 功能(变量替换、管道、重定向等)。
  • 命令简单,追求可读性。

使用 Exec 形式当:

  • 你不需要 shell 功能,希望避免 shell 引起的意外行为。
  • 你需要为 ENTRYPOINT 指定确切的参数。
  • 你希望容器进程能够正确接收 Unix 信号(如 SIGTERM),因为 shell 形式会默认让 shell 成为 PID 1 的进程。

4.更改默认 Shell

可以使用 SHELL 指令改变后续所有 Shell 形式指令所使用的默认 shell。

Docker
1
2
3
SHELL ["/bin/bash", "-c"] 
# 后续的 RUN、CMD、ENTRYPOINT 的 shell 形式将使用 bash
RUN echo hello

Dockerfile 基本指令

指令列表

Dockerfile 支持如下指令:

指令 说明
FROM 指定基础镜像,用于后续的指令构建,centos,ubuntu
MAINTAINER 指定Dockerfile 的作者/维护者,姓名+邮箱。(已弃用,推荐使用 LABEL 指令)
LABEL 添加镜像的元数据,使用键值对的形式
RUN 构建时需要运行的命令,build 时运行
CMD 指定容器创建时的默认命令(可以被覆盖),run 时执行
ENTRYPOINT 设置容器创建时的主要命令(不可被覆盖)
EXPOSE 声明容器运行时监听的特定网络端口
ENV 构建时设置环境变量
ADD 将文件、目录或远程 URL 复制到镜像中,会解压缩文件
COPY 将文件或目录复制到镜像中
VOLUME 为容器创建挂载点或声明卷
WORKDIR 设置后续指令的工作目录
USER 指定后续指令的用户上下文
ARG 定义在构建过程中传递给构建器的变量,可以使用 "docker build" 命令设置
ONBUILD 当该镜像被用作另一个构建过程的基础时,添加触发器
STOPSIGNAL 设置发送给容器以退出的系统调用信号
HEALTHCHECK 定义周期性检查容器健康状态的命令
SHELL 覆盖Docker 中默认的 shell,用于 RUNCMDENTRYPOINT 指令

基本规则

  • 指令不区分大小写,但建议大写,以区分指令与参数
  • 执行从上到下顺序执行
  • # 开头的行表示注释,构建时不创建镜像层
  • 每个指令都会创建一个新的镜像层并提交

Dockerfile 例⼦

Docker
1
2
3
4
5
6
7
# 简单的 Dockerfile 示例
FROM ubuntu:20.04
MAINTAINER yourname@example.com
LABEL version="1.0" description="My Application"
RUN apt-get update && apt-get install -y nginx
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

参考资源