Dockerfile指令详解

释放双眼,带上耳机,听听看~!

镜像的生成途径通常有以下三种:

  1. Dockerfile
  2. 基于容器制作
  3. Docker Hub automated builds

这段内容我们在Docker第三章镜像管理中有讲到过使用“基于容器制作”镜像的方法,但“基于容器制作”并没有Dockerfile功能强大,在我们日常生产中,也都是使用Dockerfile来制作镜像

为什么要用Dockerfile制作镜像

  1. 在我们生产环境当中,并不是从Docker Hub上pull下来一个镜像就符合我们的需求,我们以往要对配置文件以及其他配置做二次修改来完成我们的需求,但在每台容器上修改工作量无疑增大,这时候我们把修改过一台的容器制作成镜像,然后再使用此镜像直接启动容器即可。
  2. 上面有说道我们可以把容器制作为镜像直接拉起其它容器,其实也可以把我们配置好的配置文件存放到共享目录“存储卷”内,然后让容器进行挂载。

初识Dockerfile

Dockerfile组成

Dockerfile就是一个文本文件,然后在文本文件中定义镜像所需内容,此文件有固定格式
整个Docker就只有两类组成

  1. Conmment #注释信息
  2. INSTRUCTION arguments #指令加参数

Dockerfile工作原理

Dockerfile可以理解为构建Docker镜像的代码,通过配置Dockerfile文件来实现构建镜像

工作原理:
如上图所示,Dockerfile文件定义好之后通过build(docker build)命令来制作镜像,镜像制作成功后,可以通过docker run命令来使用此镜像直接启动容器以及docker push上传到镜像仓库 Docker registry或者导出镜像等

环境变量

Environment replacement 环境变量
这里的环境变量是我们使用docker build时可用的环境变量,变量赋值和bash里面一样

引用变量的两种方式:

1.变量:${variable:-word}
如果这个变量没有赋值,那么它就会去应用word这个字符串作为其$variable的值,如果其变量存在值,那就会引用它本身的值

2.变量:${variable:+word}
如果这个变量存在值,那么就给它重新赋值为后面的word字符串,如果这个变量值为空,则为空

Dockerfile环境总结

1.在Dockerfile文件中指令需大写,其实指令本身不需要区分大小写,因为大家都习惯在Dockerfile中把指令写为大写
2.在Dockerfile文件中指令都是按照顺序执行,从上到下依次执行,指令在Dockerfile文件中的前后顺序相当重要
3.Dockerfile文件必须要有一个专门的目录来作为Dockerfile的工作目录
4.工作目录内必须有一个文件叫Dockerfile,此文件名首字母必须大写,该文件为Dockerfile制作镜像的文件
5.在Dockerfile文件中所指定的文件和安装包必须放到此工作目录下或工作目录内的子目录内
6.Dockerfile支持工作目录下允许存在一个隐藏文件,此隐藏文件名叫dockerignore,但凡写进dockerignore文件内的路径Dockerfile指令都不能调用,相当于一个黑名单
7.Dockerfile文件中有指定运行的命令,必须是底层镜像所支持的命令,否则不可行

Dockerfile指令详解

Dockerfile指令是在Dockerfile文件中所指定运行命令以及复制文件到镜像内的一些指令

FROM

FROM指令是最重要且必须的一个为Dockerfile文件开篇的第一个非注释行,用于为镜像文件构建过程中指定基准镜像,后续的指定运行此基准镜像所提供的运行环境;
实践中,基准镜像可以是任何可用镜像文件,默认情况下,docker build会在docker主机上查找指定的镜像文件,在其不存在时,则会从docker hub registry上拉取所需的镜像文件;如果在FROM 指令后指定了Docker registry的地址,它就会到你指定的仓库地址中去拉取该镜像,如果在docker hub上找不到指定的镜像文件;
如果在docker hub上找不到指定的镜像文件,docker build会返回一个错误信息;

Syntax:

Syntax1:FROM <repository>[<tag>]
<reposotiry>:指定作为base image的名称;<tag>:base image的标签,为可选项,省略时默认为latest;
这种语法指定镜像的方法其实并不是很安全,因为你指定了镜像名称和标签后,也有可能有人修改了自己的镜像名称然后放到了共有的仓库中,或许这是一个挖矿代码;

Syntax2:FROM <resository>@<digest>
FROM<resository>@<digest>这样的resository指定了仓库名称,也可以是镜像名称,随后@后面的digest这个为这个镜像的哈希码,哈希码是没有办法被顶替掉的,这种相对来说更安全;

FROM实例:

[root@Docker-node1 /]# mkdir /dockerfile_image                  创建Dockerfile的专用工作目录
[root@Docker-node1 /]# vim /dockerfile_image/Dockerfile         #编写Dockerfile文件
#Destscription: Test Image             #Dockerfile文件描述信息
FROM busybox:latest                     #Syntax1的实例
FROM busybox@hash                       #Syntax2的实例指定hash码

