Docker学习——Dockerfile中的构建命令

    xiaoxiao2022-07-04  123

    目录

     

    前言

     

    Dockerfile的作用

    Parser directives

    escape

    ENV

    .dockerignore文件

    FROM

    RUN

    CMD

    LABEL

    MAINTAINER

    EXPOSE

    ENV

    ADD

    COPY

    ENTRYPOINT

     

    VOLUME

    USER

    WORKDIR

    ARG

    ONBUILD

    STOPSIGNAL

    HEALTHCHECK

    SHELL   前言

    docker的有些文档写的真的有点糟糕.............   Dockerfile的作用

    相当于docker构建镜像的说明书,docker会根据Dockerfile中的构建命令一步一步的构建镜像,每一步构建指令都会产生一个镜像,在这个镜像的基础上在执行下一步构建指令,本博客不会涉及docker构建镜像的细节,只会介绍Dockerfile中的命令,运行dokcer build命令可以构建镜像,此时会将工作目录下的所有文件发送给docker守护进程(不管构建过程是不是需要)

     

      Parser directives

    Parser directives会影响docker后续处理行的方式,它不会在构建中填加额外的层,关于构建过程中层的概念,请查看:docker 的image是什么

    使用格式:#directive=value

    注意事项:以下使用方式会导致Parser directives无效

        换行

            # direc \         tive=value

        重复定义

            # directive=value1         # directive=value2                   FROM ImageName

        出现在构建命令之后

            FROM ImageName         # directive=value

        出现在非parser directive之后

            # About my dockerfile         # directive=value         FROM ImageName

        不是合法的parser directive,目前docker支持的Parser directives只有escape,所以我在这里废话总结

            # unknowndirective=value         # knowndirective=value

      escape

    定义转义符号,目前支持两种形式

    # escape=\ (backslash)

    # escape=` (backtick)

    如果在dockerfile中未指定,则默认为\,这会导致一些麻烦,因为\是windows的文件路径分割符,如果我们如下使用:

        FROM microsoft/nanoserver     COPY testfile.txt c:\\     RUN dir c:\

    二、三行命令会被翻译成:

    COPY testfile.txt c:\RUN dir c:

    因此在windows上最好使用  ` 号

      ENV

    dockerfile中可以使用环境变量:$variable_name或是${variable_name},这两种格式被同等对待,但是括号可以处理空格的状态,

    ${variable_name}具有更多的用法:

        ${variable:-word}:如果variable值没有被指定,那么将使用word作为值     ${variable:+word}:如果variable值被指定,那variable最终的值将是word,如果没有被指定,则默认为空字符串

    环境变量也会被转义字符转义:

    COPY \$foo /quux 等效于 COPY $foo /quux

    环境变量的值可以通过ENV指令指定,ENV定义的值只有在ENV命令外才会生效,例如:

        ENV abc=hello     ENV abc=bye def=$abc     ENV ghi=$abc

    def的值将是hello(由于abc=hello在第一条ENV命令中,位于第二条ENV命令的def外),ghi的值将是bye

      .dockerignore文件

    前面说过docker build指令会将工作目录的所有文件发送给docker守护进程,在此之前,docker会检查工作目录下是否存在.dockerignore文件,通过.dockerignore文件,我们可以指定哪些文件不用发送给docker守护进程,.dockerignore文件以一行为单位,表示哪些文件不需要添加到docker守护进程,.dockerignore中的文件路径都是相对于工作目录而言,如果我们在一行的前面标记#,则改行被当作注释:

        # comment     */temp*     */*/temp*     temp?

    上述文件每行意义如下:

    .dockerignore也支持通配符,**表示匹配任意数目的目录,!表示排除在外的意思,例如:

        *.md     !README.md

    除了README.md以外的所有.md文件都会被排除在外,.dorckerignore文件的最后一行具有最高的优先级,它会覆盖之前的匹配,例如:

            *.md         !README*.md         README-secret.md

    即使README-secret.md匹配!README*.md,由于README-secret.md在最后一行,因此仍然会将README—secret.md移除,再如:

           *.md         README-secret.md         !README*.md

    README-secret.md不会被移除,因为!README*.md在最后一行

    docker一定会见工作目录的Dockerfile文件发完docker守护进程,即使在.dockeringnore中声明Dockerfile

      FROM

    FROM指令具有三种格式:

        FROM <image> [AS <name>]     FROM <image>[:<tag>] [AS <name>]     FROM <image>[@<digest>] [AS <name>]

    要点:

        FROM为接下来的构建指令指定基础镜像,一个有效的Dockerfile文件必须以FROM指令开头     除arg指令以外的构建指令都不能出现在FROM之前,Dockerfile文件可以出现多个FROM指令,此时一个Dockerfile可以构建多个image,并且输出这些image的ID,在执行FROM指令时,之前构建命令生成的状态会被清空,若arg指令位于FROM之外,FROM内部的指令不能引用arg,如果想使用,必须声明一遍:

            ARG VERSION=latest         FROM busybox:$VERSION         #声明过后,才能替换RUN指令为的$VERSION为latest         ARG VERSION         RUN echo $VERSION > image_version

        FROM指令允许添加镜像的别名(指令中的[AS <name>]),在接下来的FROM指令或是COPY --from=<name|index>指令中可以引用这个镜像     tag与digest指镜像的版本信息,如果不指定,则默认为latest

      RUN

    RUN指令有两种形式:

        #shell形式,命令会运行在shell脚本上,在linux上默认为/bin/sh -c,在windwos上默认为cmd /S /C     RUN <command>           #exec形式     RUN["executable","param1","param2"]

    要点:

        RUN指令会在当前镜像的基础上执行命令     如果当前镜像不支持默认的shell,可以使用第二种形式,exec形式会解析成JSON数组,所以不能使用单引号

    RUN ["/bin/bash", "-c", "echo hello"]

        可以通过SHELL指令更改默认的shell环境     exec形式不会默认调用shell,类似于RUN [ "echo", "$HOME" ]的指令(需要环境变量解析)将不会得到解析,环境变量解析的工作由shell进行,不是docker     RUN命令的执行结果会进行缓存,以便加快二次构建的速度,可以使用docker build --no-cache,禁止使用缓存

      CMD

    CMD指令具有三种形式

        #exec形式,推荐使用     CMD ["executable","param1","param2"]           #作为ENTRYPOINT指令的参数     CMD ["param1","param2"]           #shell形式     CMD command param1 param2

    要点:

        dockerfile中只有一条CMD指令会生效,如果有多条,只有最后一条CMD指令生效     CMD指令主要为ENTRYPOINT提供默认值,此时CMD指令与ENTRYPOINT指令都必须使用exec格式     exec指令会解析成JSON格式,因此必须使用双引号     exec形式不会调用shell,这意味着CMD [ "echo", "$HOME" ]不会进行环境变量解析,如果想要使用,更改为CMD [ "sh", "-c", "echo $HOME" ],环境变量的解析均有shell负责,而不是docker     当镜像运行时才会运行CMD指令,而RUN是在构建阶段运行     如果使用shell形式,命令会运行在/bin/sh -c上     如果不想运行在shell上,就使用exec形式,但是要指明可执行文件的位置     如果在docker run命令上添加了参数,会覆盖CMD中对应的默认值

      LABEL

    LABEL <key>=<value> <key>=<value> <key>=<value> ...

    要点:

        LABEL命令增加元数据到image中(描述作用)     LABEL命令使用key-value模式     子image会继承父image的LABEL,同时可以覆盖其中的值     可以使用docker inspect命令查看Labels

      MAINTAINER

    MAINTAINER <name>

    要点:

        指定image的创作者

      EXPOSE

    EXPOSE <port> [<port>/<protocol>...]

    要点:

        EXPOSE让container在运行时监听特定的端口,可以指定端口运行tcp或是udp命令,默认情况下为tcp

    EXPOSE 80/udp

        EXPOSE命令不会真正发布端口,只是image构建者告诉container运行者应该如何映射端口     docker run指令的-p参数可以指定端口映射,以及对应的协议,此时才会发布端口

    docker run -p 80:80/tcp -p 80:80/udp ...

      ENV

        #一行只能设置一个全局变量,双引号会被去除     ENV <key> <value>     #一行可以设置多个全局变量     ENV <key>=<value> ...

    要点:

        ENV指令设置的key-value相当于全局变量     ENV指令设置的全局变量会持久化,可以使用docker inspect查看,可以使用docker run --env <key>=<value>更改其中的值

      ADD

        ADD [--chown=<user>:<group>] <src>... <dest>     #当存在空格时,只能使用这种形式     ADD [--chown=<user>:<group>] ["<src>",... "<dest>"]

    要点:

        [--chown=<user>:<group>]只在linux上有效,用于指定用户以及用户组     ADD指令将文件、文件夹、URL处的文件(夹)拷贝到<dest>指示的位置     如果<src>不是URL,则文件与文件夹的位置都是是相对于工作目录的,即相对目录     <src>可以使用通配符

            ADD hom* /mydir/        # adds all files starting with "hom"         ADD hom?.txt /mydir/    # ? is replaced with any single character, e.g., "home.txt"

              .<dest>只能是绝对路径或相对于WORDIR(稍后会介绍的指令)

            ADD test relativeDir/          # adds "test" to `WORKDIR`/relativeDir/         ADD test /absoluteDir/         # adds "test" to /absoluteDir/

        除非指定了--chown,否则所有新创建的文件以及目录的UID与GID均为0,--chown允许UID以及GID为数字或是字符串,也可以是两者的组合,/etc/passwd和/etc/group文件会被用来将字符串转换为对应的数字形式的UID以及GID,如果只指定了UID,GID默认取UID的值     如果URL需要验证登陆,ADD指令需要与RUN wget、RUN curl指令搭配使用(提供账号密码)     如果使用STDIN给出Dockerfile,可能会没有上下文,此时ADD指令只能通过URL获取资源

            #没有上下文         docker build -< Dockerfile                   #解压后的文件作文上下文         docker build - < archive.tar.gz

              如果<src>发生了改变,包括ADD在内的接下来的所有构建指令的缓存都会无效化     如果<src>是URL,而<dest>是文件夹,则文件名有URL中自动推算得知,例如ADD http://example.com/foobar /,在/下对应的文件名为foobar     如果<src>是文件夹,则文件夹的所有内容都会被拷贝到<dest>     如果<src>是压缩文件,则ADD会将其解压,URL对应的压缩文件不会被解压,一个文件会不会被解压不是由文件后缀决定,而是文件内容     将多个文件或是文件夹ADD到<dest>,<dest>必须是一个文件夹,并且以/结尾,否则会被认为是一个文件     如果<dest>不存在,则ADD指令会创建对应的文件路径

      COPY

    copy有两种形式:

        COPY [--chown=<user>:<group>] <src>... <dest>     #如果路径包括空格,则使用这种格式     COPY [--chown=<user>:<group>] ["<src>",... "<dest>"]

    要点:

        copy将文件从<src>拷贝到<dest>,与ADD不同,它不支持从URL获取文件或文件夹,其余使用与ADD基本一致     copy指令可以使用--from=<name|index>引用之前构建阶段的镜像(FROM ..AS<name>创建的镜像),如果在之前的构建阶段找不到对应的镜像,则会尝试使用相同名字的镜像(从远程下载),也可以指定index,从而引用某个镜像(name指定)某个构建阶段(index指定)对应的镜像

      ENTRYPOINT

    ENTRYPOINT具有两种写法:

        #exec形式     ENTRYPOINT ["executable", "param1", "param2"]     #shell形式     ENTRYPOINT command param1 param2

    要点:

        运行docker run指令后会运行的指令     docker run指令后面的参数或是命令会附加到ENTRYPOINT上,会覆盖cmd对应的值,例如cmd指令指定了-name的值,如果使用docker run -name....,则容器最终的name为docker run指定的值     通过docker run --entrypoint会替换ENTRYPOINT的值     shell形式不接受cmd指定的参数,shell形式有一个缺点,就是启动的可执行程序不会接收信号,如果我们运行docker stop指令,可执行程序将不会接收到停止信号     如果定义了多条entrypoint指令,只有最后一条可以生效     cmd指令与ENTRYPOINT指令的关系

        两者均制定了容器运行时执行的命令     Dockerfile应该至少指定CMD或是ENTRYPOINT中的一个     CMD可以为ENTRYPOINT指定参数值     CMD指定的值可以被命令中对应的参数值替换,两者的协作效果如下

      VOLUME

    命令格式:

        #定义匿名数据卷     VOLUME ["/data"]

    要点:

        VOLUME指令用于创建一个挂载点,挂载点用于存储持久化数据,一般不建议将数据存储在Docker容器的可写层(原因我还没看),挂载点可以理解为就是一个用于存储数据的文件,只是这个文件由docker统一管理,当然,也可以将本地文件映射成挂载点,此时数据将写入到本地文件中     volume分为两种,一种是匿名卷,一种是实名卷,匿名数据卷就是未映射到本文将的卷,一般存储在/var/lib/docker/volumes中,当容器被删除时,对应的卷也会被删除,实名卷映射到了本地文件,当容器被删除时也不会被删除     实名卷只可以通过docker run -v指定,例如docker run -v /var/temp:/app     docker run指令会保留作为卷的文件之前的数据,例如:

            FROM ubuntu         RUN mkdir /myvol         RUN echo "hello world" > /myvol/greeting         VOLUME /myvol                   /myvol中将存在greeting文件,并且该文件保留hello world的字符

        在windows上使用卷时,挂载文件必须存储在空文件夹或是一开始不存在的文件夹下,并且文件夹不能存储在C盘     使用实名卷需要注意,实名卷可能会影响容器的移植性,因为实名卷对应的文件结构受操作系统的影响,因此,我们不能在Dockerfile中指定使用实名卷(影响移植性),只能通过docker run -v指令

      USER

    格式:

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

    要点:

        用于指定运行image、RUN、CMD、ENTRYPOINT的user和group,只有对应的user以及group可以运行image     如果user没有对应的group,则默认使用root

      WORKDIR

    命令格式:

    WORKDIR /path/to/workdir

    要点:

        RUN、CMD、ENTRYPOINT、COPY、ADD指令可以使用,当这些指令未指出工作目录时,则默认使用WORKDIR指定的目录作为工作目录     如果WORKDIR指定的目录不存在,则会默认创建     WORKDIR指令可以使用多次,如果使用相对路径,会承接到之前的WORKDIR指定的路径中,例如:

            WORKDIR /a         WORKDIR b         WORKDIR c         RUN pwd                   RUN指令指定的文件为 /a/b/c/pwd

        WORKDIR指令可以使用ENV指定的环境变量,例如:

            ENV DIRPATH /path         WORKDIR $DIRPATH/b         RUN pwd                   RUN指令指定的文件为/path/b/pwd

      ARG

    命令格式:

    ARG <name>[=<default value>]

    要点:

        ARG定义参数的值必须通过docker build --build-arg <varname>=<value> 指定     dockerfile文件可以使用多个ARG参数

            FROM busybox         ARG user1         ARG buildno         ...

        一般不建议将账号密码等敏感信息作为ARG参数的值,因为可以通过docker history命令查看到     ARG指令可以指定参数的默认值     ARG指令只对位于自己下方的指令有效,镜像构建完毕后就会失效,如果想在多个镜像的构建过程中使用,则在多个镜像的构建过程中指定相同的ARG:

            FROM busybox         ARG SETTINGS         RUN ./run/setup $SETTINGS                   FROM busybox         ARG SETTINGS         RUN ./run/other $SETTINGS

        ENV指令会覆盖ARG指令中相应的参数,例如:

            1 FROM ubuntu         2 ARG CONT_IMG_VER         3 ENV CONT_IMG_VER v1.0.0         4 RUN echo $CONT_IMG_VER                   运行指令docker build --build-arg CONT_IMG_VER=v2.0.1 .                   CONT_IMG_VER的值将是v1.0.0

        有些ARG参数是预定义的:

            HTTP_PROXY         http_proxy         HTTPS_PROXY         https_proxy         FTP_PROXY         ftp_proxy         NO_PROXY         no_proxy                   可以直接使用,这些参数的值不会被docker history输出,我们也可以自己覆盖这些参数

              如果指定的ARG指令与之前构建阶段的不同,如果在其他指令中使用过ARG,则会出现缓存缺失,但如果它的值杯ENV指令覆盖,则不会出现:

            1 FROM ubuntu         2 ARG CONT_IMG_VER         3 ENV CONT_IMG_VER hello         4 RUN echo $CONT_IMG_VER                   因为ARG指令的CONT_IMG_VER杯ENV覆盖了,所以不会出现缓存确实

      ONBUILD

    ONBUILD [INSTRUCTION]

    要点:

        指定运行镜像后紧接着执行的命令     这个指令是如何起作用的呢?在构建镜像时,builder会将ONBUILD指令的值添加到镜像的OnBuild中,可以通过运行docker inspect查看,当其他镜像使用这个镜像时,builder会查看OnBuild区域,并且按顺序执行它们,OnBuild区域的值不会被继承

      STOPSIGNAL

    STOPSIGNAL signal

    要点:

        使用这个指令允许用户自定义应用在收到 docker stop 时所发送的信号

      HEALTHCHECK

        #通过运行容器中的指令来判断容器是否健康,CMD可以是shell或是exec形式     HEALTHCHECK [OPTIONS] CMD command           #禁止所有父镜像的健康检查     HEALTHCHECK NONE

    要点:

        这条指令用于检查容器的健康状况     如果容器指定了健康检查,会添加额外的health字段,这个字段一开始是starting,当健康检查通过以后,会更改为healthy,如果几次尝试都失败,则会设置为unhealthy     OPTIONS字段

            #两次健康检查的间隔         --interval=DURATION(默认为30s)                   健康检查命令运行超时时间,如果超过这个时间,本次健康检查视为失败         --timeout=DURATION(默认为30s)                   #应用启动的初始化时间,在启动过程中的健康检查失效不会计入         --start--period=DURATION(默认为0s)                   #当连续失败指定次数后,则将容器状态视为unhealthy         --retries=N(默认为3次)          

         

        如果有多条HEALTHCHECK,只有最后一条才会起作用

        这条命令执行完毕后,会输出一个数字:

            #成功         0:success         #失败         1:unhealthy         #保留字段,没有意义         2:reserved

         

      SHELL

    SHELL ["executable", "parameters"]

    要点:

        用于指定shell形式的命令运行的shell环境,linux默认的shell环境为["/bin/sh","-c"],windwos默认为["cmd","/S","/C"] --------------------- 作者:菜到怀疑人生 来源: 原文:https://blog.csdn.net/dhaiuda/article/details/82424282 版权声明:本文为博主原创文章,转载请附上博文链接!

    最新回复(0)