Dockerfile命令详解

什么是 Dockerfile?

Dockerfile 是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和说明。Docker读取Dockerfile文件里面的指令,自动地构建镜像。

基本特点

  • dockerfile由许多行命令语句组成,支持以#开头为注释行
  • 行命令本身不区分大小写,但是一般把指令写成大写,用于区分命令行参数
  • Docker运行Dockerfile的指令是顺序执行的,因此在写Dockerfile文件的时候,一定要注意行命令的依赖关系,注意顺序
  • 第一个非注释的命令,必须从FROM开始

基本结构

dockerfile分为四部分:基础镜像信息、维护者信息、镜像操作指令、容器启动时执行指令,如:

dockerfile分为四部分:基础镜像信息、维护者信息、镜像操作指令、容器启动时执行指令,如:
# This dockerfile user the ubuntu image
# VERSION 2 - EDITON 1
# Author: docker_user
# Command format: Instruction [arguments / command] .. 
# 第一行必须指定基于的基础镜像
FROM ubuntu
# 维护者信息
MAINTAINER  docker_user docker_user@email.com 
# 镜像的操作指令
RUN echo "deb http://archive.ubuntu.com/ubuntu/ raring main universe" >> /etc/apt/sources.list
RUN apt-get update && apt-get install -y nginx 
# 容器启动时执行指令
CMD /usr/sbin/nginx

Dockerfile常用指令  

FROM 指令

FROM指令是最重要的一个,且必须为Dockerfile文件开篇的第一个非注释行,用于为镜像文件构建过程指定基准镜像,后续的指令运行于此基准镜像所提供的运行环境,因此后续的命令行是否可以正常的使用,取决于该基准镜像。基准镜像可以是任何可用的镜像文件,默认情况下,docker build会在docker主机上查找指定的镜像文件,在其不存在时,则会从Docker Hub Registry上,去所需的镜像文件。如果找不到指定的镜像文件,docker build会返回一个错误信息。

语法格式:
FROM <repository>[:<tag>]或者FROM <repository>@<digest镜像的hash码>
<repository>:指定作为base image的名称
<tag>:base image的标签,为可选项,省略时默认为latest

MAINTAINER 指令
用于让Dockerfile制作者提供本人的详细信息
Dockerfile并不限制MAINTAINER指令出现的位置,但是推荐将其放置于FROM指令之后
语法格式:
MAINTAINER <discirbe message>
discirbe message可是任何文本信息,但是约定俗成的使用作者名和邮件地址
MAINTAINER "docker_user docker_user@email.com"

LABEL指令
用于为镜像添加元数据。一个镜像可以有多个LABEL指令,可以单行里指定多个标签。作者的信息,可以使用这个进行表示
语法格式:
LABEL <key>=<value> <key>=<value> <key>=<value> <key>=<value> ...

COPY指令
用于从Docker宿主机的当前目录复制文件到创建的新镜像中;
语法格式:
COPY <src>...<dest>或者 COPY ["<src>",... "<dest>"]
<src>:要复制的源文件或者目录,支持使用通配符,src是相对路径
<dest>:目标路径,即正在创建的images的文件系统路径;建议<dest>使用绝对路径,否则COPY指令使用以WORKDIR为其起始路径,在路径中有空白字符时,通常使用第二种格式
文件复制准则:
<src>必须是docker build时Dockerfile文件所在目录,上下文中的路径,不能是其父目录中的文件,
如果<src>是目录,则其内部文件或者子目录会递归复制,但<src>目录自身不会被复制
如果指定了多个<src>,或者<src>中使用了通配符,则<dest>必须是一个目录,且必须以/结尾
如果<dest>事先不存在,它将会被自动创建,这包括其父目录路径

ADD指令
ADD指令类似于COPY指令,所不同的地方是ADD支持使用TAR文件和url路径
语法格式:
ADD <src>...<dest>或者 ADD ["<src>",... "<dest>"]
操作准则:
同COPY指令,将文件复制到镜像文件中,同样需求下,官方推荐使用 COPY
如果<src>为url且<dest>不以/结尾,则<src>指定的文件将被下载并直接被创建为<dest>;如果<dest>以/结尾,则文件名url指定的文件将被直接下载并保存为<dest>/<filename>
如果<src>是一个本地系统上的压缩格式的tar文件,它将被展开为一个目录,其行为类似于"tar -x"命令;然而,通过url获取到的tar文件将不会自动展开
如果<src>有多个,或其间接或者直接使用了通配符,则<dest>必须是一个以/结尾的目录路径;如果<dest>不以/结尾,则其被视作一个普通文件,<src>的内容被直接写入到<dest>