MAINTAINER

用于让Dockerfile制作者提供本人的信息,一般为姓名加邮箱,Dockerfile不限制MAINTAINER的出现位置,但推荐放到FROM指令之后

Syntax:

MAINTAINER <authtor's detail>
<authtor's detail>可以是任何文本信息,但一般都是用作者名称以及邮件地址

MAINTAINER实例:

[root@Docker-node1 /]# cat /dockerfile_image/Dockerfile 
#Destscription: Test Image
FROM busybox:latest
#FROM busybox@hash
MAINTAINER "xuwl<755528357@qq.com>"             #指定作者信息

LABEL

LABEL和MAINTAINER是一种类型的指令,但LABEL比MAINTAINER可以支持更多的详细信息,LABEL可以让你指定很多的元数据,元数据都是由键和值组成

Syntax:

LABEL <key>=<value><key>=<value><key>=<value><key>=<value>.......可以指定多个

LABEL实例:

[root@Docker-node1 /]# cat /dockerfile_image/Dockerfile 
#Destscription: Test Image
FROM busybox:latest
#FROM busybox@hash
MAINTANIER "xuwl<755528357@qq.com>"
LABEL name="xuwl" mail="755528357@qq.com"                       #可以作为键值来写

COPY

用于从宿主机复制文件到新创建的镜像文件

Syntax:

Syntax1:COPY <src>...<dest>
<src>:要复制的源文件或者目录,支持使用通配符;
<dest>:目标路径,即正在创建的image的文件系统路径;建议为<dest>使用绝对路径,否则,COPY指定则以WORKDIR工作路径为其起始路径;
文件复制准则:
如果<src>是目录,则其内部文件或子目录会被递归复制,但<src>目录自身不会被复制,只会复制其目录下的所有文件及子目录;
如果指定了多个<src>,或在<src>中使用了通配符,则<dest>必须是一个目录,且必须以/结尾;
如果<dest>事先不存在,它将会被自动创建,这包括其父目录路径

Syntax2:COPY [“<src>”…”<dest>”]
如果路径中有空白字符,通常使用第二种格式

COPY实例:

[root@Docker-node1 /]# echo 'Dockerfile container images busybox!' >  /dockerfile_image/index.html
[root@Docker-node1 /]# cp -rf /etc/yum.repos.d/ /dockerfile_image/
[root@Docker-node1 /]# cat /dockerfile_image/Dockerfile 
#Destscription: Test Image
FROM busybox:latest
#FROM busybox@hash
MAINTANIER "xuwl<755528357@qq.com>"
LABEL name="xuwl" mail="755528357@qq.com"
COPY index.html /data/web/html/
COPY yum.repos.d /usr/local/src/
[root@Docker-node1 dockerfile_image]# docker build -t busybox:v0.1 ./       #docker build制作镜像,-t指定制作的镜像名称及标签
Sending build context to Docker daemon  24.06kB
Step 1/5 : FROM busybox:latest
 ---> 59788edf1f3e
Step 2/5 : MAINTAINER "xuwl<755528357@qq.com>"
 ---> Running in 1a1f9144b5a5
Removing intermediate container 1a1f9144b5a5
 ---> ee3a1322199a
Step 3/5 : LABEL name="xuwl" mail="755528357@qq.com"
 ---> Running in e4454b62ece7
Removing intermediate container e4454b62ece7
 ---> b08f463a84f4
Step 4/5 : COPY index.html /data/web/html/
 ---> 47d18264dbe5
Step 5/5 : COPY yum.repos.d /usr/local/src/
 ---> b7ffca3f0c9a
Successfully built b7ffca3f0c9a
Successfully tagged busybox:v0.1
[root@Docker-node1 dockerfile_image]# docker image ls           #查看制作好的镜像为busybox:v0.1
REPOSITORY          TAG                 IMAGE ID            CREATED              SIZE
busybox             v0.1                b7ffca3f0c9a        About a minute ago   1.17MB
redis               latest              1babb1dde7e1        3 weeks ago          94.9MB
tomcat              latest              05af71dd9251        3 weeks ago          463MB
nginx               latest              dbfc48660aeb        3 weeks ago          109MB
busybox             latest              59788edf1f3e        5 weeks ago          1.15MB
[root@Docker-node1 dockerfile_image]# docker run -it --rm --name busyboxweb1 busybox:v0.1  #启动镜像并查看是否COPY到相应目录
/ # ls /usr/local/src/  #上面我们有说过COPY指令,如果COPY目录,它将会COPY除了此目录以下的所有子目录及文件到dest中
CentOS-Base.repo       CentOS-Debuginfo.repo  CentOS-Sources.repo    CentOS-fasttrack.repo
CentOS-CR.repo         CentOS-Media.repo      CentOS-Vault.repo      docker-ce.repo
/ # cat /data/web/html/index.html 
Dockerfile container images busybox!

ADD

ADD指令类似于COPY指令,ADD支持使用tar文件和URL路径

