跳转至

Dockerfile指令清单

指令 描述
ADD 添加本地或远程文件和目录。
ARG 使用构建时变量。
CMD 指定默认命令。
COPY 复制文件和目录。
ENTRYPOINT 指定默认可执行文件。
ENV 设置环境变量。
EXPOSE 描述应用程序监听的端口。
FROM 从基础镜像创建新的构建阶段。
HEALTHCHECK 在启动时检查容器的健康状态。
LABEL 向镜像添加元数据。
MAINTAINER 指定镜像的作者。
ONBUILD 指定在构建中使用镜像时的指令。
RUN 执行构建命令。
SHELL 设置镜像的默认 shell。
STOPSIGNAL 指定退出容器的系统调用信号。
USER 设置用户和组 ID。
VOLUME 创建卷挂载。
WORKDIR 更改工作目录。

Dockerfile

Docker可以通过Dockerfile自动构建镜像,Dockerfile是一个包含多个指令的文档。如下

1
2
3
 FROM ubuntu:18.04    
 CMD python /app/app.py    

FROM

FROM命令用于初始化一个新的构建阶段,并为后续指令设置基础镜像:

1
2
3
 FROM [--platform=<platform>] <image> [AS <name>]    
 FROM [--platform=<platform>] <image>[:<tag>] [AS <name>]    
 FROM [--platform=<platform>] <image>[@<digest>] [AS <name>]    

FROM指令用于指定基础镜像,单个Dockerfile可以多次出现FROM,以使用之前的构建阶段作为另一个构建阶段的依赖项。

ARG是唯一可以位于FROM指令之前的指令,一般用于声明基础镜像的版本。

--platform选项可用在FROM多平台镜像的情况下指定平台。例如,linux/amd64、lunux/arm64、windows/amd64。

AS name表示为构建阶段命令,在后续FROMCOPY --from=name说明中可以使用这个名词,引用此阶段构建的映像。

tagdigest值是可选的。如果您省略其中任何一个,构建器默认使用latest标签。如果找不到指定tag,构建起将返回错误。

RUN

RUN指令将在当前镜像之上的新层中执行命令,并且提交结果。在docker build时运行。

 RUN /bin/bash -c 'source $HOME/.bashrc; \    
     echo $HOME'    

RUN有两种形式:

  • RUN :shell形式,命令在shell中运行,默认在Linux上使用/bin/sh -c,在Windows上使用cmd /S /C
    RUN /bin/bash -c 'source $HOME/.bashrc && echo $HOME'

  • RUN [“command”,”param1”,”param1”]:exec形式,不会触发shell,所以$HOME这样的环境变量无法使用,但它可以在没有bash的镜像中执行。
    RUN ["/bin/bash", "-c", "echo hello"]

RUN的一些高级语法 详细官方文档
–mount=[type=][,option=[,option=]…]

bind(默认) 绑定装载上下文目录(只读)。
cache 挂载一个临时目录来缓存编译器和包管理器的目录。
secret 允许生成容器访问私钥等安全文件,而无需将其烘焙到映像中。
ssh 允许生成容器通过 SSH 代理访问 SSH 密钥,并支持密码。

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    

RUN pip install awscli    
RUN --mount=type=secret,id=aws,target=/root/.aws/credentials \    
  aws s3 cp s3://... ...    

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    

说明:
- 可以使用反斜杠(\)将单个RUN命令延续到下一行。- RUN在下一次构建期间,指令缓存不会自动失效。可以使用--no-cache选项使指令缓存失效。如RUN apt-get update之类的构建缓存将在下一次构建期间被重用,此时构建中可能安装过时版本的工具,但我们可以使用–no-cache标志来使RUN命令的缓存失效,如docker build –no-cache。- Dockerfile的指令每执行一次就会给镜像新建一层只读层。过多无意义的层会造成镜像膨胀过大,可以使用& & 符号连接多个命令,这样执行RUN指令后之后创建一层镜像。
有些命令会使用管道(|),如:

 RUN wget -O - https://some.site | wc -l > /number    