WORKDIR指令
用于为Dockerfile中所有的RUN,CMD,ENTRYPOINT,COPY和ADD指令设定工作目录。用 WORKDIR 指定的工作目录,会在构建镜像的每一层中都存在。WORKDIR 指定的工作目录,必须是提前创建好的。
docker build 构建镜像过程中的,每一个 RUN 命令都是新建的一层。只有通过 WORKDIR 创建的目录才会一直存在。可以在 docker run命令中用 -w参数覆盖掉WORKDIR指令的设置。容器启动时执行的命令会在该目录下执行。
相当于设置容器的工作目录了。在Dockerfile文件中,WORKDIR指令可出现多次,其路径也可以为相对路径。不过,其是相对此前一个WORKDIR指令指定的路径。另外,WORKDIR也可以调用由ENV指令定义的变量。
语法格式:
WORKDIR <dirpath>

VOLUME指令
用于在image中创建一个挂载点目录,以挂载docker host上的卷或者其他容器上的卷。而卷的创建,由docker daomen自动的在默认目录/var/lib/docker/volumes下创建卷,并挂载到这个挂载点。在启动容器 docker run 的时候,我们可以通过 -v 参数修改挂载点。
如果挂载点目录路径下,有文件存在,docker run命令会在卷挂载完成后,将此前的所有文件赋值到新挂载的卷中。
语法格式:
VOLUME <mountpoint>或者VOLUME ["<mountpoint>"]

EXPOSE指令
声明运行时容器提供服务端口,容器打开指定要监听的端口,以实现与外部通信。这只是一个声明,在运行时并不会因为这个声明应用就会开启这个端口的服务。
在 Dockerfile 中写入这样的声明有两个好处,一个是帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射;
另一个用处则是在运行时使用随机端口映射时,也就是 docker run -P 时,会自动随机映射 EXPOSE 的端口。EXPOSE指令可一次指定多个端口,例如EXPOSE 11211/udp 11211/tcp
语法格式:
EXPOSE <port> [/<protocol>] [<port> [/<protocol>]...].<protocol>用于指定传输层协议,可为tcp或udp二者之一,默认为tcp协议

ENV指令
用于为镜像定义所需的环境变量,并可被Dockerfile文件中位于其后的其他指令(如ENV,ADD,COPY等)所调用。调用格式为$variable_name或者${variable_name}。
可以在定义变量时为这些变量赋默认值,通过${variable:-默认值}方式,也可以在执行docker run命令时,为这些变量赋值,通过docker run --env 给变量赋值
在dockerfile文件中定义的所有环境变量,可以在docker run启动容器后,在容器中使用,你可以通过pring env,查看这些定义的变量,
在dockerfile中定义了这些变量,并赋值了,制作了镜像,在运行这个镜像的时候,可以通过docker run --env,为这些变量重新的赋值。
语法格式:
ENV <key>=<value> 或者 ENV <key>=<value> <key>=<value> ...
第一种格式中,<key>之后的所有内容均会被视作其<value>的组成部分,因此,一次只能设置一个变量;
第二种格式可一次设置多个变量,每个变量为一个"<key>=<value>"的键值对,如果<value>中包含空格,可以以反斜线(\)进行转义,也可以通过对<value>加双引号进行标识;
另外,反斜线也可用于续行;定义多个变量时,建议使用第二种格式,以便在同一层中完成所有功能

RUN指令
用于指定docker build过程中,运行的程序,其可以是任何的命令。每条RUN 指令将在当前镜像基础上执行指定命令,将提交为新的镜像。当命令较长时可以使用 \ 来换行
语法格式:
RUN <command>或者RUN ["<executable>","<param1>","<param2>"]
第一种语法格式中,<command>通常是一个shell命令,且以"/bin/sh -c"来运行它,这意味着此进程在容器中的pid不为1,不能接受unix信号。因此,当使用docker stop <container>命令,停止容器时,
此进程接受不到SIGTERM信号。而进到容器中查看pid的时候,又看到了其pid为1的信息,为什么呢?是因为docker 为了管理容器,在执行命令的时候,通过exec命令,把<command> 替换成原有进程的内容,沿用它的pid号。(因为任何在shell交互界面,执行的常用shell命令,都是通过fork一个子进程的方式来执行的)
第二种语法格式中的参数是一个json格式的数组,其中<executable>为要运行的命令,后面的<paramN>为传递给命令的选项或者参数;然而,此种格式指定的命令,不会以"/bin/sh -c"来发起,
因此常见的shell操作如变量替换以及通配符等替换将不会进程(即该程序由内核来直接启动,不经过shell fork的子进程,其pid直接为1,可以接受系统发出的signal信号);不过,如果要运行的命令依赖于此shell特性的话,可以将其替换为类似下面的格式。RUN ["/bin/bash","-c ","<executable>","<param1>"]。
简单一句话就是,使用 exec 模式时,容器中的任务进程就是容器内的 1 号进程,特点是不会通过 shell 执行相关的命令,所以像 $HOME 这样的环境变量是取不到的;
使用 shell 模式时,docker 会以 /bin/sh -c "task command" 的方式执行任务命令。也就是说容器中的 1 号进程不是任务进程而是 bash 的子进程。