Syntax:

Syntax1:ADD <src>…<dest>
操作准则:同COPY指令
如果<src>为URL且<dest>不以/结尾,则<src>指定的文件将被下载并直接被创建为<dest>;
如果<dest>以/结尾,则文件名URL指定的文件将被直接下载并保存为<dest>/<fukebane>;
如果<src>是一个本地系统上的压缩格式的tar文件,它将被展开为一个目录,其行为类似于”tar -x”命令;然而,如果不是本地的,例如一些网站的tar包,通过URL获取到的tar文件将不会自动展开;

Syntax2:ADD[“<src>”,…”<dest>”]
操作准备:同Syntax1
Syntax2支持向镜像内添加更多的文件

ADD实例:

[root@Docker-node1 dockerfile_image]# wget http://nginx.org/download/nginx-1.15.6.tar.gz
[root@Docker-node1 dockerfile_image]# cat Dockerfile 
#Destscription: Test Image
FROM busybox:latest
#FROM busybox@hash
MAINTAINER "xuwl<755528357@qq.com>"
LABEL name="xuwl" mail="755528357@qq.com"
COPY index.html /data/web/html/
COPY yum.repos.d /usr/local/src/
ADD nginx-1.15.6.tar.gz /usr/local/src/ADD/                                     #本地系统上的tar包,到容器中会自动解压
ADD http://nginx.org/download/nginx-1.15.6.tar.gz /usr/local/src/ADD/           #URL地址,到容器中不会自动展开
[root@Docker-node1 dockerfile_image]# docker build -t busybox:v0.2  ./
Sending build context to Docker daemon  1.051MB
Step 1/7 : FROM busybox:latest
 ---> 59788edf1f3e
Step 2/7 : MAINTAINER "xuwl<755528357@qq.com>"
 ---> Using cache
 ---> ee3a1322199a
Step 3/7 : LABEL name="xuwl" mail="755528357@qq.com"
 ---> Using cache
 ---> b08f463a84f4
Step 4/7 : COPY index.html /data/web/html/
 ---> Using cache
 ---> 47d18264dbe5
Step 5/7 : COPY yum.repos.d /usr/local/src/
 ---> Using cache
 ---> b7ffca3f0c9a
Step 6/7 : ADD nginx-1.15.6.tar.gz /usr/local/src/ADD/
 ---> d75f146eed79
Step 7/7 : ADD http://nginx.org/download/nginx-1.15.6.tar.gz /usr/local/src/ADD/
Downloading [==================================================>]  1.026MB/1.026MB
 ---> 91459c16bd23
Successfully built 91459c16bd23
Successfully tagged busybox:v0.2
[root@Docker-node1 dockerfile_image]# docker run -it --rm --name busybox_web2 busybox:v0.2
/ # ls /usr/local/src/ADD/
nginx-1.15.6         nginx-1.15.6.tar.gz                        #可以看到本地ADD的已经被展开,URL下来的不会被自动展开

WORKDIR

用于设定Dockerfile中的所有RUN、CMD、ENTRYPOINT、COPY和ADD指定的工作目录

Syntax:

WORKDIR <DIRPATH>
在Dockerfile文件中,WORKDIR指令可出现多次,每指定的一次只影响下次指定WORKDIR之前的指令 
另外,WORKDIR也可以调用由ENV指定定义的变量

WORKDIR实例:

[root@Docker-node1 dockerfile_image]# cat Dockerfile 
#Destscription: Test Image
FROM busybox:latest
#FROM busybox@hash
MAINTAINER "xuwl<755528357@qq.com>"
LABEL name="xuwl" mail="755528357@qq.com"
COPY index.html /data/web/html/
COPY yum.repos.d /usr/local/src/
ADD nginx-1.15.6.tar.gz /usr/local/src/ADD/
ADD http://nginx.org/download/nginx-1.15.6.tar.gz /usr/local/src/ADD/
WORKDIR /workdir/                   #在此指定工作目录为/workdir
ADD nginx-1.15.6.tar.gz ./          #这里 ./ 当前目录就是引用了上面所指定的WORKDIR指定的目录位置
[root@Docker-node1 dockerfile_image]# docker build -t busybox:v0.3  ./
[root@Docker-node1 dockerfile_image]# docker run -it --name busybox_web busybox:v0.3
/workdir # ls /workdir/             #查看指定的WORKDIR目录是否生效
nginx-1.15.6

WORKDIR调用ENV指定定义变量实现
修改Dockerfile
ENV WORKDIRECTORY=/usr/local/nginx/
WORKDIR $WORKDIRECTORY
ADD nginx-1.15.6.tar.gz ./

VOLUME

用于在镜像中创建一个挂载点目录,以挂载Docker host上的卷或其它容器上的卷;
挂载卷有两种方式,

  1. bind Mount volume 绑定挂载卷
  2. docker-manege docker管理卷
    但是在Dockerfile中的VOLUME指令只能使用第二种docker管理卷,指定镜像内的挂载点,宿主机内的共享目录自动创建