Docker使用/bin/sh -c解释器,解释器只计算所有一个命令的退出状态码以确定命令是否执行成功,如上例,只要wc -l执行成功,即使wget命令失败,这个构建步骤也会生成一层新镜像。如果希望命令由于管道中任意阶段命令的错误而失败,需要预先设置set-o pipefail& &,如下:

 RUN set -o pipefail & &  wget -O - https://some.site | wc -l > /number    

注意,基于debian的镜像要使用exec形式支持-o pipefail:
RUN [“/bin/bash”, “-c”, “set -o pipefail & & wget -O - https://some.site | wc -l > /number”]

CMD

Dockerfile使用RUN指令完成docker build所有的环境安装与配置,通过CMD指令来指示docker run命令运行镜像时要执行的命令。Dockerfile只允许使用一次CMD命令。使用多个CMD会抵消之前所有的命令,只有最后一个命令生效。一般来说,这是整个Dockerfile脚本的最后一个命令。

 FROM ubuntu    
 CMD ["/usr/bin/wc","--help"]    

CMD有三种形式:
- CMD [“exec”,”param1”,”param2”]:使用exec执行,推荐方式。- CMD command param1 param2:在/bin/sh中执行,可以提供交互操作。- CMD [“param1”,”param2”]:提供给ENTRYPOINT的默认参数(极少这样使用)。

EXPOSE

EXPOSE指令通知容器在运行时监听某个端口,可以指定TCP或UDP,如果不指定协议,默认为TCP端口。但是为了安全,docker run命令如果没有带上相应的端口映射参数,Docker并不会将端口映射出去。

 EXPOSE 80/tcp    
 EXPOSE 80/udp    

指定映射端口方式:

docker run -P:将所有端口发布到主机接口,每个公开端口绑定到主机上的随机端口,端口范围在/proc/sys/net/ipv4/ip_local_port_range定义的临时端口范围内。

docker run -p :显式映射单个端口或端口范围。

LABEL

LABEL指令为镜像添加标签,当前镜像会继承父镜像的标签,如果与父标签重复,会覆盖之前的标签。

1
2
3
4
5
 LABEL multi.label1="value1" \    
       multi.label2="value2" \    
       other="value3"    
 LABEL multi.label1="value1" multi.label2="value2" other="value3"    

可以使用如下方式查看镜像标签:

 docker image inspect --format='' myimage    

查看结果实例:

1
2
3
4
5
6
7
8
9
 {    
   "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"    
 }    


ENV

ENV命令用来在执行docker run命令运行镜像时指定自动设置的环境变量。这个环境变量可以在后续任何RUN命令中使用,并在容器运行时保持。一般用于软件更便捷的运行,如:

 ENV PATH=/usr/local/nginx/bin:$PATH    
 CMD ["nginx"]    

设置的环境变量将持续存在,可以使用docker inspect来查看。这些环境变量可以通过docker run --env <key>=<value>命令的参数来修改。

ARG

ARG命令定义用户只在构建时使用的变量,效果和docker build --build-arg <varname>=<value>一样,这个参数只会在构建时存在,不会保留在镜像中。

 ARG <name>[=<default value>]    

ARG与ENV类似,不同的是ENV会在镜像构建结束后一直保存在容器中,而ARG会在镜像构建结束狗消失。一般运用在希望整个构建过程是无交互的,那么可以使用ARG命令(仅限Debian发行版)。

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

Docker 有一组预定义的 ARG 变量,您可以在 Dockerfile 中没有相应指令的情况下使用这些变量。
- HTTP_PROXY- http_proxy- HTTPS_PROXY- https_proxy- FTP_PROXY- ftp_proxy- NO_PROXY- no_proxy
要使用这些,请使用 –build-arg 标志在命令行上传递它们,例如:

 docker build --build-arg HTTPS_PROXY=https://my-proxy.example.com .    

ADD

ADD指令用于复制新文件、目录或远程文件 URL到容器路径中。可以指定多个资源,但如果它们是文件或目录,则它们的路径被解释为相对于构建上下文的源,也就是 WORKDIR。

ADD指令有两种形式:

 ADD [--chown=<user>:<group>] <src>... <dest>    
 ADD [--chown=<user>:<group>] ["<src>",... "<dest>"]    

每个都 可能包含通配符,匹配将使用 Go 的 filepath.Match 规则。 是一个绝对路径,或相对 WORKDIR 的相对路径。例如:

添加所有以“hom”开头的文件:

 ADD hom* /mydir/    

在下面的示例中,? 被替换为任何单个字符,例如“home.txt”。

 ADD hom?.txt /mydir/    

所有新创建的文件和目录的UID和GID都为0,除非使用--chown指定UID/GID以及权限。-chown特性仅在用于构建Linux容器。

1
2
3
4
 ADD --chown=55:mygroup files* /somedir/    
 ADD --chown=bin files* /somedir/    
 ADD --chown=1 files* /somedir/    
 ADD --chown=10:11 files* /somedir/    

如果是一个可识别压缩格式(identity、gzip、bzip2或xz)的本地tar存档,那么它将被解包为一个目录。远程URL中的资源不会解压缩。当一个目录被复制或解包时,它的行为与tar -x相同。

COPY

COPY 指令和 ADD 指令的唯一区别在于:是否支持从远程URL获取资源。COPY 指令只能从执行 docker build 所在的主机上读取资源并复制到镜像中。而 ADD 指令还支持通过 URL 从远程服务器读取资源并复制到镜像中。

相同复制命令下,使用ADD构建的镜像比COPY命令构建的体积大,所以如果只是复制文件使用COPY命令。ADD 指令更擅长读取本地tar文件并解压缩。

ENTRYPOINT

ENTRYPOINTCMD一样,都是在指定容器启动程序以及参数,不会它不会被docker run的命令行指令所覆盖。如果要覆盖的话需要通过docker run --entrypoint来指定。

ENTRYPOINT有两种形式:

 ENTRYPOINT ["exec","param1","param1"]    
 ENTRYPOINT command param1 param2    

指定了ENTRYPOINT后,CMD的内容作为参数传递给ENTRYPOINT指令,实际执行时将变为:

VOLUME

创建一个具有指定名称的挂载数据卷。

 VOLUME ["/var/log/"]    
 VOLUME /var/log    

VOLUME的主要作用是:
- 避免重要的数据因容器重启而丢失。- 避免容器不断变大。- 保留配置文件。

ONBUILD

ONBUILD指令作为触发指令添加到镜像中,只有在该镜像作为基础镜像时执行。触发器将在下游构建的Dockerfile中的FROM指令之后执行。如果任何触发器失败,FROM指令将中止,从而导致生成失败。如果所有触发器都成功,FROM指令将完成,构建将照常继续。

 ONBUILD ADD . /app/src    
 ONBUILD RUN /usr/local/bin/python-build --dir /app/src    

注意,ONBUILD指令不能触发FORM和MAINTAINER指令。

STOPSIGNAL

设置容器退出时唤起的系统调用信号。该信号可以是与内核系统调用表中的位置匹配的有效无符号数字,例如9,或格式为SIGNAME的信号名称,如SIGKILL。

 STOPSIGNAL signal    

默认的stop-signal是SIGTERM,在docker stop的时候会给容器内PID为1的进程发送这个信号,通过--stop-signal可以设置需要的signal,主要用于让容器内的程序在接收到signal之后可以先处理些未完成的事务,实现优雅结束进程后退出容器。如果不做任何处理,容器将在一段时间后强制退出,可能会造成业务强制中断,默认时间是10s。

HEALTHCHECK

HEALTHCHECK指令告诉容器如何检查它是否保持运行。当容器具有指定的HEALTHCHECK时,除了其正常状态外,还具有健康状态。容器的状态最初是starting,只要通过健康检查,容器的状态就变成healthy(无论之前处于什么状态)。如果经过一定数量的失败检查,容器的状态会变成unhealthy

HEALTHCHECK指令有两种形式:
- HEALTHCHECK [OPTIONS] CMD command:通过容器内运行命令来检查容器健康状况。后面命令的退出状态会影响容器的健康状态,如:

    - 0: success - 容器是健康的,并且准备使用- 1: unhealthy - 容器没有正确工作- 2: reserved - 没有使用退出状态


    - HEALTHCHECK NONE:禁用从基础镜像继承的任何健康检查。
    HEALTHCHECK选项(应处于CMD之前):
    - --interval=DURATION:检查间隔,default: 30s。- --timeout=DURATION:检查超时时间,超出此范围认为检查失败,default: 30s。- --start-period=DURATION:容器初始化阶段的时间,此阶段健康检查失败不计入最大重试次数,如果检查成功则认为容器已启动,default: 0s。- --retries=N:健康检查连续失败次数,default: 3
    举例:

     HEALTHCHECK --interval=5m --timeout=3s \    
       CMD curl -f http://localhost/ || exit 1    
    

    SHELL

    SHELL指令用于设置默认shell。Linux上默认shell是["/bin/sh","-c"],Windows上是["cmd","/S","/C"]

     SHELL ["exec","param1"]    
    

    SHELL指令在Windows上特别有用,因为Windows有两种截然不同的本机SHELL:CMD和powershell,以及备用的sh。该SHELL指令可以出现多次。每条SHELL指令都会覆盖所有先前的SHELL指令,并影响后续指令。

     FROM    
     Learn more about the "FROM" Dockerfile command.    
      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    
    

    WORKDIR

    WORKDIR指令为Dockerfile中接下来的RUNCMDENTRYPOINTADDCOPY指令设置工作目录。如果WORKDIR不存在,及时它没有在后续Dockerfile指令中使用,它也会被创建。

    Dockerfile中可以多次使用WORKDIR,如果提供了相对路径,它将相对于前一条WORKDIR指令的路径。

    1
    2
    3
    4
     WORKDIR /a    
     WORKDIR b    
     WORKDIR c    
     RUN pwd    
    

    最终 pwd 命令的输出是 /a/b/c。

    该 WORKDIR 指令可以解析先前使用 ENV,例如:

    1
    2
    3
     ENV DIRPATH=/path    
     WORKDIR $DIRPATH/$DIRNAME    
     RUN pwd    
    

    最终 pwd 命令的输出是 /path/$DIRNAME。

    官方推荐WORKDIR始终使用绝对路径。此外,尽量避免使用RUN cd ..& & dosomething,大量的类似指令会降低可读性,令Dockerfile难以维护。

    USER

    RUN指令设置用户名或(UID)和可选用户组(或GID),用于运行Dockerfile中接下来的RUNCMDENTRYPOINT指令。

     USER <user>[:<group>]    
     USER <UID>[:<GID>]    
    

    注意,在Linux上,当用户没有主组时,镜像(或指令)将与根组一起运行。 在Windows上,如果用户不是内置帐户,则必须首先创建该用户。也可以先通通过net user创建用户,再指定用户。
    FROM microsoft/windowsservercore
    # Create Windows user in the container
    RUN net user /add patrick
    # Set it for subsequent commands
    USER patrick

    MAINTAINER

    MAINTAINER指令设置生成镜像的作者。如:

     MAINTAINER <name>    
    

    配置文件 /etc/docker/daemon.json

    /etc/docker/daemon.json

    {
        "authorization-plugins": [],//访问授权插件
        "data-root": "",//docker数据持久化存储的根目录
        "dns": [],//DNS服务器
        "dns-opts": [],//DNS配置选项,如端口等
        "dns-search": [],//DNS搜索域名
        "exec-opts": [],//执行选项
        "exec-root": "",//执行状态的文件的根目录
        "experimental": false,//是否开启试验性特性
        "storage-driver": "",//存储驱动器
        "storage-opts": [],//存储选项
        "labels": [],//键值对式标记docker元数据
        "live-restore": true,//dockerd挂掉是否保活容器(避免了docker服务异常而造成容器退出)
        "log-driver": "",//容器日志的驱动器
        "log-opts": {},//容器日志的选项
        "mtu": 0,//设置容器网络MTU(最大传输单元)
        "pidfile": "",//daemon PID文件的位置
        "cluster-store": "",//集群存储系统的URL
        "cluster-store-opts": {},//配置集群存储
        "cluster-advertise": "",//对外的地址名称
        "max-concurrent-downloads": 3,//设置每个pull进程的最大并发
        "max-concurrent-uploads": 5,//设置每个push进程的最大并发
        "default-shm-size": "64M",//设置默认共享内存的大小
        "shutdown-timeout": 15,//设置关闭的超时时限(who?)
        "debug": true,//开启调试模式
        "hosts": [],//监听地址(?)
        "log-level": "",//日志级别
        "tls": true,//开启传输层安全协议TLS
        "tlsverify": true,//开启输层安全协议并验证远程地址
        "tlscacert": "",//CA签名文件路径
        "tlscert": "",//TLS证书文件路径
        "tlskey": "",//TLS密钥文件路径
        "swarm-default-advertise-addr": "",//swarm对外地址
        "api-cors-header": "",//设置CORS(跨域资源共享-Cross-origin resource sharing)头
        "selinux-enabled": false,//开启selinux(用户、进程、应用、文件的强制访问控制)
        "userns-remap": "",//给用户命名空间设置 用户/组
        "group": "",//docker所在组
        "cgroup-parent": "",//设置所有容器的cgroup的父类(?)
        "default-ulimits": {},//设置所有容器的ulimit
        "init": false,//容器执行初始化,来转发信号或控制(reap)进程
        "init-path": "/usr/libexec/docker-init",//docker-init文件的路径
        "ipv6": false,//开启IPV6网络
        "iptables": false,//开启防火墙规则
        "ip-forward": false,//开启net.ipv4.ip_forward
        "ip-masq": false,//开启ip掩蔽(IP封包通过路由器或防火墙时重写源IP地址或目的IP地址的技术)
        "userland-proxy": false,//用户空间代理
        "userland-proxy-path": "/usr/libexec/docker-proxy",//用户空间代理路径
        "ip": "0.0.0.0",//默认IP
        "bridge": "",//将容器依附(attach)到桥接网络上的桥标识
        "bip": "",//指定桥接ip
        "fixed-cidr": "",//(ipv4)子网划分,即限制ip地址分配范围,用以控制容器所属网段实现容器间(同一主机或不同主机间)的网络访问
        "fixed-cidr-v6": "",//(ipv6)子网划分
        "default-gateway": "",//默认网关
        "default-gateway-v6": "",//默认ipv6网关
        "icc": false,//容器间通信
        "raw-logs": false,//原始日志(无颜色、全时间戳)
        "allow-nondistributable-artifacts": [],//不对外分发的产品提交的registry仓库
        "registry-mirrors": [],//registry仓库镜像
        "seccomp-profile": "",//seccomp配置文件
        "insecure-registries": [],//非https的registry地址
        "no-new-privileges": false,//禁止新优先级(??)
        "default-runtime": "runc",//OCI联盟(The Open Container Initiative)默认运行时环境
        "oom-score-adjust": -500,//内存溢出被杀死的优先级(-1000~1000)
        "node-generic-resources": ["NVIDIA-GPU=UUID1", "NVIDIA-GPU=UUID2"],//对外公布的资源节点
        "runtimes": {//运行时
            "cc-runtime": {
                "path": "/usr/bin/cc-runtime"
            },
            "custom": {
                "path": "/usr/local/bin/my-runc-replacement",
                "runtimeArgs": [
                    "--debug"
                ]
            }
        }
    }