写在前面
这里是原文链接,本文学习Dockerfile中的指令。
指令表格
指令 | 描述 |
---|---|
ADD | 添加本地文件或远程文件到image |
ARG | 环境变量 |
CMD | 运行container时执行的命令 |
COPY | 复制文件或目录到image |
ENTRYPOINT | 运行container时执行的命令(优先级高) |
ENV | 环境变量(优先级高) |
EXPOSE | 暴露容器的端口 |
FROM | 指定基础image |
HEALTHCHECK | 检查容器 |
LABEL | 给image添加元数据 |
MAINTAINER | 指定image的作者 |
ONBUILD | 构建时指定的指令 |
RUN | 运行 |
SHELL | 更换默认SHELL |
STOPSIGNAL | 退出容器时指定的系统调用信号 |
USER | 设置user和group ID |
VOLUME | 创建或指定volume |
WORKDIR | 设置工作目录 |
使用说明
使用形式如下,注释用#
,INSTRUCTION
是指令名如ADD
,FROM
。arguments
是指令携带的参数。
# Comment
INSTRUCTION arguments
指令是不分大小写的,如FROM
, from
都是合法的,但使用全大写的容易区分指令和参数。docker是逐条运行Dockerfile
中的指令的。Dockerfile
需要从FROM
作为第一条指令。
指令开头前的空格会默认省略,如下两个例子的效果是相同的。
# this is a comment-line
RUN echo hello
RUN echo world
# this is a comment-line
RUN echo hello
RUN echo world
但是指令后面的参数中的空格并不会省略,如下面的例子
RUN echo "\
hello\
world"
Parser directives
Parser directives(解析器指令)是可选的,下称PD。PD是可选的,不会参与构建,PD的语法类似特殊的注释# directive=value.
下面操作将会导致PD失效:
-
PD使用换行符
# direc \ tive=value
-
声明多次
# directive=value1 # directive=value2 FROM ImageName
-
没有在首行
FROM ImageName # directive=value
-
在注释后面出现
# About my dockerfile # directive=value FROM ImageName
-
未知的指令将会当作注释
# unknowndirective=value # syntax=value
下面是PD支持的指令,分别是syntax
和escape
syntax
这个指令的作用是规范编写Dockerfile,类似于xml的语法约束。语法如下:
# syntax=[remote image reference]
使用例子
# syntax=docker/dockerfile:1
# syntax=docker.io/docker/dockerfile:1
# syntax=example.com/user/repo:tag@sha256:abcdef...
语法约束有官方和自定义两种,下面说明官方的方式。
官网约束文件在Docker Hub下的docker/dockerfile
仓库,有 stable(稳定) 和 labs(实验) 两种。
stable
stable 有以下三种使用方式。
docker/dockerfile:1
持续使用1.x.x
的最新版本docker/dockerfile:1.2
持续使用1.2.x
的最新版本,不会使用如1.3.0
版本docker/dockerfile:1.2.1
指定版本,不会更新
labs
labs与stable使用方式相同,不过要加labs
后缀
docker/dockerfile:labs
docker/dockerfile:1-labs
docker/dockerfile:1.2-labs
docker/dockerfile:1.2.1-labs
escape
这个指令是替换默认的换行符,默认的换行符是\
。使用方法如下
# escape=`
环境变量替换
使用ENV
指令声明的语句,如ENV FOO=/bar
,使用类似给/bar
起别名’FOO’,在别的指令中使用的方法是${FOO}
。下面是一些使用方式,其中第3,4,5和6例子需要在声明# syntax=docker/dockerfile-upstream:master
才可使用
-
如果
variable
存在,variable
为结果,否则word
为结果${variable:-word}
-
如果
variable
存在,word
为结果,否则以空字符串为结果${variable:+word}
-
从前缀中删除匹配长度最短的字符串,如下面例子删除了
foob
str=foobarbaz echo ${str#f*b} # arbaz
-
从前缀中删除匹配长度最长的字符串,如下面例子删除了
foobarb
str=foobarbaz echo ${str##f*b} # az
-
从后缀中删除匹配长度最短的字符串,如下面例子删除了
baz
string=foobarbaz echo ${string%b*} # foobar
-
从后缀中删除匹配长度最长的字符串,如下面例子删除了
brzbaz
string=foobarbaz echo ${string%%b*} # foo
当需要显示字符原来的意思时,使用\
实现。如下例子:
FROM busybox
ENV FOO=/bar
WORKDIR ${FOO} # WORKDIR /bar
ADD . $FOO # ADD . /bar
COPY \$FOO /quux # COPY $FOO /quux
环境变量在以下指令中生效:
- ADD
- COPY
- ENV
- EXPOSE
- FROM.
- LABEL
- STOPSIGNAL
- USER
- VOLUME
- WORKDIR
- ONBUILD
事实上,在RUN
,CMD
,ENTRYPOINT
中同样可以使用环境变量,只不过是在command shell使用,而不是builder使用。
变量可以多次声明,后声明的会替换前面声明的。如下面例子中,def
为hello
,ghi
为bye
ENV abc=hello
ENV abc=bye def=$abc
ENV ghi=$abc
执行命令的两种形式
RUN
,CMD
,ENTRYPOINT
指令都有两种形式。分别是exec
形式和shell
形式。
INSTRUCTION ["executable","param1","param2"] (exec form)
INSTRUCTION command param1 param2 (shell form)
Exec form
因为exec形式
是json数组形式,所以每个元素都必须用双引号括住,而不是单引号。这种形式最好用在ENTRYPOINT
指令上,如果用在CMD上,设置的默认参数会在运行时被改变,更多信息在这里
ENTRYPOINT ["/bin/bash", "-c", "echo", "hello"]
变量替换
exec
形式并不会进行变量替换,如RUN [ "echo", "$HOME" ]
并不会替换$HOME
。若需要变量替换,可用以下形式RUN [ "sh", "-c", "echo $HOME" ]
,这时候是shell在做变量替换而不是builder
Shell form
shell形式总会使用新的command shell,而exec形式不会。使用’'可以将一行的命令分开写成多行。
RUN source $HOME/.bashrc && \
echo $HOME
替换默认的shell
使用SHELL
命令可以替换掉默认shell,例如:
SHELL ["/bin/bash", "-c"]
RUN echo hello
FROM
FORM用于指定基础image。FORM可以声明多次,每次声明构建一个image或者作为构建步骤的依赖。
有以下三种使用形式,中括号里都是可选的:
FROM [--platform=<platform>] <image> [AS <name>]
FROM [--platform=<platform>] <image>[:<tag>] [AS <name>]
FROM [--platform=<platform>] <image>[@<digest>] [AS <name>]
--platform
是可选的,用于指定image的目标平台,如linux/amd64, linux/arm64, or windows/amd64。AS <name>
是给镜像起别名,后面可以用这个别名代表镜像。tag
和digest
也是可选的,tag指定image的tag版本,digest指定image的版本。
ARG
ARG
的效果也是替换字符串,不过是用在指定image的版本上。同时有一点需要注意,ARG
替换字符串的效果只能生效在FROM
语句使用之后,因为ARG
不参与构建。如果想在使用FROM
也能发生替换,则需要再次声明,如下所示。
ARG VERSION=latest
FROM busybox:$VERSION
# 再次声明
ARG VERSION
RUN echo $VERSION > image_version
RUN
运行命令的指令,有shell形式和exec形式,上面说过这两种的区别,这里不再赘述。运行的命令都会有缓存,如国想完全重新构建,需要加上--no-cache
,如docker build --no-cache
。RUN
使用例子如下:
RUN apt-get update
RUN apt-get install -y curl
RUN --mount
这个参数可以执行特定的操作,如挂载主机的文件或目录,运行访问安全性高的文件等,共有4种类型,如下所示:
语法形式:--mount=[type=<TYPE>][,option=<value>[,option=<value>]...]
类型 | 描述 |
---|---|
bind(默认) | 挂载主机的目录(只读) |
cache | 此挂载类型允许build container缓存编译器和包管理器的目录。 |
secret | 允许访问安全文件如private keys,无须将它们放进image种 |
ssh | 允许构建容器通过SSH代理访问SSH密钥,支持口令。 |
RUN --mount=type=bind
允许绑定文件或目录到build container。默认是只读的。
option | description |
---|---|
target | 挂载路径 |
source | 在from里的源路径。默认是from的root |
from | 构建阶段或image的名称。默认为build context。 |
rw,readwrite | 挂载后允许写。写入的数据将被丢弃。 |
RUN --mount=type=cache
此挂载类型允许build container缓存编译器和包管理器的目录。
缓存目录的内容在构建器调用之间持续存在,而不会使指令缓存失效。缓存挂载应该只用于更好的性能。您的构建应该处理缓存目录的任何内容,因为另一个构建可能会覆盖文件,或者如果需要更多的存储空间,GC可能会清除它。
option | description |
---|---|
id | 可选ID,用于识别不同的缓存。默认为target的值。 |
target | 挂载路径 |
ro,readonly | 设置只读 |
sharing | sharing,private,locked之一。默认为shared。shared cache挂载可以由多个写入器并发使用。设置成private,如果有多个写入器,每个写入创建一个新的挂载。Locked暂停后面的写入器,直到第一个写入器释放挂载。 |
from | 构建阶段,用作缓存挂载的基础。默认为空目录。 |
source | from的子路径。默认为from的根目录。 |
mode | 新缓存目录的权限,使用八进制。默认0755 |
uid | 新缓存目录的user id。默认0 |
gid | 新缓存目录的group id。默认0 |
例子1,缓存go包
# syntax=docker/dockerfile:1
FROM golang
RUN --mount=type=cache,target=/root/.cache/go-build \
go build ...
例子2,缓存apt包
# syntax=docker/dockerfile:1
FROM ubuntu
RUN rm -f /etc/apt/apt.conf.d/docker-clean; echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' > /etc/apt/apt.conf.d/keep-cache
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
Apt需要独占访问其数据,因此缓存使用shared =locked选项,这将确保使用相同缓存挂载的多个并行构建将相互等待,而不会同时访问相同的缓存文件。在这种情况下,如果您希望每个构建都创建另一个缓存目录,也可以使用sharing=private。
RUN --mount=type=tmpfs
这种挂载类型允许在构建容器中挂载tmpfs。
option | description |
---|---|
target | 挂在路径 |
size | 指定文件系统大小的上限 |
RUN --mount=type=secret
这种挂载类型允许构建容器访问安全文件,如私钥,而无需将它们放入映像中。
option | description |
---|---|
id | secret的ID。默认为target path的basename |
target | 挂载路径。默认 /run/secrets/ + id |
required | 如果设置为true,则当密钥不可用时,指令将出错。默认为false。 |
mode | secret file的file mode为八进制。默认0400 |
uid | 文件的用户ID。默认值0 |
gid | 文件的组ID。默认值0 |
例子 access to S3
# syntax=docker/dockerfile:1
FROM python:3
RUN pip install awscli
RUN --mount=type=secret,id=aws,target=/root/.aws/credentials \
aws s3 cp s3://... ...
RUN --mount=type=ssh
这种挂载类型允许构建容器通过SSH代理访问SSH密钥,并支持密码短语。
option | description |
---|---|
id | ssh agent socket或者key的id。默认是"default" |
target | ssh agent socket路径。默认是/run/buildkit/ssh_agent.${N}. |
required | 如果设置为true,则当密钥不可用时,指令将出错。默认为false。 |
mode | socket的file mode,八进制。默认是0600 |
uid | socket的用户ID。默认值0 |
gid | 文件的组ID。默认值0 |
使用例子:访问Gitlab
# syntax=docker/dockerfile:1
FROM alpine
RUN apk add --no-cache openssh-client
RUN mkdir -p -m 0700 ~/.ssh && ssh-keyscan gitlab.com >> ~/.ssh/known_hosts
RUN --mount=type=ssh \
ssh -q -T git@gitlab.com 2>&1 | tee /hello
\ # "Welcome to GitLab, @GITLAB_USERNAME_ASSOCIATED_WITH_SSHKEY" should be printed here
\ # with the type of build progress is defined as `plain`.
eval $(ssh-agent)
ssh-add ~/.ssh/id_rsa
(Input your passphrase here)
docker buildx build --ssh default=$SSH_AUTH_SOCK .
RUN --network
network允许控制命令在哪个网络环境中运行。
语法:--network=<TYPE>
Network类型
type | description |
---|---|
default(默认) | 运行在默认网络 |
none | 没有网络 |
host | 运行在主机的网络环境 |
RUN --security
在stable语法中还不可以用,需要使用docker/dockerfile:1-labs
RUN --security=insecure
构建器运行不用沙箱运行命令处于不安全模式,这允许运行需要提升权限的流(例如containerd),其作用与docker run --privileged
相同
例子 检查权限
# syntax=docker/dockerfile:1-labs
FROM ubuntu
RUN --security=insecure cat /proc/self/status | grep CapEff
RUN --security=sandbox
默认的沙箱模式可以通过——security=sandbox激活,但这是无效的。
CMD
当运行container才会执行的命令,RUN是构建时执行的命令。一个Dockerfile中只能有一个CMD指令。如果您列出了多个CMD命令,则只有最后一个生效。CMD的目的是为执行容器提供默认值。这些默认值可以包含可执行文件,也可以省略可执行文件,在这种情况下,您还必须指定ENTRYPOINT指令。如果您希望您的容器每次都运行相同的可执行文件,那么您应该考虑将ENTRYPOINT与CMD结合使用。看到入口点。如果用户为docker run指定了参数,那么它们将覆盖CMD中指定的默认值,但仍然使用默认的ENTRYPOINT。如果CMD用于为ENTRYPOINT指令提供默认参数,则CMD和ENTRYPOINT指令都应在exec表单中指定。
LABEL
作用时给image添加元数据。需要注意只能用双引号。使用例子如下
LABEL "com.example.vendor"="ACME Incorporated"
LABEL com.example.label-with-value="foo"
LABEL version="1.0"
LABEL description="This text illustrates \
that label-values can span multiple lines."
为了查看image的label,使用如下命令
docker image inspect --format='{{json .Config.Labels}}' myimage
效果
{
"com.example.vendor": "ACME Incorporated",
"com.example.label-with-value": "foo",
"version": "1.0",
"description": "This text illustrates that label-values can span multiple lines.",
"multi.label1": "value1",
"multi.label2": "value2",
"other": "value3"
}
EXPOSE
作用是指定容器开放的端口和开放协议(TCP,UDP),默认是TCP。使用形式如下
EXPOSE <port> [<port>/<protocol>...]
例子
EXPOSE 80/tcp
EXPOSE 80/udp
若想启动时定义端口,就在docker run命令加上-p
参数,如下
docker run -p 80:80/tcp -p 80:80/udp ...
ENV
作用是设置环境变量。使用形式:
ENV <key>=<value> ...
使用例子
ENV MY_NAME="John Doe"
ENV MY_DOG=Rex\ The\ Dog
ENV MY_CAT=fluffy
一个ENV也可以写多个
ENV MY_NAME="John Doe" MY_DOG=Rex\ The\ Dog \
MY_CAT=fluffy
这些环境变量会保留到容器运行时,可以使用docker inspect
查看环境变量,使用docker run --env <key>=<value>
改变环境变量。
ADD
作用是复制新的文件,目录或者远程URL的文件到image的文件系统的dest
目录。以下是使用形式:
ADD [--chown=<user>:<group>] [--chmod=<perms>] [--checksum=<checksum>] <src>... <dest>
ADD [--chown=<user>:<group>] [--chmod=<perms>] ["<src>",... "<dest>"]
--chown
和--chmod
只能用于构建linux containers
,并不适用于windows containers
。
下面是使用例子:
- 添加所有以
hom
开头的文件ADD hom* /mydir/
?
替换任意字符。如"home.txt"ADD hom?.txt /mydir/
dest
是一个绝对路径,或者WORKDIR
的相对路径。如下例子就是将test.txt
放到<WORKDIR>/relativeDir/
ADD test.txt relativeDir/
- 将
test.txt
放到绝对路径/absoluteDir/
下ADD test.txt /absoluteDir/
所有新的文件和目录的UID
和GID
都是0。可以使用--chown
改变。当container root filesystem不包含/etc.passwd
或/etc/group
文件,这个ADD
操作就会失败。使用数字id不需要查找,也不依赖于容器根文件系统的内容。
ADD --chown=55:mygroup files* /somedir/
ADD --chown=bin files* /somedir/
ADD --chown=1 files* /somedir/
ADD --chown=10:11 files* /somedir/
ADD --chown=myuser:mygroup --chmod=655 files* /somedir/
src
操作需要注意以下要求:
src
路径必须在build context中,不能使用COPY ../something /something
,因为../something
访问父目录超出了build context的范围 。- 如果
src
是个目录,这个目录下所有的目录都会被复制 - 如果src是个
URL
并且dest
以/
结尾,则文件会放在dest/filename
下。如ADD http://example.com/foobar /
将会创建文件/foobar
- 如果
src
是个本地文本,且是个压缩文件,以gzip,bzip2,xz
结尾,则会解压该文件,而远程压缩文件不会这样做。 - 如果
<src>
是其他类型的文件,它会连同它的元数据一起单独复制,在这种情况下,如果<dest>
以一个斜杠/结尾,它会被认为是一个目录,并且<src>
的内容会被写到<dest>/base(<src>)
中。 - 如果直接或使用通配符指定了多个资源,则必须是一个目录,并且必须以斜杠/结尾。
- 如果
<dest>
没有以斜杠结尾,它将被认为是一个常规文件,并且<src>
的内容将被写在<dest>
。 - 如果
<dest>
不存在,则创建它,以及其路径中所有缺失的目录。
http使用--checksum
检查文件是否被修改过
ADD --checksum=sha256:24454f830cdb571e2c4ad15481119c43b3cafd48dd869a9b2945d1036d1dc68d https://mirrors.edge.kernel.org/pub/linux/kernel/Historic/linux-0.01.tar.gz /
添加git仓库
# syntax=docker/dockerfile:1
FROM alpine
ADD --keep-git-dir=true https://github.com/moby/buildkit.git#v0.10.1 /buildkit
添加私有git仓库
# syntax=docker/dockerfile:1
FROM alpine
ADD git@git.example.com:foo/bar.git /bar
构建时的命令使用ssh
docker build --ssh default
#
buildctl build --frontend=dockerfile.v0 --local context=. --local dockerfile=. --ssh default
COPY
作用是复制主机中的文件到容器的中
使用形式:
COPY [--chown=<user>:<group>] [--chmod=<perms>] <src>... <dest>
COPY [--chown=<user>:<group>] [--chmod=<perms>] ["<src>",... "<dest>"]
使用例子:
COPY hom* /mydir/
COPY hom?.txt /mydir/
COPY test.txt relativeDir/
COPY test.txt /absoluteDir/
COPY --chown=55:mygroup files* /somedir/
COPY --chown=bin files* /somedir/
COPY --chown=1 files* /somedir/
COPY --chown=10:11 files* /somedir/
COPY --chown=myuser:mygroup --chmod=644 files* /somedir/
COPY --link
作用是加速image构建,这里有篇文章说得不错,可以看看。
ENTRYPOINT
- Dockeer file应至少有一个CMD或ENTRYPOINT
- 当将容器用作可执行文件时,应该定义ENTRYPOINT。
- CMD应该用作定义ENTRYPOINT命令的默认参数或在容器中执行临时命令的一种方式。
- 当使用可选参数运行容器时,CMD将被覆盖。
以下是CMD和ENTRYPOINT的交互方式
VOLUME
VOLUME指令创建具有指定名称的挂载点,并将其标记为保存来自本机主机或其他容器的外部挂载卷。
使用形式:
VOLUME ["/data"]
使用指令需要以下要求
- 使用基于windows的容器时,volume必须是一个不存在的或者空文件夹,且不能位于C盘。
- 如果任何构建步骤在声明卷之后更改了卷中的数据,那么这些更改将被丢弃。
- 该列表被解析为JSON数组。必须用双引号(")而不是单引号(')括起元素
- 主机目录(挂载点)本质上是依赖于主机的。这是为了保持映像的可移植性,因为不能保证给定的主机目录在所有主机上都可用。由于这个原因,您不能从Dockerfile中挂载主机目录。VOLUME指令不支持指定host-dir参数。在创建或运行容器时,必须指定挂载点。
USER
设置当前stage的用户和组,执行CMD时会用到。使用方式:
USER <user>[:<group>]
USER <UID>[:<GID>]
FROM microsoft/windowsservercore
# Create Windows user in the container
RUN net user /add patrick
# Set it for subsequent commands
USER patrick
WORKDIR
设置RUN,CMD,ENTRYPOINT,COPY,ADD的工作目录。合格指令可以设置多次,若提供相对目录,那么是相对当前WORKDIR的目录,如下:
WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd
# 当前目录是/a/b/c
ARG
作用与ENV
相同,不过ENV
会覆盖同名的ARG
。使用方式:
FROM busybox
USER ${username:-some_user}
ARG username
USER $username
# ...
构建命令docker build --build-arg username=what_user .
第2行的USER计算结果为some_user,因为username变量是在随后的第3行定义的。第4行USER的计算结果为what_user,因为定义了username参数,并且在命令行上传递了what_user值。在ARG指令定义变量之前,对变量的任何使用都会导致一个空字符串。
ARG指令在构建阶段结束时超出了定义它的范围。要在多个阶段中使用一个参数,每个阶段必须包含ARG指令。
FROM busybox
ARG SETTINGS
RUN ./run/setup $SETTINGS
FROM busybox
ARG SETTINGS
RUN ./run/other $SETTINGS
ENV
会覆盖AGR
的值,如下:
FROM ubuntu
ARG CONT_IMG_VER
ENV CONT_IMG_VER=v1.0.0
RUN echo $CONT_IMG_VER
构建命令:docker build --build-arg CONT_IMG_VER=v2.0.1 .
执行构建输出的是v1.0.0
预定义ARG
Docker有一组预定义的ARG变量,你可以在Dockerfile中使用这些变量,而不需要相应的ARG指令。如下:
- HTTP_PROXY
- http_proxy
- HTTPS_PROXY
- https_proxy
- FTP_PROXY
- ftp_proxy
- NO_PROXY
- no_proxy
- ALL_PROXY
- all_proxy
使用方式:
docker build --build-arg HTTPS_PROXY=https://my-proxy.example.com .
ONBUILD
ONBUILD指令将一个触发指令添加到映像中,以便稍后在映像用作另一个构建的基础时执行。触发器将在下游构建的上下文中执行,就像它被插入到下游Dockerfile中的FROM指令之后一样。
任何构建指令都可以注册为触发器。
如果您正在构建一个映像,该映像将用作构建其他映像的基础,例如应用程序构建环境或可以使用特定于用户的配置进行定制的守护进程,那么这将非常有用。
例如,如果您的映像是可重用的Python应用程序构建器,则需要将应用程序源代码添加到特定目录中,并且可能需要在此之后调用构建脚本。您现在不能仅仅调用ADD和RUN,因为您还没有访问应用程序源代码的权限,而且对于每个应用程序构建都是不同的。您可以简单地为应用程序开发人员提供一个样板Dockerfile,以便将其复制粘贴到他们的应用程序中,但这样做效率低下、容易出错且难以更新,因为它与应用程序特定的代码混合在一起。
解决方案是使用ONBUILD注册高级指令,以便在下一个构建阶段运行。
下面是它的工作原理:
-
当它遇到ONBUILD指令时,构建器向正在构建的映像的元数据添加一个触发器。该指令不会影响当前的构建。
-
在构建结束时,所有触发器的列表存储在映像清单中,在OnBuild键下。可以使用docker inspect命令进行检查。
-
稍后,可以使用FROM指令将映像用作新构建的基础。作为处理FROM指令的一部分,下游构建器查找ONBUILD触发器,并按照注册时的顺序执行它们。如果任何一个触发器失败,FROM指令将被终止,从而导致构建失败。如果所有触发器都成功,则FROM指令完成,并像往常一样继续构建。
-
触发器在执行后将从最终映像中清除。换句话说,它们不会被“孙辈”建筑所继承。
例如:
ONBUILD ADD . /app/src
ONBUILD RUN /usr/local/bin/python-build --dir /app/src
STOPSIGNAL
STOPSIGNAL signal
STOPSIGNAL指令设置将被发送到容器以退出的系统调用信号。这个信号可以是SIG< name >格式的信号名,例如SIGKILL,或者是一个与内核的系统调用表中的位置匹配的无符号数,例如9。如果没有定义,默认值是SIGTERM。
镜像的默认停止信号可以覆盖每个容器,在docker运行和docker创建时使用——stop-signal标志。
HEALTHCHECK
HEALTHCHECK指令告诉Docker如何测试容器以检查它是否仍在工作。这可以检测web服务器陷入无限循环,无法处理新连接等情况,即使服务器进程仍在运行。
有两种形式:
- HEALTHCHECK [OPTIONS] CMD command (check container health by running a command inside the container)
- HEALTHCHECK NONE (disable any healthcheck inherited from the base image)
OPTIONS有以下选项:
- –interval=DURATION (default: 30s)
- –timeout=DURATION (default: 30s)
- –start-period=DURATION (default: 0s)
- –start-interval=DURATION (default: 5s)
- –retries=N (default: 3)
运行状况检查将在容器启动后的一段时间内首次运行,然后在每次前一次检查完成后的一段时间内再次运行。
如果检查的单次运行时间超过timeout秒,则认为检查失败。
需要重试连续失败的健康检查,容器才会被认为不健康。
Start period为需要启动时间的容器提供初始化时间。在此期间的探测失败将不计入最大重试次数。但是,如果在启动期间运行状况检查成功
,则认为容器已启动,并且所有连续失败都将计入最大重试次数。
“start-interval”是指开始周期内两次健康检查的时间间隔。此选项需要Docker引擎25.0或更高版本。
一个Dockerfile中只能有一条HEALTHCHECK指令。如果您列出了多个HEALTHCHECK,那么只有最后一个HEALTHCHECK会生效。
CMD关键字后的命令可以是shell命令(如HEALTHCHECK CMD /bin/check-running)或exec数组
该命令的退出状态表示容器的健康状态。可能的值是:
- 0:成功,容器时健康的
- 1:非健康的,容器不是正确的运行
- 2:保留的,不要使用这个值
例如,每隔五分钟左右检查一次网络服务器是否能够在三秒钟内为网站主页提供服务:
HEALTHCHECK --interval=5m --timeout=3s \
CMD curl -f http://localhost/ || exit 1
为了方便Debug,命令在标准输出或标准错误上写入的任何输出文本(UTF-8编码)都将存储在健康状态中,并且可以使用docker inspect进行查询。这样的输出应该保持较短(目前只存储前4096字节)。
SHELL
SHELL ["executable", "parameters"]
SHELL指令允许覆盖用于SHELL形式命令的默认SHELL。Linux系统默认shell为[“/bin/sh”, “-c”], Windows系统默认shell为[“cmd”, “/S”, “/C”]。SHELL指令必须在Dockerfile中以JSON形式编写。
SHELL指令在Windows上特别有用,因为Windows上有两种常用且完全不同的本机SHELL: cmd和powershell,以及包括sh在内的备用SHELL。
SHELL指令可以出现多次。每个SHELL指令覆盖之前的所有SHELL指令,并影响所有后续指令。例如:
FROM microsoft/windowsservercore
# Executed as cmd /S /C echo default
RUN echo default
# Executed as cmd /S /C powershell -command Write-Host default
RUN powershell -command Write-Host default
# Executed as powershell -command Write-Host hello
SHELL ["powershell", "-command"]
RUN Write-Host hello
# Executed as cmd /S /C echo hello
SHELL ["cmd", "/S", "/C"]
RUN echo hello