Syntax:

Syntax1:VOLUME <mountpoint>
如果挂载点目录路径下此前文件存在,docker run命令会在卷挂在完成后将此前所有文件复制到新挂载的卷中
Syntax2:VOLUME[“<mountpoint>”]

VOLUME实例:

[root@Docker-node1 dockerfile_image]# cat Dockerfile 
#Destscription: Test Image
FROM busybox:latest
#FROM busybox@hash
MAINTAINER "xuwl<755528357@qq.com>"
LABEL name="xuwl" mail="755528357@qq.com"
COPY index.html /data/web/html/
COPY yum.repos.d /usr/local/src/
ADD nginx-1.15.6.tar.gz /usr/local/src/ADD/
ADD http://nginx.org/download/nginx-1.15.6.tar.gz /usr/local/src/ADD/
ENV WORKDIRECTORY=/usr/local/nginx/
WORKDIR $WORKDIRECTORY
ADD nginx-1.15.6.tar.gz ./
VOLUME /data/volume/                        #指定制作镜像是的存储卷挂载点目录
[root@Docker-node1 dockerfile_image]# docker build -t busybox:v0.4  ./
[root@Docker-node1 dockerfile_image]# docker run -it --name busybox_web4 busybox:v0.4
/usr/local/nginx # mount | grep /data/volume                #查看挂载点
/dev/mapper/centos-root on /data/volume type xfs (rw,relatime,attr2,inode64,noquota)
/usr/local/nginx # exit
[root@Docker-node1 dockerfile_image]# docker start busybox_web4
[root@Docker-node1 dockerfile_image]# docker inspect  busybox_web4 | grep Source                            #使用inspect查看容器的元数据的共享目录
                "Source": "/var/lib/docker/volumes/8858c1d20913d3d11871984bc55421cfd509dab04cd3b316b9f851479a93cc92/_data",

EXPOSE

用于为容器打开指定要监听的端口以实现与外部通信,对外暴露的端口

Syntax:

EXPOSE <post>[/<protocol>][<port>[/<protocol>]…]
<protocol>用于指定传输层协议,可为tcp或udp二者之一,默认为TCP协议
EXPOSE一次可以指定多个指令
但无法像docker -p 命令一样指定映射到宿主机的哪个端口,仅能指定此镜像暴露什么端口,然后动态绑定到宿主机的某个端口和所有网卡;
虽然在dockerfile中指定过了暴露的端口,但如果启动镜像的时候不加 -P选项,那么容器端口会成为一个待暴露状态,并不是正真的暴露;

EXPOSE实例:

[root@Docker-node1 dockerfile_image]# cat Dockerfile 
#Destscription: Test Image
FROM busybox:latest
#FROM busybox@hash
MAINTAINER "xuwl<755528357@qq.com>"
LABEL name="xuwl" mail="755528357@qq.com"
COPY index.html /data/web/html/
COPY yum.repos.d /usr/local/src/
ADD nginx-1.15.6.tar.gz /usr/local/src/ADD/
ADD http://nginx.org/download/nginx-1.15.6.tar.gz /usr/local/src/ADD/
ENV WORKDIRECTORY=/usr/local/nginx/
WORKDIR $WORKDIRECTORY
ADD nginx-1.15.6.tar.gz ./
VOLUME /data/volume/
EXPOSE 80/udp 80/tcp                                #指定对外暴露的端口和协议
[root@Docker-node1 dockerfile_image]# docker build -t busybox:v0.5  ./
[root@Docker-node1 dockerfile_image]# docker run -it --name busybox_web5 busybox:v0.5
/usr/local/nginx # exit
[root@Docker-node1 dockerfile_image]# docker start busybox_web5
[root@Docker-node1 dockerfile_image]# docker exec busybox_web5 httpd /data/web/html
[root@Docker-node1 dockerfile_image]# docker port busybox_web5          #当我们查看端口的时候是没有的,上面已经说了如果运行的时候不加 -P选项,那么容器端口会是一个伪暴露状态,并不是正真的暴露

重新制作容器启动时加-P选项,也可以直接在原有的镜像上加-P启动
[root@Docker-node1 dockerfile_image]# docker build -t busybox:v0.6  ./
[root@Docker-node1 dockerfile_image]# docker run -itd --name busybox_web6 -P  busybox:v0.6 
f10b03a8a4aa704416383b580402cba12756ddda0a8d2a6cf88e11e58104dcd6
[root@Docker-node1 dockerfile_image]# docker exec busybox_web6 httpd /data/web/html
[root@Docker-node1 dockerfile_image]# docker port busybox_web6
80/udp -> 0.0.0.0:32768
80/tcp -> 0.0.0.0:32768

ENV

用于为镜像定义所需的环境变量,并可被Dockerfile文件中位于其后的其它指令(如ENV、ADD、COPY等)所调用,调用格式为$variable_name或${variable_name}