CMD指令
类似于RUN指令,CMD指令也可用于运行任何命令或者应用程序。不过,二者的运行时间点不同。RUN指令运行于docker build镜像文件构建过程中,而CMD指令运行于基于Dockerfile文件构建出来的
新镜像文件启动一个新容器时;CMD指令的首要目的在于为启动的容器指定默认要运行的程序,且其运行结束后,容器也将终止;不过,CMD指定的命令,可以被docker run的命令行所覆盖;
在Dockfile文件中,可以存在多个CMD指令,但仅最后一个CMD命令会生效。docker run指令命令行,就运行其指定的命令行,如果没有,就运行CMD指定的命令
语法格式:
CMD <command> 或者CMD ["<executable>","<param1>","<param2>"] 或者CMD ["<param1>","<param2>"]
前两种语法格式的意义通RUN,第三种则用于为ENTRYPOINT指令提供默认参数

ENTRYPOINT指令
类似CMD指令的功能,用于为容器指定默认运行的程序,从而使得容器像是一个单独的可执行程序。与CMD不同的是,由ENTRYPOINT启动的程序不会被docker run命令行指定的参数所覆盖,而且,这些命令行参数会被当做参数传递给ENTRYPOINT指令指定的程序,不过,docker run命令的--entrypoint选项的参数可覆盖ENTRYPOINT指令指定的程序。docker run命令传入的命令参数会覆盖
CMD指令的内容并且附加到ENTRYPOINT命令最后做为其参数使用。如果ENTRYPOINT和CMD同时存在,并且执行docker run的时候,没有指定命令行,那么CMD指定的内容,做为参数放到ENTRYPOINT后面。
Dockerfile文件中也可以存在多个ENTRYPOINT指令,但仅有最后一个会生效。
语法格式:
ENTRYPOINT <command>(shell 中执行)或者 ENTRYPOINT ["<executable>","<param1>","<param2>"]

USER指令
用于指定运行image时或者运行Dockerfile中的任何RUN/CMD/ENTRYPOINT指令指定的程序时的用户和用户组。默认情况下,container的运行身份为root用户。
语法格式:
USER <UID>|<UserName>或者 USER <用户名>[:<用户组>]
需要注意的是,用户和用户组必须提前已经存在,<UID>可以为任意数字,但是其必须为/etc/passwd中某用户的有效UID,否则docker run命令将运行失败

HEALTHCHECK指令
用于告诉docker怎样去检测一个容器,它还是处于工作状态的。比如有时候一个提供web服务的容器,虽然进程处于运行状态,但是它已经不能对外提供服务,不能处理新的web请求。
语法格式:
HEALTHCHECK [选项] CMD <命令>:设置检查容器健康状况的命令
可选项包括:
--interval(默认为30s)执行健康检测命令的周期间隔,
--timeout(默认为30s) 执行健康检测命令后,认为失败的默认超时时间,
--start-period(默认为0s) 有时候,主进程初始化需要一段时间,这个参数表示多长时间以后,开始第一次检测
--retries(默认为3次),认为检测失败的次数
CMD的退出状态表示了容器的监控状态。
状态码为0,表示容器运行正常,且对外服务正常
状态码为1,表示容器工作不正常
状态码为2,未用
HEALTHCHECK NONE:如果基础镜像有健康检查指令,使用这行可以屏蔽掉其健康检查指令
样例:HEALTHCHECK --interval=5m --timeout=3s CMD curl -f http://localhost/ || exit 1

ARG指令
构建参数,与 ENV 作用一至。不过作用域不一样。ARG 定义的变量仅对 Dockerfile内有效,也就是说只有 docker build 的过程中有效,构建好的镜像内不存在此环境变量。
构建命令 docker build 中可以用 --build-arg <参数名>=<值> 来覆盖默认值。用户指定了一个Dockerfile文件中,未定义的参数,那么构建镜像时,会输出告警信息。Dockerfile文件中可以包括多个
ARG指令
语法格式:
ARG <参数名>[=<默认值>]

ONBUILD
用于延迟构建命令的执行。简单的说,就是 Dockerfile 里用 ONBUILD 指定的命令,在本次构建镜像的过程中不会执行(假设镜像为 test-build)。
当有新的 Dockerfile 使用了之前构建的镜像 FROM test-build ,这是执行新镜像的 Dockerfile 构建时候,会执行 test-build 的 Dockerfile 里的 ONBUILD 指定的命令。
语法格式:
ONBUILD <其它指令>

 

posted @ 2021-01-29 14:52  一切都是当下  阅读(881)  评论(0编辑  收藏  举报