跳转至

Dockerfile 指令详解

FROM

Docker hub 中 99% 镜像都是从 FROM scratch 为基础构建的

必需指令:一个有效的 Dockerfile 必须以 FROM 指令开头(唯一例外是 ARG 可以出现在它之前)。

多次使用:一个 Dockerfile 中可以出现多个 FROM 指令,用于创建多个镜像或实现多阶段构建。

语法格式

FROM 指令有三种基本格式:

  1. FROM [--platform=<platform>] <image> [AS <name>]
  2. FROM [--platform=<platform>] <image>[:<tag>] [AS <name>] (最常见)
  3. FROM [--platform=<platform>] <image>[@<digest>] [AS <name>]

参数解释:

  • <image>: (必需) 指定基础镜像的名称。可以是官方镜像(如 ubuntu)、私有仓库镜像(如 my-registry.com/app)或本地镜像。
  • [:<tag>]: (可选) 指定镜像的标签。如果省略,构建器默认使用 :latest 标签。
    • 示例: FROM alpine:3.18
  • [@<digest>]: (可选) 使用镜像的摘要(Digest)来指定一个绝对固定的版本,这比标签更精确。
    • 示例: FROM alpine@sha256:...(一长串哈希值)
  • [AS <name>]: (可选) 为当前构建阶段命名。这个名字可以在后续的多阶段构建中被其他指令(如 COPY --from=<name>)引用。
    • 示例: FROM node:18 AS builder-stage

选项(Flag)

[--platform=<platform>]: (可选) 当引用的基础镜像是多平台镜像(如官方 python 镜像同时支持 linux/amd64 和 linux/arm64)时,使用此选项来强制指定构建平台。

  • 示例: FROM --platform=linux/arm64 alpine
  • 常与全局构建参数一起使用,例如 --platform=$BUILDPLATFORM--platform=$TARGETPLATFORM

与 ARG 指令的交互

这是 FROM 指令的一个复杂但强大的特性。

  1. 在 FROM 之前声明的 ARG:这些 ARG 位于==构建阶段之外==,只能在 FROM 指令本身中使用

    Docker
    1
    2
    3
    4
    5
    6
    # 这个 ARG 在所有构建阶段之外
    ARG CODE_VERSION=latest
    # 可以在 FROM 中使用它
    FROM base:${CODE_VERSION}
    # 但在这里不能再使用 CODE_VERSION
    RUN ... 
    
  2. 在阶段内使用外部 ARG 的默认值:如果需要在阶段内部使用之前声明的 ARG 的默认值,需要在阶段内重新声明一个同名的 ARG(可以不带值)

    Docker
    1
    2
    3
    4
    5
    ARG VERSION=latest
    FROM busybox:$VERSION
    # 重新声明 VERSION,它将继承外部 ARG 的默认值('latest')
    ARG VERSION 
    RUN echo $VERSION > image_version # 现在可以使用了
    

RUN

两种形式

1. Shell 形式(最常用)

RUN <command> ...

  • 命令在 shell(默认 /bin/sh -c)中执行。
  • 支持使用 \ 换行和 Heredoc 语法来编写多行命令。

    Docker
    1
    2
    3
    4
    5
    6
    7
    RUN apt-get update && \
        apt-get install -y curl
    
    RUN <<EOF
    apt-get update
    apt-get install -y curl
    EOF
    

2. Exec 形式

RUN ["executable", "param1", "param2"]

  • 直接执行命令,不调用 shell。
  • 注意:不会自动进行环境变量替换。需要变量替换时,应显式调用 shell:RUN ["sh", "-c", "echo $HOME"]

主要选项 (--mount)

  1. type=cache - 缓存目录(用于加速构建)

用途:为包管理器(apt, npm, go mod)等创建缓存目录,内容在多次构建间持久化。

Docker
1
2
3
4
5
6
7
8
9
# 缓存 Go 的编译缓存
FROM golang
RUN --mount=type=cache,target=/root/.cache/go-build \
  go build ...