Syntax:

Syntax1:ENV <key><value>
语法一中,<key>之后的所有内容均会被视作其<value>的组成部分,因此,一次只能设置一个变量

Syntax2:ENV <key>=<value>
语法二中:可用一次设置多个变量,每个变量为一个”<key>=<value>”的键值对,如果<value>中包含空格,可以使用反斜线()进行转义,也可通过对<value>加引号进行标识;另外反斜线也可以用来换行;
定义多个变量时,建议使用第二种格式,以便在同一层中完成所有功能

ENV实例:
第一种语法:

[root@Docker-node1 dockerfile_image]# grep -Ev "#|^

quot; Dockerfile FROM busybox:latest MAINTAINER "xuwl<755528357@qq.com>" LABEL name="xuwl" mail="755528357@qq.com" ENV DOC_ROOT /data/web/html/ COPY index.html ${DOC_ROOT:-/data/web/html/} [root@Docker-node1 dockerfile_image]# docker build -t busybox:v0.7 ./ [root@Docker-node1 dockerfile_image]# docker run --rm -it --name busybox_web7 busybox:v0.7 / # cat /data/web/html/index.html Dockerfile container images busybox! 

第二种语法:

[root@Docker-node1 dockerfile_image]# grep -Ev "#|^

quot; Dockerfile FROM busybox:latest MAINTAINER "xuwl<755528357@qq.com>" LABEL name="xuwl" mail="755528357@qq.com" ENV DOC_ROOT=/opt/web/html/ #定义变量,换行使用 反撇号 DOCKERFILE=/usr/local/src/ WEB_SERVER_PACKAGE="nginx-1.15.6.tar.gz" #最后一行一定不要加 反撇 COPY index.html $DOC_ROOT ADD $WEB_SERVER_PACKAGE $DOCKERFILE [root@Docker-node1 dockerfile_image]# docker build -t busybox:v0.8 ./ [root@Docker-node1 dockerfile_image]# docker run -it --name busybox_web8 --rm busybox:v0.8 / # cat /opt/web/html/index.html Dockerfile container images busybox! / # ls /usr/local/src/ nginx-1.15.6 

扩展知识

从Dockerfile到container为两个过程
由Dockerfile制作Images为第一过程,在第一次过程中我们在Dockerfile文件中制作的任何指令到了第二过程中,也就是从Images启动到container是都可以被命令替换掉
例如我们在Dockerfile中指定的env,我们在使用docker build时就可以使用env选项给替换掉

扩展实例:

[root@Docker-node1 dockerfile_image]# docker run --name busybox_web10 busybox:v0.8 printenv                     #printenv选项显示busybox:v0.8镜像内的所有环境变量
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=39a71d5c6d39
DOC_ROOT=/opt/web/html/
DOCKERFILE=/usr/local/src/
WEB_SERVER_PACKAGE=nginx-1.15.6.tar.gz
HOME=/root
[root@Docker-node1 dockerfile_image]# docker run --name busybox_web10 --rm -e WEB_SERVER_PACKAGE=nginx-1.15.10.tar.gz busybox:v0.8 printenv   #-e选项相当于--env,修改变量的值并输出所有变量
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=a0756bcf7028
WEB_SERVER_PACKAGE=nginx-1.15.10.tar.gz
DOC_ROOT=/opt/web/html/
DOCKERFILE=/usr/local/src/
HOME=/root
注意: 虽然我们已经替换了WEB_SERVER_PACKAGE的值,但是仅仅是把值该掉了,也就是改掉了nginx的版本号,这是在docker run的时候为第二阶段,并不会把docker build第一阶段时我们所指定的nginx源tar包给替换掉,当docker run之后,只不过我们在nginx包目录中看到的不是docker Build的版本,而是docker run -e所指定的版本,只是修改了名称,但nginx包实际的版本并没有修改,这是env变量设置,但如果是指令指定的命令的话,是可以起到配置变换的作用的

RUN

用于指定Docker build过程中运行的程序,其可以是任何命令

Syntax:

Syntax1:RUN <command>
语法一中<command>通常是一个shell命令,且以”/bin/sh -c”来运行它,这意味着此进程在容器中的PID不为1,不能接收Unix信号,因此,当使用docker stop <container>命令停止容器时,此进程接收不到SIGTERM信号

Syntax2:RUN ["<executable>","<param1>","<param2>"]
语法二中的参数是一个JSON格式的数组,其中<executable>为要运行的命令,后面的<paramN>为传递给命令的选项或参数;然而,此种格式指定的命令不会以”/bin/sh -C”来发起,那么它就是由内核直接拉起,然后进程为1,但由于剥离了shell,因此常见的shell操作如变量替换以及通配符(?.*等)替换符不会进行;不过,如果要运行的命令依赖此shell特性的话,可以将其替换为类似下面的格式:
RUN [“/bin/bash”,”-c”,”<executable>”,”<param1>”]

RUN实例:

