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

目录

 

前言

 

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无效

  1. 换行
    # direc \
    tive=value
  2. 重复定义
    # directive=value1
    # directive=value2
    
    FROM ImageName
  3. 出现在构建命令之后
    FROM ImageName
    # directive=value
  4. 出现在非parser directive之后
    # About my dockerfile
    # directive=value
    FROM ImageName
  5. 不是合法的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}具有更多的用法:

  1. ${variable:-word}:如果variable值没有被指定,那么将使用word作为值
  2. ${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>]

要点:

  1. FROM为接下来的构建指令指定基础镜像,一个有效的Dockerfile文件必须以FROM指令开头
  2. 除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
  3. FROM指令允许添加镜像的别名(指令中的[AS <name>]),在接下来的FROM指令或是COPY --from=<name|index>指令中可以引用这个镜像
  4. 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指令的关系
  1. 两者均制定了容器运行时执行的命令
  2. Dockerfile应该至少指定CMD或是ENTRYPOINT中的一个
  3. CMD可以为ENTRYPOINT指定参数值
  4. 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"]
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Dockerfile是用于构建Docker镜像的文本文件,它包含了一系列指令来告诉Docker如何构建镜像。Dockerfile的格式如下: 1. 每个指令都以大写字母开头,并以换行符结束。 2. 指令和其参数之间可以使用空格或制表符进行分隔。 3. 注释以#开头,可以单独一行或在指令行的末尾添加。 4. 指令按照顺序执行,每个指令都会在上一个指令的基础上进行构建。 常见的Dockerfile指令包括: - FROM:指定基础镜像。 - MAINTAINER:指定作者信息。 - RUN:在镜像运行命令。 - ADD/COPY:将文件或目录从构建上下文复制到镜像。 - WORKDIR:设置工作目录。 - ENV:设置环境变量。 - EXPOSE:声明容器运行时的端口。 - CMD/ENTRYPOINT:设置容器启动时要执行的命令。 以下是一个示例的Dockerfile文件格式: ``` # 注释示例 # 设置基础镜像 FROM ubuntu:latest # 设置作者信息 MAINTAINER John Smith <john@example.com> # 安装软件包 RUN apt-get update && apt-get install -y package1 package2 # 复制文件到镜像 COPY ./path/to/source /path/to/destination # 设置工作目录 WORKDIR /path/to/workdir # 设置环境变量 ENV ENV_VARIABLE value # 声明容器运行时的端口 EXPOSE 8080 # 设置容器启动时要执行的命令 CMD ["command", "arg1", "arg2"] ``` 希望这个回答能帮助到你!<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [Docker——Dockerfile编写实战](https://blog.csdn.net/weixin_41605937/article/details/124916394)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值