# 缓存 apt 包
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
  --mount=type=cache,target=/var/lib/apt,sharing=locked \
  apt update && apt-get --no-install-recommends install -y gcc
  • id:可选缓存标识符,用于识别不同的缓存,默认为 target 路径。
  • target, dst, destination:挂载路径
  • ro,readonly:设置为只读
  • sharing:默认共享模式。可以被多个写入器使用。 locked暂停第二写入器,确保并发构建顺序访问缓存; private 为每个构建创建独立缓存。
  • from:要用作缓存挂载基础的构建阶段、上下文或映像名称。默认为空目录
  • source:from挂载的子路径,默认为根目录
  • mode:新缓存目录的文件模式为八进制,默认0755
  • uid:缓存目录用户ID,默认0
  • gid:缓存目录组ID,默认0
  1. type=bind - 绑定挂载(从其他阶段或上下文复制文件

用途:将文件或目录从构建上下文或其他构建阶段挂载到当前指令中

Docker
1
2
3
# 从名为 'builder' 的阶段挂载文件
RUN --mount=type=bind,from=builder,source=/output/app,target=/usr/local/bin/app \
    ./app --version
  • target, dst, destination:挂载路径
  • source:from中的源路径。默认为from的根目录
  • from:源代码根的构建阶段、上下文或映像名称。默认为构建上下文
  • rw,readwrite:允许在挂载上写。写入的数据将被丢弃
  1. type=secret - 挂载敏感信息

用途:在构建时安全地访问密码、密钥等,避免将其固化到最终镜像中

Docker
1
2
3
# 将主机上的密钥文件挂载到容器内使用
RUN --mount=type=secret,id=my_key,target=/root/.ssh/id_rsa \
    git clone git@github.com:user/repo.git

构建时需传递密钥:docker build --secret id=my_key,src=./id_rsa

  1. type=ssh - 挂载 SSH 代理

用途:在构建过程中使用 SSH 密钥(例如克隆私有仓库)

Docker
RUN --mount=type=ssh \
    git clone git@github.com:user/private-repo.git

构建时需传递 SSH agent:docker build --ssh default=$SSH_AUTH_SOCK .

建议

  • 绝大多数情况下,使用 Shell 形式 和 --mount=type=cache 就足以应对大多数场景。
  • 使用 secretssh 来安全地处理敏感信息。
  • 使用 --network=none 来创建可复现的、隔离的构建环境

CMD

作用:指定从镜像启动容器时默认执行的命令。在构建阶段 (docker build) 不执行。

语法形式

Exec 形式(推荐)

CMD ["executable", "param1", "param2"]

Exec 形式(作为 ENTRYPOINT 的参数)

CMD ["param1", "param2"] # 必须与 ENTRYPOINT 搭配使用

Shell 形式

CMD command param1 param2

关键特性

  • 唯一性:一个 Dockerfile 中只能有一个生效的 CMD 指令,最后一个会覆盖之前的。
  • 默认值:CMD 提供的是容器的默认命令和参数。
  • 覆盖性:用户在执行 docker run [IMAGE] [NEW_COMMAND] 时,[NEW_COMMAND] 会完全覆盖 Dockerfile 中的 CMD。
  • 与 ENTRYPOINT 的关系:
    • ENTRYPOINT 定义固定的可执行文件。
    • CMD 定义传递给 ENTRYPOINT 的默认参数。
    • 两者结合时,应都使用 Exec 形式。
    • docker run 传入的参数会覆盖 CMD 的内容,但不会覆盖 ENTRYPOINT

示例

Docker
1
2
3
4
5
6
7
8
9
# 用法1:直接运行命令(Exec形式)
CMD ["nginx", "-g", "daemon off;"]

# 用法2:作为ENTRYPOINT的参数
ENTRYPOINT ["/app/start.sh"]
CMD ["--mode=production"]

# 用户运行 `docker run myapp --mode=development` 时,实际执行的是:
# /app/start.sh --mode=development

LABEL

作用:为镜像添加键值对形式的元数据(如作者、版本、描述等)

语法

LABEL <key>=<value> [<key>=<value> ...]

关键特性

  • 多标签:一个镜像可以有多个标签。可以在一个指令中写多个,也可以用多个指令。
  • 换行:值中包含空格或需要换行时,使用引号和反斜杠 \
  • 继承与覆盖:基础镜像的标签会被继承。如果标签键重复,后设置的值会覆盖先前的值。
  • 查看:使用 docker image inspect --format='{{json .Config.Labels}}' [IMAGE] 查看所有标签。

示例

Docker
# 单行多标签(推荐)
LABEL version="1.0" description="My custom app" maintainer="admin@example.com"

# 多行写法(更清晰)
LABEL org.opencontainers.image.version="1.0" \
      org.opencontainers.image.description="My custom app" \
      org.opencontainers.image.authors="admin@example.com"

# 注意:MAINTAINER 指令已废弃,应使用 LABEL 代替:
LABEL org.opencontainers.image.authors="your-email@example.com"

EXPOSE

作用:声明容器在运行时将监听哪些网络端口和协议(TCP/UDP)。它本身并不发布端口

EXPOSE <port>[/<protocol>] [<port>[/<protocol>]...] # 协议默认为 tcp

关键特性

  • 文档功能:它主要作为镜像作者和使用者之间的文档说明,告知哪些端口需要被映射。
  • 自动映射:使用 docker run -P 时,Docker 会自动随机映射所有 EXPOSE 声明的端口到主机的高端口。
  • 手动映射:使用 docker run -p <host-port>:<container-port>/<protocol> 可以手动指定映射。
  • 协议:可以指定 tcp 或 udp。如需同时监听,必须声明两次。

示例

Docker
1
2
3
4
5
6
7
8
9
# 声明容器监听80端口(TCP)
EXPOSE 80

# 声明容器使用UDP协议监听53端口(DNS)
EXPOSE 53/udp

# 声明容器同时用TCP和UDP监听80端口
EXPOSE 80/tcp
EXPOSE 80/udp

ENV

作用:设置环境变量,该变量在构建阶段和最终的容器运行时都有效。

语法(推荐)

ENV <key>=<value> [<key>=<value> ...]

关键特性

  • 持久化:使用 ENV 设置的环境变量会被持久化到最终的镜像中,容器运行时也能看到。
  • 作用范围:在构建阶段,它对其后所有指令都有效。在运行时,所有从该镜像启动的容器内部都存在这些变量。
  • 值中的空格:如果值包含空格,需要用引号括起或用反斜杠 \ 转义。
  • 查看与覆盖:使用 docker inspect 查看;使用 docker run --env <key>=<value> 在运行时覆盖。
  • 潜在问题:滥用 ENV 可能导致镜像包含不必要的或敏感的环境变量(如 DEBIAN_FRONTEND=noninteractive)。

替代方案

如果环境变量仅在构建阶段需要,不应保留到最终镜像中,应使用:

单条命令前设置:

RUN DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y ...

使用 ARG 指令(不会持久化到镜像):

Docker
ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y ...

示例

Docker
1
2
3
4
5
6
7
8
# 设置多个环境变量(推荐方式)
ENV APP_VERSION=1.0 \
    NODE_ENV=production \
    APP_HOME=/usr/src/app

# 值中包含空格
ENV NAME="John Doe" \
    GREETING=Hello\ World

ADD

基本语法

Docker
ADD [OPTIONS] <src> ... <dest>
ADD [OPTIONS] ["<src>", ... "<dest>"]  # 用于包含空格的路径

可用选项

  • --keep-git-dir (v1.1+) - 保留 Git 目录
  • --checksum (v1.6+) - 验证远程资源校验码
  • --chown - 设置文件所有权
  • --chmod (v1.2+) - 设置文件权限
  • --link (v1.4+) - 创建硬链接
  • --exclude (v1.7-labs) - 排除特定文件

功能说明

ADD 指令从 <src> 复制文件/目录到镜像文件系统的 <dest> 路径,支持:

  • 构建上下文中的本地文件
  • 远程 URL
  • Git 仓库

源类型处理

  • 本地文件/目录:内容复制到目标位置
  • 本地 tar 归档:自动解压到目标位置
  • 远程 URL:下载文件到目标位置
  • Git 仓库:克隆到目标位置

示例

Docker
# 添加多个文件
ADD file1.txt file2.txt /usr/src/things/

# 从 URL 添加文件
ADD https://example.com/archive.zip /usr/src/things/

# 从 Git 仓库添加
ADD git@github.com:user/repo.git /usr/src/things/

# 使用通配符
ADD *.png /dest/
ADD index.?s /dest/

# 转义特殊字符
ADD arr[[]0].txt /dest/

# 保留 Git 目录
ADD --keep-git-dir=true https://github.com/user/repo.git /repo

# 验证校验码
ADD --checksum=sha256:<hash> https://example.com/file.tar.gz /

目标路径规则

  • / 开头:绝对路径
  • 不以 / 开头:相对于工作目录
  • 尾随斜线影响行为:
    • ADD file /dir :将file放在/目录命名为dir
    • ADD file /dir/ :结果则是/dir/file

注意事项

  • 通过 stdin 传递 Dockerfile 时无构建上下文
  • URL 文件不支持身份验证
  • Git 仓库需可从构建上下文访问
  • 使用 SSH 密钥需通过 --ssh 标志传递

COPY

基本语法

Docker
COPY [OPTIONS] <src> ... <dest>
COPY [OPTIONS] ["<src>", ... "<dest>"]  # 用于包含空格的路径

可用选项

  • --from - 从构建阶段、命名上下文或镜像复制

    Docker
    1
    2
    3
    4
    5
    6
    7
    8
    9
    FROM golang AS build
    WORKDIR /app
    RUN go build -o /myapp .
    
    # 从build阶段复制文件
    COPY --from=build /myapp /usr/bin/
    
    # 直接从镜像复制
    COPY --from=nginx:latest /etc/nginx/nginx.conf /nginx.conf
    
  • --chown - 设置文件所有权

  • --chmod (v1.2+) - 设置文件权限

    Docker
    # 设置用户和组
    COPY --chown=55:mygroup files* /somedir/
    COPY --chown=bin files* /somedir/
    COPY --chown=1 files* /somedir/
    
    # 设置权限(仅支持八进制)
    COPY --chown=myuser:mygroup --chmod=644 files* /somedir/
    
    # 使用构建参数
    ARG MODE=440
    COPY --chmod=$MODE . .
    
  • --link (v1.4+) - 创建硬链接优化层缓存

    COPY --link /foo /bar

    优势

    • 层独立性:文件保持在自己的独立层
    • 缓存重用:前层变更不影响COPY层
    • 性能提升:支持直接推送到注册表而不拉取基础层
  • --parents (v1.7-labs) - 保留源文件父目录结构

    Docker
    1
    2
    3
    4
    5
    6
    # syntax=docker/dockerfile:1-labs
    COPY --parents ./x/a.txt ./y/a.txt /parents/
    
    # 结果:
    # /parents/x/a.txt
    # /parents/y/a.txt
    
  • --exclude (v1.7-labs) - 排除特定文件

    Docker
    1
    2
    3
    4
    5
    6
    # syntax=docker/dockerfile:1-labs
    # 复制所有以"hom"开头的文件,排除.txt文件
    COPY --exclude=*.txt hom* /mydir/
    
    # 排除多种类型
    COPY --exclude=*.txt --exclude=*.md hom* /mydir/
    

    满足 Go 的 filepath.Match 规则

功能说明

COPY 指令从 <src> 复制文件/目录到镜像文件系统的 <dest> 路径,支持:

  • 构建上下文中的本地文件
  • 构建阶段(多阶段构建)
  • 命名上下文
  • 其他镜像

示例

Docker
1
2
3
4
5
6
7
8
9
# 复制多个文件
COPY file1.txt file2.txt /usr/src/things/

# 使用通配符
COPY *.png /dest/
COPY index.?s /dest/

# 转义特殊字符
COPY arr[[]0].txt /dest/

目标路径规则

  • / 开头:绝对路径

  • 不以 / 开头:相对于工作目录

  • 尾随斜线影响行为:

    • ADD file /dir :将file放在/目录命名为dir
    • ADD file /dir/ :结果则是/dir/file

注意事项

  • 无构建上下文时:通过stdin传递Dockerfile时,只能使用 --from 选项
  • 权限默认值:从Git仓库复制的文件权限为644,可执行文件为755
  • Linux专用:--chown--chmod 仅适用于Linux容器
  • 冲突处理:目录复制会合并内容,文件冲突时以源文件为准

最佳实践

  • 明确指定目标路径的尾随斜线以避免混淆
  • 在多阶段构建中使用 --from 减少最终镜像大小
  • 考虑使用 --link 优化构建缓存和层管理
  • 使用 --chown--chmod 确保正确的文件权限
  • 不需要ADD的特殊功能(自动解压、远程URL下载)时优先使用COPY

ENTRYPOINT

ENTRYPOINT 允许将容器配置为可执行文件,定义容器启动时运行的主命令

基本语法形式

1. Exec 形式(推荐)

ENTRYPOINT ["executable", "param1", "param2"]

2. Shell 形式

ENTRYPOINT command param1 param2

关键特性

命令行参数处理

  • Exec 形式:docker run <image> 的参数会追加到 ENTRYPOINT 参数后面
  • Shell 形式:会忽略 CMD 和 docker run 的命令行参数

信号处理

  • Exec 形式: executable 作为 PID 1,能正确接收 Unix 信号(如 SIGTERM)
  • Shell 形式: executable 作为 /bin/sh -c 的子命令,无法接收信号

覆盖规则

  • 只有最后一个 ENTRYPOINT 指令生效
  • 可以使用 docker run --entrypoint 标志覆盖 ENTRYPOINT

Exec 形式示例

Docker
1
2
3
4
5
6
FROM ubuntu
ENTRYPOINT ["top", "-b"]
CMD ["-c"]

# 运行方式
docker run -it --rm --name test top -H

Shell 形式正确用法

Docker
FROM ubuntu
ENTRYPOINT exec top -b  # 使用exec确保信号传递

ENTRYPOINT 与 CMD 交互规则

ENTRYPOINT CMD 最终执行的命令
未设置 未设置 错误,不允许
未设置 CMD ["exec_cmd", "p1_cmd"] exec_cmd p1_cmd
未设置 CMD exec_cmd p1_cmd /bin/sh -c exec_cmd p1_cmd
ENTRYPOINT exec_entry p1_entry 未设置 /bin/sh -c exec_entry p1_entry
ENTRYPOINT exec_entry p1_entry CMD ["exec_cmd", "p1_cmd"] /bin/sh -c exec_entry p1_entry
ENTRYPOINT exec_entry p1_entry CMD exec_cmd p1_cmd /bin/sh -c exec_entry p1_entry
ENTRYPOINT ["exec_entry", "p1_entry"] 未设置 exec_entry p1_entry
ENTRYPOINT ["exec_entry", "p1_entry"] CMD ["exec_cmd", "p1_cmd"] exec_entry p1_entry exec_cmd p1_cmd
ENTRYPOINT ["exec_entry", "p1_entry"] CMD exec_cmd p1_cmd exec_entry p1_entry /bin/sh -c exec_cmd p1_cmd

重要注意事项

  • 至少指定一个:Dockerfile 应至少指定 CMD 或 ENTRYPOINT 中的一个
  • 可执行容器:ENTRYPOINT 应在将容器用作可执行文件时定义
  • 默认参数:CMD 应为 ENTRYPOINT 命令定义默认参数
  • 基础镜像覆盖:设置 ENTRYPOINT 会重置来自基础镜像的 CMD

最佳实践

  • 优先使用 Exec 形式:确保正确的信号处理
  • 使用 exec 命令:在 shell 脚本中确保进程替换和信号传递
  • 明确分工:
    • ENTRYPOINT:定义主命令
    • CMD:定义默认参数
  • 测试信号处理:确保 docker stop 能正常停止容器

VOLUME

基本语法

Docker
VOLUME ["/data"]  # JSON数组形式
VOLUME /var/log /var/db  # 多参数形式

重要注意事项

  1. Windows容器:卷目标必须是:

    • 不存在或空的目录
    • 非C:驱动器
  2. BuildKit差异:

    • 传统构建器:VOLUME声明后的数据变更会被丢弃
    • BuildKit:保留数据变更
  3. JSON格式:必须使用双引号

  4. 主机目录:不能在Dockerfile中指定主机目录,必须在运行时指定

USER

基本语法

Docker
USER <user>[:<group>]    # 用户名形式
USER UID[:GID]          # ID形式

功能说明

  • 设置当前阶段后续指令的默认用户和组
  • 用于RUN指令和运行时(ENTRYPOINTCMD

注意事项

  • 如果用户没有主组,将使用root组运行
  • Windows必须先创建非内置账户

WORKDIR

基本语法

WORKDIR /path/to/workdir

功能说明

  • 设置后续RUNCMDENTRYPOINTCOPYADD指令的工作目录
  • 如果目录不存在会自动创建
  • 支持多次使用,路径会相对累积

示例

Docker
1
2
3
4
5
6
7
8
9
WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd  # 输出: /a/b/c

# 使用环境变量
ENV DIRPATH=/path
WORKDIR $DIRPATH/$DIRNAME
RUN pwd  # 输出: /path/$DIRNAME

最佳实践

  • 始终明确设置WORKDIR,避免在未知目录中操作

ARG

基本语法

ARG <name>[=<default value>]

功能说明

  • 定义构建时用户可传递的变量
  • 通过 docker build --build-arg <varname>=<value> 传递

示例

Docker
1
2
3
4
FROM busybox
ARG user1=someuser      # 带默认值
ARG buildno=1
# 使用$user1, $buildno

作用域规则

  • 从声明行开始生效
  • 在多个阶段使用时,每个阶段都需要重新声明
  • 环境变量(ENV)会覆盖同名的ARG变量

预定义的ARG变量

代理相关(自动排除在history外):

Bash
HTTP_PROXY, http_proxy, HTTPS_PROXY, https_proxy
FTP_PROXY, ftp_proxy, NO_PROXY, no_proxy

平台相关ARG变量(BuildKit)

Bash
1
2
3
4
5
# 全局作用域,需要在阶段内重新声明才能使用
ARG TARGETPLATFORM    # 目标平台,如linux/amd64
ARG TARGETOS          # 目标操作系统
ARG TARGETARCH        # 目标架构
ARG BUILDPLATFORM     # 构建平台

BuildKit内置构建参数

Bash
1
2
3
BUILDKIT_CONTEXT_KEEP_GIT_DIR=1  # 保留.git目录
BUILDKIT_SYNTAX                 # 设置前端镜像
SOURCE_DATE_EPOCH              # 设置时间戳用于可重现构建

缓存影响

  • ARG变量不会持久化到镜像中
  • 改变ARG值会导致缓存失效(在第一次使用时)
  • 预定义ARG变量免缓存,除非在Dockerfile中声明

安全警告

不要使用ARG传递敏感信息(密码、API令牌等),因为它们会出现在:

  • docker history 输出中
  • 公开仓库的溯源证明中

使用 RUN --mount=type=secret 安全地处理秘密信息。

ONBUILD

功能说明

ONBUILD 指令添加一个触发器指令,在当前镜像作为其他构建的基础时执行。触发器在下游构建的上下文中执行,就像插入在下游 Dockerfile 的 FROM 指令之后

使用场景

  • 构建作为其他镜像基础的可重用镜像
  • 应用构建环境或可定制的守护进程

示例

Docker
1
2
3
4
5
6
7
# 基础构建镜像
ONBUILD ADD . /app/src
ONBUILD RUN /usr/local/bin/python-build --dir /app/src

# 支持从其他阶段复制
ONBUILD COPY --from=build /usr/bin/app /app
ONBUILD RUN --mount=from=config,target=/opt/appconfig

限制

  • 不允许链式 ONBUILD ONBUILD
  • 不能触发 FROMMAINTAINER 指令
  • 触发器执行后会被清除,不会继承到"孙子"构建

STOPSIGNAL

语法

STOPSIGNAL signal

功能说明

设置发送给容器以退出的系统调用信号,可以是信号名(如 SIGKILL )或数字(如 9 )。默认为 SIGTERM

示例

Bash
STOPSIGNAL SIGTERM    # 信号名形式
STOPSIGNAL 9          # 数字形式

运行时覆盖

docker run --stop-signal SIGKILL myimage

HEALTHCHECK

语法形式

Docker
HEALTHCHECK [OPTIONS] CMD command  # 设置健康检查
HEALTHCHECK NONE                   # 禁用基础镜像的健康检查

选项参数

Bash
1
2
3
4
5
6
#选项            默认值    说明
--interval        30s    检查间隔时间
--timeout         30s    检查超时时间
--start-period    0s     启动初始化时间
--start-interval  5s     启动期间的检查间隔
--retries         3      连续失败次数判定为不健康

退出状态码

  • 0: 成功 - 容器健康
  • 1: 失败 - 容器不健康
  • 2: 保留 - 不要使用

示例

Docker
1
2
3
4
5
6
# Web服务器健康检查
HEALTHCHECK --interval=5m --timeout=3s \
  CMD curl -f http://localhost/ || exit 1

# 使用exec数组形式
HEALTHCHECK CMD ["/bin/check-running", "--timeout", "10"]

调试信息

健康检查命令的输出(stdout/stderr)会存储在健康状态中,可通过 docker inspect 查询(最多存储4096字节)

SHELL

语法

SHELL ["executable", "parameters"]

默认值

  • Linux: ["/bin/sh", "-c"]
  • Windows: ["cmd", "/S", "/C"]

示例

Docker
FROM microsoft/windowsservercore

# 默认使用cmd
RUN echo default

# 切换到PowerShell
SHELL ["powershell", "-command"]
RUN Write-Host hello

# 切换回cmd
SHELL ["cmd", "/S", "/C"]
RUN echo hello

影响范围

影响后续使用shell形式的指令:

  • RUN
  • CMD
  • ENTRYPOINT

Here-Documents

多行文本输入

基本语法

Docker
1
2
3
RUN <<EOF [command]
多行内容
EOF

示例

Docker
# 多行脚本执行
RUN <<EOT bash
set -ex
apt-get update
apt-get install -y vim
EOT

# 默认shell执行
RUN <<EOT
mkdir -p foo/bar
EOT

# 指定解释器
RUN <<EOT
#!/usr/bin/env python
print("hello world")
EOT

# 多个here-doc
RUN <<FILE1 cat > file1 && <<FILE2 cat > file2
I am first
FILE1
I am second
FILE2

COPY指令中使用

Docker
# 创建内联文件
COPY <<EOF greeting.txt
hello world
EOF

# 变量扩展,创建一个hello.sh脚本
{
# syntax=docker/dockerfile:1
FROM alpine
ARG FOO=bar
COPY <<-EOT /script.sh
  echo "hello ${FOO}"
EOT
ENTRYPOINT ash /script.sh
}
# 打包并运行,展示变量值
$ docker build -t heredoc .
$ docker run heredoc
hello bar


# 禁止变量扩展(引号包围分隔符)
{
# syntax=docker/dockerfile:1
FROM alpine
ARG FOO=bar
COPY <<-"EOT" /script.sh
  echo "hello ${FOO}"
EOT
ENTRYPOINT ash /script.sh
}
# 打包并穿参数运行,上边ARG FOO=bar就是多余的
$ docker build -t heredoc .
$ docker run -e FOO=world heredoc
hello world

变量扩展规则

  • 默认:构建时扩展变量
  • 使用引号分隔符:运行时扩展变量
  • 支持制表符去除(使用 <<-