[root@Docker-node1 dockerfile_image]# grep -Ev "#|^

quot; Dockerfile FROM busybox:latest MAINTAINER "xuwl<755528357@qq.com>" LABEL name="xuwl" mail="755528357@qq.com" ENV DOC_ROOT=/opt/web/html/ DOCKERFILE=/usr/local/src/ WEB_SERVER_PACKAGE="nginx-1.15.6.tar.gz" COPY index.html /opt/web/html/ ADD $WEB_SERVER_PACKAGE $DOCKERFILE #本地文件过去自动展开 RUN cd $DOCKERFILE/nginx-1.15.6 && ./configure && make && make install echo $? [root@Docker-node1 dockerfile_image]# docker build -t busybox:v10 ./ #开始制作镜像,由于我镜像内没有安装gcc环境,所以报错了,按照这个思路往下装是没有问题的 

CMD

类似于RUN指令,CMD指令也可用于运行命令或者应用程序;
不过,二者的运行时间点不同,RUN指令运行于映像文件构建过程中,而CMD指令运行于基于Dockerfile构建出的新映像文件启动一个容器时;
RUN命令运行在docker build过程;
CMD运行在docker run过程;
CMD指令的首要目的在于为启动的容器指定默认要运行的程序,且其运行结束后,容器也将终止;不过,CMD指令的命令可以被docker run的命令行选项所覆盖;
在Dockerfile中可以存多个CMD指令,但仅最后一个会生效

Syntax:

Syntax1:CMD <command>
这种语法和RUN的第一种语法一致,进程ID都不为1,都是依赖shell进程所托起,也不能接收Unix信号,docker stop命令对此没用

Syntax2:CMD[“<executable>”,”<param1>”,”<param2>”]
这种语法和RUN的第二种语法一致,进程ID为1,所以可处理和接收Unix信号

Syntax3:CMD [“<param1>”,”<param2>”]
这是第三种语法:给出<param1><param2>只有参数没有命令,此种语法需要结合另外一个指令ENTRYPOINT指令提供默认参数才能使用

CMD实例:

Syntax1:CMD <command>
CMD的第一种格式,也就是由shell父进程所托起,因此也能使用shell里面所有的变量以及通配符
[root@Docker-node1 dockerfile_image]# cat Dockerfile 
FROM busybox:latest
LABEL name="xuwl" mail="755528357@qq.com"
ENV WEB_DOC_ROOT="/data/web/html/"
RUN mkdir -p ${WEB_DOC_ROOT:-/data/web/html} && 
    echo '<h1>Busybox container web2.0</h1>' > ${WEB_DOC_ROOT}/index.html
CMD /bin/httpd -f -h ${WEB_DOC_ROOT}                        #我们直接启动/bin/httpd进程
[root@Docker-node1 dockerfile_image]# docker build -t busybox:web2.0 ./
[root@Docker-node1 dockerfile_image]# docker run -it --name busybox_web2.0 --rm busybox:web2.0    #运行容器后你会发现卡在这里了,因为我们直接去启动了/bin/httpd,-it选项为分配一个伪终端,并进入交互式,而/bin/httpd哪有什么交互式接口
我们再打开一个ssh窗口
[root@Docker-node1 ~]# docker ps        #发现容器运行的命令并不是shell而是 /bin/httpd,为shell的子进程
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
1e2ceded5b8c        busybox:web2.0      "/bin/sh -c '/bin/ht…"   3 minutes ago       Up 3 minutes                            busybox_web2.0
[root@Docker-node1 ~]# docker exec -it busybox_web2.0 /bin/sh               #在第二个ssh连接内进入容器
/ # ps
PID   USER     TIME  COMMAND
    1 root      0:00 /bin/httpd -f -h /data/web/html/                       #会发现你的/bin/httpd的PID显示为1,因为我们使用exec命令把进程启动给改掉了,在我们制作镜像的时候它确实是在shell下所拉起,为shell的子进程,但我们使用exec命令的时候改掉了这个
    6 root      0:00 /bin/sh
   11 root      0:00 ps
Syntax2:CMD[“<executable>”,”<param1>”,”<param2>”]
这种语法和RUN的第二种语法一致,进程ID为1,所以可处理和接收Unix信号,但它不是由shell所托起,理论上讲是不能使用变量以及通配符的
不使用通配符格式:CMD [“bin/httpd”.”-f”,”-h /data/web/html”]         #把所有的变量全部替换为变量值
使用通配符格式:CMD [“/bin/sh,”-c””“bin/httpd”.”-f”,”-h /data/web/html”]     #加上 /bin/sh -c,表示还是基于shell进程,然后可以使用变量和通配符
[root@Docker-node1 dockerfile_image]# cat Dockerfile 
FROM busybox:latest
LABEL name="xuwl" mail="755528357@qq.com"
ENV WEB_DOC_ROOT="/data/web/html/"
RUN mkdir -p ${WEB_DOC_ROOT:-/data/web/html} && 
    echo '<h1>Busybox container web2.0</h1>' > ${WEB_DOC_ROOT}/index.html
#CMD /bin/httpd -f -h ${WEB_DOC_ROOT}
CMD ["/bin/sh","-c","/bin/httpd","-f","-h ${WEB_DOC_ROOT}"]                 #使用通配符格式
[root@Docker-node1 dockerfile_image]# docker build -t busybox:web2.1 ./
[root@Docker-node1 dockerfile_image]# docker image inspect busybox:web2.1 | grep CMD
                "CMD ["/bin/sh" "-c" "/bin/httpd" "-f" "-h ${WEB_DOC_ROOT}"]"               #看到我们此镜像是由/bin/sh -c之上所运行的/bin/httpd指令,如果是以不使用通配符格式的就会显示以/bin/httpd指令运行
Syntax3:CMD [“<param1>”,”<param2>”]   语法三结合ENTRYPOINT来结合使用

ENTRYPOINT

1.类似CMD指令功能,用于为容器指定默认运行程序,从而使得容器像是一个单独的可执行的程序
2.与CMD不同的是,由ENTRYPOINT启动的程序不会被docker run 命令行指定的参数所覆盖,而且,这些命令行参数会被当做参数传递给ENTRYPOINT指定的程序
3.docker run命令的—entrypoint选项的参数可覆盖ENTRYPOINT,指令指定的程序
4.docker run 命令传入的命令参数会覆盖CMD指令的内容并且附加到ENTRYPOINT命令最后作为其参数使用
5.Dockerfile文件中也可以存在多个ENTRYPOINT指令,但仅有最后一个生效

Syntax:

Syntax1:ENTRYPOINT <command>
ENTRYPOINT加需要执行的命令
Syntax2:ENTRYPOINT [”<executable>”,”<param1>”,”<param2>”]
语法二的ENTRYPOINT一般结合CMD的第三种语法使用,CMD的第三种语法所指定的指令作为ENTRYPOINT第二种语法的参数使用

ENTRYPOINT实例:

Syntax1:ENTRYPOINT <command>
[root@Docker-node1 dockerfile_image]# cat Dockerfile 
FROM busybox:latest
LABEL name="xuwl" mail="755528357@qq.com"
ENV WEB_DOC_ROOT="/data/web/html/"
RUN mkdir -p ${WEB_DOC_ROOT:-/data/web/html} && 
    echo '<h1>Busybox container web2.0</h1>' > ${WEB_DOC_ROOT}/index.html
#CMD /bin/httpd -f -h ${WEB_DOC_ROOT}
#CMD ["/bin/sh","-c","/bin/httpd","-f","-h ${WEB_DOC_ROOT}"]
ENTRYPOINT /bin/httpd -f -h ${WEB_DOC_ROOT}

[root@Docker-node1 dockerfile_image]# docker build -t busybox_entrypoint_v1 ./
[root@Docker-node1 dockerfile_image]# docker run -it --name busybox_entrypoint_v1  busybox:web2.2 ls /opt/web/html      #当运行容器时,我们执行ls /opt/web/html,但这条命令并不会执行,因为此命令不能覆盖Dockerfile所指定ENTRYPOINT运行的指令

--entrypoint选项来覆盖Dockerfile中的ENTRYPOINT
[root@Docker-node1 dockerfile_image]# docker run -it --name busybox_entrypoint_v2  --entrypoint pwd busybox:web2.2
/                       #我们上面Dockerfile中定义了ENTRYPOINT指令执行 /bin/httpd ,但是在Docker run的过程中,我们使用--entrypoint command覆盖掉了Dockerfile文件中的内容
Syntax2:ENTRYPOINT [”<executable>”,”<param1>”,”<param2>”]
[root@Docker-node1 dockerfile_image]# cat Dockerfile 
FROM busybox:latest
LABEL name="xuwl" mail="755528357@qq.com"
ENV WEB_DOC_ROOT="/data/web/html/"
RUN mkdir -p ${WEB_DOC_ROOT:-/data/web/html} && \
    echo '<h1>Busybox container web2.0</h1>' > ${WEB_DOC_ROOT}/index.html
CMD ["/bin/httpd","-f","-h ${WEB_DOC_ROOT}"]            #CMD的第三种语法,直接启动/bin/httpd,这个时候它是直接由内核所托起,主进程为/bin/httpd而不是/bin/sh
ENTRYPOINT ["bin/sh","-c"]                              #上面的CMD指令所指定的命令作为此ENTRYPOINT的参数使用,所以还相当于CMD指令指定的命令运行在了/bin/sh中
[root@Docker-node1 dockerfile_image]# docker build -t busybox_entrypoint_v2 ./
[root@Docker-node1 dockerfile_image]# docker image inspect busybox_entrypoint_v2
以下内容只截取了摘要信息
            "Cmd": [                                            #在此可以看到CMD运行的是/bin/httpd
                "/bin/httpd",
                "-f",
                "-h ${WEB_DOC_ROOT}"
            ],
            "ArgsEscaped": true,
            "Image": "sha256:421cb8ad11f90f88077b64fd8456b9fd3bcc590c6e776e5fcc2acd60d0ca4c6e",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": [                                     #ENTRYPOINT运行的是/bin/sh,但CMD运行的命令是要被ENTRYPOINT当做参数使用
                "bin/sh",
                "-c"
            ],

[root@Docker-node1 dockerfile_image]# docker run -it --name busybox_entrypoint_v3  busybox_entrypoint_v2
[root@Docker-node1 dockerfile_image]# docker ps -a                      #在此可以看到容器运行的是/bin/sh -c /bin/httpd
CONTAINER ID        IMAGE                   COMMAND                  CREATED             STATUS                      PORTS               NAMES
5402e3609e9c        busybox_entrypoint_v2   "bin/sh -c /bin/http…"   17 seconds ago      Exited (0) 16 seconds ago                       busybox_entrypoint_v3

CMD所指定的指令是为ENTRYPOINT默认的参数,如果我们在docker run过程中指定了运行的指令,那么就会覆盖掉CMD所指定的参数,例如我们下面所运行的ls /usr就会当做参数传递给ENTRYPOINT

[root@Docker-node1 dockerfile_image]# docker run -it --name busybox_entrypoint_v4  busybox_entrypoint_v2  "ls /usr"
sbin

USER

用于指定运行image时的或者运行Dockerfile中任何RUN、CMD或者ENTRYPOINT指令指定的程序时的用户名或者UID
默认情况下,container的运行身份是root

Syntax:

Syntax1:
        USER <UID>
指定用户的UID号,此UID号必须在/etc/passwd内存在

Syntax2:
        USER <USERNAME>
直接指定用户名
```bash

####HEALTHCHECK
健康检查
HEALTHCHECK指令告诉Docker如何测试容器以检查它是否仍在工作
即使服务器进程仍在运行,假如一个Web服务器,它进行仍在,但是404等错误,这个时候就需要结合其它命令工具来进行实时监控

**Syntax:**
```bash
Syntax1:
HEALTHCHECK [OPTlONS]
HEALTHCHECK加选项;HEALTHCHECK结合命令工具来检查容器的运行状况,例如运行了一个web应用,在容器内运行curl来监控它的首页状态
Syntax2:
HEALTHCHECK NONE
禁止所有监控检测,包括应用默认的监控检测
OPTIONS:
--interval=DURATION(default:30s):健康检测间隔时间,默认为30秒
--timeout=DURATION(default:30s):超时时间,默认为30秒
--start-period=DURATION(default:0s):默认为0秒意思为容器刚启动就开始进行监控检查,一般要把时间改到5-10秒,容器启动,容器内的应用启动还需要进行初始化等等
--retries=N(default:3):连续检测几次失败则认为问题,默认为3次

检测返回码:
0:success 成功
1:unhealthy:不健康
2:预留,可自定义返回2状态码的意义

HEALTHCHECK实例:

vim Dockerfile
HEALTHCHECK –interval=30s –timeout=30s –start-period=15s –retries=3 \
    CMD curl -f http://localhost/ || exit 1

ARG

ARG指令雷同与ENV指令,区别在于ARG指令在docker build过程中也就是第一阶段中运行,ENV在docker run 第二阶段中运行
ARG指令使用-build-arg = 标志定义一个变量,用户可以使用docker build命令在构建时将该变量传递给构建器
如果想要在docker build过程中使用ARG指令,就必须在Dockerfile中使用该指令,否则会输出警告
Dockerfile可以包括一个或多个ARG指令

Syntax:

Syntax:ARG <name>[=<default value>]
ARG 变量名称=值

ARG实例:

docker build --build-arg author=”pony 111@qq.com” =”1.15-alpine” -it –name myweb:v0.3-9 ./
docker image inspect myweb:v0.3-9 查看镜像相信信息
会发现已经Dockerfile中定义的ARG已经被替换

ONBUILD

用于在Dockerfile中定义一个触发器
Dockerfile用于build映像文件,此映像文件亦可作base image被另一个Dockerfile用于FROM指令的参数,并以之构建新的映像文件
在后面的这个Dockerfile中的FROM指令在build过程中被执行时,将会“触发”创建其base image的Dockerfile文件中的ONBUILD指令定义的触发器

Syntax:

ONBUILD<INSTRUCTION>
 尽管任何指令都可注册成为触发器指令,但ONBUILD不能自我嵌套,且不会触发FROM和MAINTAINER指令
 使用包含ONBUILD指令的Dockerfile构建的镜像应该使用特殊的标签,例如ruby:2.0-onbuild
 在ONBUILD指令中使用ADD或者COPY指令应该格外小心,因为新构建过程的上下文在缺少指定的源文件时会失败

人已赞赏
0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
有新消息 消息中心
搜索