1  概述

基于容器制作镜像的问题是,每次都要启动一个容器,在容器内部执行相关命令,才进行制作容器,这个比较麻烦。还有一种情况,可能是制作后的容器,容器变得很庞大,用户拷贝也可能成问题,如果通过dockerfile,相当于是一个文档,客户可以基于dockerfile生成新的容器

dockerfile仅仅是用来制作镜像的源码文件,是构建容器过程中的指令,docker能够读取dockerfile的指定进行自动构建容器,基于dockerfile制作镜像,每一个指令都会创建一个镜像层,即镜像都是多层叠加而成,因此,层越多,效率越低,创建镜像,层越少越好。因此能在一个指令完成的动作尽量通过一个指令定义。

docker镜像制作的工作逻辑

首先需要有一个制作镜像的目录,该目录下有个文件,名称必须为Dockerfile,Dockerfile有指定的格式,#号开头为注释,,指定默认用大写字母来表示,以区分指令和参数,docker build读取Dockerfile是按顺序依次Dockerfile里的配置,且第一条非注释指令必须是FROM 开头,表示基于哪个基础镜像来构建新镜像。可以根据已存在的任意镜像来制作新镜像。

Dockerfile可以使用环境变量,用ENV来定义环境变量,变量名支持bash的变量替换,如${variable:-word},表示如果变量值存在,就使用原来的变量,变量为空时,就使用word的值作为变量的值,一般使用这个表示法。

${variable:+word},表示如果变量存在了,不是空值,那么变量将会被赋予为word对应的值,如果变量为空,那么依旧是空值

.dcokerignore:把文件路径写入到.dockerignore,对应的路径将不会被打包到新镜像

2  指令介绍

FROM 

 FROM指令是最重的一个且必须为 Dockerfile文件开篇的第一个非注释行,用于为映像文件构建过程指定基准镜像,后续的指令运行于此基准镜像所提供的运行环境 .

实践中,基准镜像可以是任何可用镜像文件,默认情况下, docker build会在 docker主机上查找指定的镜像文件,在其不存在时,则会从 Docker Hub Registry上拉取所需的镜像文件 .如果找不到指定的镜像文件, docker build会返回一个错误信息

FROM 语法

FROM <repository>[:<tag>] 或者 FROM <repository>@<digest>

<repository>:指定作为base image的名称

 <tag>base image的标签,为可选项,省略时默认为 latest

<digest>为校验码


MAINTANIER

用于让镜像制作者提供本人的详细信息

Dockerfile并不限制 MAINTAINER指令可在出现的位置,但推荐将

其放置于 FROM指令之后 .

语法:

MAINTAINER  <authtor's detail> l <author's detail>可是任何文本信息,但约定俗成地使用作者名称及邮件地址,如

MAINTAINER "sunny <sunny@ghbsunny.cn>"

一般把MAINTAINER放在FROM后面


COPY

用于从 Docker主机复制文件至创建的新映像文件

语法

COPY <src> ... <dest> . COPY ["<src>",... "<dest>"]

<src>:要复制的源文件或目录,支持使用通配符

 <dest>:目标路径,即正在创建的 image的文件系统路径;建议为 <dest>使用绝对路径,<dest>绝对路径为镜像中的路径,而不是宿主机的路径。否则, COPY指定则以 WORKDIR为其起始路径

注意:在路径中有空白字符时,通常使用第二种格式 .

文件复制准则

<src>必须是build上下文中的路径,即只能放在workshop这个工作目录下,不能是其父目录中的文件

如果<src>是目录,其内部文件或者子目录会被递归复制,但<src>目录自身不会被复制

如果指定了多个<src>,或在<src>中使用了通配符,则<dest>必须是一个目录,且dest目录必须以/结尾

如果<dest>事先不存在,它将会被自动创建,这包括其父目录路径

copy是指在当前的workshop工作目录中,准备好要添加到新镜像的文件放到这个workshop下面,copy过程实际是基于dockerfile在后台启动一个容器,把工作目录当做卷挂载到后台启动的容器,然后再把这些准备好的文件(workshop目录下)拷贝到后台容器,然后基于这个容器制作新镜像,所以,镜像的制作过程是基于指定的镜像来制作

例子

创建一个目录workshop,在该目录下新建index.html文件用于镜像制作的素材文件,在workshop下新建Dockerfile文件,把index.html拷贝到新镜像里

 

[root@docker ~]# mkdir workshop
[root@docker ~]# cd workshop/
[root@docker workshop]# vim index.html
[root@docker workshop]# vim Dockerfile
FROM busybox:1.27.2
 
MAINTAINER "sunny <sunny@ghbsunny.cn>"
 
COPY index.html  /data/htdocs/
COPY yum.repos.d /etc/yum.repos.d/

Dockerfile制作完成后,用命令build制作基于dockerfile的新镜像。命令如下

[root@docker workshop]# docker build -t sunnydocker01:v1 ./

查看

docker images

查看到生成了一个新镜像sunnydocker01

启动新生成的镜像,在容器内部有目录/data/htdocs,并且有文件index.html,且成功拷贝/etc/yum.repos.d这个目录到新镜像中

[root@docker workshop]# docker run -it --rm --name sunny01 sunnydocker01:v1

/ # ls

bin   data  dev   etc   home  proc  root  sys   tmp   usr   var

/ # ls data/htdocs/

index.html

/ # ls /etc/yum.repos.d/

CentOS-Base.repo   docker-ce.repo     epel.repo

bak/               epel-testing.repo  sunny.repo

/ # ls /etc/yum.repos.d/

ADD 

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

语法

. ADD <src> ... <dest>

. ADD ["<src>",... "<dest>"]

.操作准则 .

COPY指令的4点准则

 如果<src>URL<dest>不以/结尾,则<src>指定的文件将被下载并直接被创建为<dest>;如果<dest>/结尾,则文件名URL指定的文件将被直接下载,并保存为<dest>/<filename>,注意,URL不能是ftp格式的url

如果<src>是一个本地系统上的压缩格式的tar文件,它将被展开为一个目录,其行为类似于“tar -x”命令,然后,通过URL获取到的tar文件将不会自动展开

如果<src>有多个,或其间接或直接使用了通配符,则<dest>必须是一个以/结尾的目录路径;如果<dest>不以/结尾,则其被视作一个普通文件,<src>的内容将被直接写入到<dest>

例子

在workshop目录下,准备了apache-tomcat-8.0.47.tar.gz 这个tar包,已经从网络上下载一个包,Dockerfile路径如下

[root@docker workshop]# vim Dockerfile

 

FROM busybox:1.27.2

 

MAINTAINER "sunny <sunny@ghbsunny.cn>"

 

COPY index.html  /data/htdocs/

COPY yum.repos.d /etc/yum.repos.d/

 

ADD http://nginx.org/download/nginx-1.14.0.tar.gz /tmp

ADD apache-tomcat-8.0.47.tar.gz /app/tomcat/

制作镜像

[root@docker workshop]# docker build -t test02:v1 ./

基于新镜像启动容器,并检查

[root@docker workshop]# docker run -it --rm --name testadd test02:v1

/ # ls

app   bin   data  dev   etc   home  proc  root  sys   tmp   usr   var

/ # ls /tmp/

nginx-1.14.0.tar.gz

/ # ls /app/tomcat/

apache-tomcat-8.0.47

/ #

注意,此时url对应的nginx已经被下载到/tmp下,且这个nginx的tar包不会被展开,同时目录/app/tomcat/下有一个tomcat目录,为apache-tomcat-8.0.47.tar.gz 展开的目录

 

WORKDIR

workdir为工作目录,指当前容器环境的工作目录,用于为 Dockerfile中所有的 RUNCMDENTRYPOINTCOPY ADD指定设定工作目录

语法

 WORKDIR  <dirpath>

Dockerfile文件中, WORKDIR指令可出现多次,其路径也可以为相对路径,不过,其是相对此前一个 WORKDIR指令指定的路径

另外, WORKDIR也可调用由 ENV指定定义的变量 .例如

WORKDIR /var/log

WORKDIR  $STATEPATH

例子

指定workdir为/usr/local,相当于是容器启动后,会把工作目录切换到/usr/local这个workdir路径下,而不是默认的根目录,如下例子,则相对路径 ./src/ 的绝对路径为容器的/usr/local/src,制作镜像时,把nginx包拷贝到/usr/local/src,把tomcat包解压到/usr/local/src下面

[root@docker workshop]# vim Dockerfile

FROM busybox:1.27.2

 

MAINTAINER "sunny <sunny@ghbsunny.cn>"

 

WORKDIR "/usr/local"

 

ADD http://nginx.org/download/nginx-1.14.0.tar.gz  ./src/

ADD apache-tomcat-8.0.47.tar.gz ./

启动容器并检查

[root@docker workshop]# docker run -it --rm --name testworkdir testworkdir:v1

/usr/local # ls

apache-tomcat-8.0.47  src

/usr/local # ls src

nginx-1.14.0.tar.gz

/usr/local #

容器启动后,工作路径直接切换为/usr/local

 

 

VOLUME

定义卷,只能是docker管理的卷,,VOLUME为容器上的目录,用于在 image中创建一个挂载点目录,以挂载 Docker host上的卷或其它容器上的卷

语法

. VOLUME <mountpoint>

. VOLUME ["<mountpoint>"]

如果挂载点目录路径下此前在文件存在, docker run命令会在卷挂载完成后将此前的所有文件复制到新挂载的卷中

例子

[root@docker workshop]# vim Dockerfile

FROM busybox:1.27.2

 

MAINTAINER "sunny <sunny@ghbsunny.cn>"

 

VOLUME "/test/htdocs"

 

COPY  index.html  /test/htdocs/

制作镜像

[root@docker workshop]# docker build -t testvolume:v1

启动镜像

[root@docker workshop]# docker run -it --rm --name testvolume1 testvolume:v1

/ # ls

bin   dev   etc   home  proc  root  sys   test  tmp   usr   var

/ # ls /test/htdocs/

index.html

/ #

在另外的窗口检查该容器挂载的卷

[root@docker workshop]# docker inspect -f {{.Mounts}} testvolume1

[{volume e87fdd9ab3b8037167e23edb5c4eae3cc7c5d5ffa63c7a4fa4c18173e0e06460 /var/lib/docker/volumes/e87fdd9ab3b8037167e23edb5c4eae3cc7c5d5ffa63c7a4fa4c18173e0e06460/_data /test/htdocs local  true }]

[root@docker workshop]# cd /var/lib/docker/volumes/e87fdd9ab3b8037167e23edb5c4eae3cc7c5d5ffa63c7a4fa4c18173e0e06460/_data

[root@docker _data]# ls

index.html

[root@docker _data]# cat index.html

hello,this is first container made by sunny~

[root@docker _data]#

 

 

EXPOSE

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

语法

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

其中<protocol>用于指定传输层协议,可为 tcpudp二者之一,默认为 TCP协议

EXPOSE指令可一次指定多个端口,但是不能指定暴露为宿主机的指定端口,因为指定的宿主机端口可能已经被占用,因此这里使用随机端口,例如

. EXPOSE 11211/udp 11211/tcp

例子

[root@docker workshop]# vim Dockerfile

FROM busybox:1.27.2

 

MAINTAINER "sunny <sunny@ghbsunny.cn>"

 

VOLUME "/data/htdocs"

 

COPY  index.html  /data/htdocs/

 

EXPOSE 80/tcp

制作镜像

[root@docker workshop]# docker build -t testexpose:v1 ./

启动并暴露端口,注意,启动容器要跟大写P选项-P来暴露

[root@docker workshop]# docker run -it -P --rm --name testexpose testexpose:v1

/ # ls

bin   data  dev   etc   home  proc  root  sys   tmp   usr   var

/ # ls data/htdocs/

index.html

/ #

在其他端口检查80口是否有暴露

[root@docker _data]# docker port testexpose

80/tcp -> 0.0.0.0:32768

[root@docker _data]#

 

 

ENV

ENV用于为镜像定义所需的环境变量,并可被 Dockerfile文件中位于其后的其它指令(如 ENVADDCOPY等)所调用 ,即先定义后调用

调用格式为 $variable_name${variable_name}

语法

ENV <key> <value> . ENV <key>=<value> ... .

第一种格式中, <key>之后的所有内容均会被视作其 <value>的组成部分,因此一次只能设置一个变量

第二种格式,可用一次设置多个变量,每个变量为一个“<key>=<value>”的键值对,如果<value>包含空格,可以以反斜线(\)进行转义,也可通过对<value>加引号进行标识;另外反斜线也可以用于续行;

.定义多个变量时,建议使用第二种方式,以便在同一层中完成所有功能

例子

下载一个nginx包,其中nginx的版本和nginx包的路径用变量替换

编辑Dockerfile

vim Dockerfile

 

FROM busybox:1.27.2

 

MAINTAINER "sunny <sunny@ghbsunny.cn>"

 

ENV nginx_ver=1.14.0

ENV nginx_url=http://nginx.org/download/nginx-${nginx_ver}.tar.gz

 

ADD ${nginx_url} /usr/local/

创建镜像

[root@docker workshop]# docker build -t testenv:v1 ./

运行容器并验证

[root@docker workshop]# docker run -it --rm --name testenv testenv:v1

/ # ls /usr/local/

nginx-1.14.0.tar.gz

/ #

有些变量在运行为容器时依然有用,因此需要把那些变量在运行为容器时重新定义为一个新的值,如果变量很多,可以放到一个文件中进行定义,使用参数 --env-list实现,通过文件来加载环境变量

 

RUN

RUN用于指定 docker build过程中运行的程序,其可以是任何命令,但是这里有个限定,一般为基础镜像可以运行的命令,如基础镜像为centos,安装软件命令为yum而不是ubuntu里的apt-get命令

RUN和CMD都可以改变容器运行的命令程序,但是运行的时间节点有区别,RUN表示在docker build运行的命令,而CMD是将镜像启动为容器运行的命令。因为一个容器正常只用来运行一个程序,因此CMD一般只有一条命令,如果CMD配置多个,则只有最后一条命令生效。而RUN可以有多个。

语法

RUN <command> . RUN ["<executable>", "<param1>", "<param2>"]

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

第二种语法格式中的参数是一个JSON格式的数组,其中<executable>为要运行的命令,后面的<paramN>为传递给命令的选项或参数;然而,此种格式指定的命令不会以“/bin/sh -c”来发起,表示这种命令在容器中直接运行,不会作为shell的子进程,因此常见的shell操作如变量替换以及通配符(?,*等)替换将不会进行,不过,如果要运行的没能力依赖此shell特性的话,可以将其替换为类似下面的格式

RUN ["/bin/bash","-C","<executable>","<paraml>"]

例子

把下载的nginx打包文件,用RUN命令来展开

编辑dockerfile

vim Dockerfile

 

FROM busybox:1.27.2

 

MAINTAINER "sunny <sunny@ghbsunny.cn>"

 

ENV nginx_ver=1.14.0

ENV nginx_url=http://nginx.org/download/nginx-${nginx_ver}.tar.gz

 

WORKDIR "/usr/local/src"

 

ADD ${nginx_url} /usr/local/src/

RUN tar xf nginx-${nginx_ver}.tar.gz

创建镜像

[root@docker workshop]# docker build -t testrun ./

运行容器并验证

[root@docker workshop]# docker run -it --rm --name testrun testrun:latest

/usr/local/src # ls

nginx-1.14.0         nginx-1.14.0.tar.gz

/usr/local/src #

如果RUN的命令很多,就用&&符号连接多个命令,少构建镜像层,提高容器的效率

例子如下

基础镜像为centos,RUN多个命令

由于安装是到互联网上的仓库进行安装,所以,建议把centos的yum源配置为本地,即创建镜像时,把yum的配置有本地仓库源配置在CentOS-Base.repo文件放在workshop下面,配置文件配置ADD拷贝一份到新建镜像的/etc/yum.repos.d目录下,因为经常默认会优先加载CentOS-Base.repo下的包,但是不建议使用这个方法,除非本地仓库有足够的包解决依赖关系,否则建议仅使用默认的即可

编辑dockerfile

[root@docker workshop]# vim Dockerfile

 

FROM centos:7.3.1611

 

MAINTAINER "sunny <sunny@ghbsunny.cn>"

 

ENV nginx_ver=1.14.0

ENV nginx_url=http://nginx.org/download/nginx-${nginx_ver}.tar.gz

 

WORKDIR "/usr/local/src"

 

ADD CentOS-Base.repo  /etc/yum.repos.d/

ADD ${nginx_url} /usr/local/src/

RUN tar xf nginx-${nginx_ver}.tar.gz && yum -y install gcc pcre-devel openssl-devel make \

    && cd nginx-${nginx_ver} && ./configure && make && make install

创建镜像

[root@docker workshop]# docker build -t nginx:v1 ./

运行容器,启动nginx进程

[root@docker workshop]# docker build -t testexpose:v1 ./cc^C

[root@docker workshop]# docker run -it --rm --name nginxv1 nginx:v1

[root@ccedfdf5e63f src]# /usr/local/nginx/sbin/nginx

此时,nginx进程运行于后台,不建议这么做,因为容器的进程要运行于前台模式,否则容器会终止,nginx运行于前台,需要在nginx的配置文件nginx.conf里添加配置项

vi /usr/local/nginx/conf/nginx.conf

daemon off;

这样使得nginx运行于前台

再次运行nginx,则运行于前台

或者通过-g选项,在运行nginx的全局配置模式之后再运行某些参数,注意off后面的冒号

[root@ccedfdf5e63f local]# /usr/local/nginx/sbin/nginx -g "daemon off;"

 

 

CMD 

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

语法

CMD <command>或

CMD ["<executable>","<param1>","<param2>"]或

CMD["<param1>","<param2>"]

.前两种语法格式的意义同 RUN

.第三种则用于为 ENTRYPOINT指令提供默认参数

例子

编译安装nginx,并将镜像的默认命令修改为nginx启动于前台,暴露80口

编辑dockerfile

vim Dockerfile

FROM centos:7.3.1611

 

MAINTAINER "sunny <sunny@ghbsunny.cn>"

 

ENV nginx_ver=1.14.0

ENV nginx_url=http://nginx.org/download/nginx-${nginx_ver}.tar.gz

 

WORKDIR "/usr/local/src"

EXPOSE 80/tcp

ADD ${nginx_url} /usr/local/src/RUN tar xf nginx-${nginx_ver}.tar.gz && yum -y install gcc pcre-devel openssl-devel make \

    && cd nginx-${nginx_ver} && ./configure && make && make install

CMD ["/usr/local/nginx/sbin/nginx","-g","daemon off;"]

制作镜像

[root@docker workshop]# docker build -t nginx:v3 ./

启动容器并测试

[root@docker workshop]# docker run -it --rm --name nginxv3 nginx:v3

测试,容器的ip 为 172.17.0.2,得到nginx的测试页

[root@docker yum.repos.d]# curl 172.17.0.2

查看容器80口被暴露为哪个口

[root@docker yum.repos.d]# docker port nginxv3

80/tcp -> 0.0.0.0:32772

[root@docker yum.repos.d]# curl 10.10.10.72:32772

注意,CMD在dockerfile里写的命令,如果启动容器的命令行里执行命令,则会把dockerfile里的命令覆盖掉,如下,容器启动后,执行/bin/bash,而不是启动nginx于前台

[root@docker workshop]# docker run -it --rm -P --name nginxv3 nginx:v3 /bin/bash

[root@5f2f4b930df3 src]# ss -ntlp

如果dockerfile指定的CMD不允许覆盖,则使用ENTRYPOINT

 

ENTRYPOINT

类似 CMD指令的功能,用于为容器指定默认运行程序,从而使得容器像是一个单独的可执行程序

CMD不同的是,由 ENTRYPOINT启动的程序不会被 docker run命令行指定的参数所覆盖,而且,这些命令行参数会被当作参数传递给 ENTRYPOINT指定指定的程序 .不过, docker run命令的 --entrypoint选项的参数可覆盖 ENTRYPOINT指令指定的程序

语法

ENTRYPOINT <command>

ENTRYPOINT ["<excutable>","<param1>","<param2>"]

docker run 命令传入的命令参数会覆盖CMD指令的内容并且附加到ENTRYPOINT命令最后做为其参数使用 . Dockerfile文件中也可以存在多个 ENTRYPOINT指令,但仅有最后一个会生效

例子

把上例中的CMD执行命令,改成ENTRYPOINT

vim Dockerfile

 

FROM centos:7.3.1611

 

MAINTAINER "sunny <sunny@ghbsunny.cn>"

 

ENV nginx_ver=1.14.0

ENV nginx_url=http://nginx.org/download/nginx-${nginx_ver}.tar.gz

 

WORKDIR "/usr/local/src"

EXPOSE 80/tcp

ADD ${nginx_url} /usr/local/src/

RUN tar xf nginx-${nginx_ver}.tar.gz && yum -y install gcc pcre-devel openssl-devel make \

    && cd nginx-${nginx_ver} && ./configure && make && make install

ENTRYPOINT ["/usr/local/nginx/sbin/nginx","-g","daemon off;"]

制作镜像

[root@docker workshop]# docker build -t nginx:v5 ./

由于这次镜像修改相比上次很少,只差了一层CMD,构建过程直接使用缓存,所以速度很快,dockerfile里,建议CMD和ENTRYPOINT不用复用,二者选其一,除非明确指定CMD里的命令参数会被ENTRYPOINT当做参数执行

启动容器

run命令不带其他命令

[root@docker workshop]# docker run -it --rm -P --name nginxv3 nginx:v5

直接启动,可以正常启动nginx,并暴露端口

run命令修改默认命令如/bin/bash,与上例CMD不一样,此时报选项错误,因为此时会把 /bin/bash当做参数传递给ENTRYPOINT指定的指令,此时ENTRYPOINT指定的指令为启动nginx,不能识别/bin/bash

[root@docker workshop]# docker run -it --rm -P --name nginxv3 nginx:v5 /bin/bash

nginx: invalid option: "/bin/bash"

[root@docker workshop]#

但是,如果一定要覆盖dockerfile里指定的ENTRYPOINT命令,那么在run命令使用参数--entrypoint来覆盖,如下

[root@docker workshop]# docker run -it --rm -P --name nginxv3  --entrypoint /bin/bash nginx:v5

[root@4c940d422f20 src]# pwd

/usr/local/src

[root@4c940d422f20 src]#

成功以进程/bin/bash启动了容器,覆盖了dockerfile里设定的nginx启动命令

 

USER

USER用于指定运行 image时的或运行 Dockerfile中任何 RUNCMDENTRYPOINT指令指定的程序时的用户名或 UID ,即改变容器中运行程序的身份

.默认情况下, container的运行身份为 root用户

语法

USER  <UID>|<UserName>

需要注意的是, <UID>可以为任意数字,但实践中其必须为 /etc/passwd中某用户的有效 UID,否则, docker run命令将运行失败

 

ONBUILD

ONBUILD 用于在 Dockerfile中定义一个触发器 . 用来指定运行docker指令

Dockerfile用于 build映像文件,此映像文件亦可作为 base image被另一个 Dockerfile用作 FROM指令的参数,并以之构建新的映像文件

.在后面的这个 Dockerfile中的 FROM指令在 build过程中被执行时,将会触发创建其 base imageDockerfile文件中的 ONBUILD指令定义的触发器

语法

ONBUILD <INSTRUCTION>

尽管任何指令都可注册成为触发器指令,但是ONBUILD不能自我嵌套,且不会触发FROM和MAINTAINER指令

使用包含ONBUILD指令的Dockerfile构建的镜像应该使用特殊的标签,例如 ruby:2.0-onbuild

ONBUILD指令中使用ADDCOPY指令应该格外小心,因为新构建过程的上下文在缺少指定的源文件时会失败

ONBUILD 在构建镜像时不会运行,是别人基于这个镜像作为基础镜像构建时,才会运行

如下例子

增加一个ONBUILD命令,执行RUN

FROM centos:7.3.1611

 

MAINTAINER "sunny <sunny@ghbsunny.cn>"

 

ENV nginx_ver=1.14.0

ENV nginx_url=http://nginx.org/download/nginx-${nginx_ver}.tar.gz

 

WORKDIR "/usr/local/src"

EXPOSE 80/tcp

ADD ${nginx_url} /usr/local/src/

RUN tar xf nginx-${nginx_ver}.tar.gz && yum -y install gcc pcre-devel openssl-devel make \

    && cd nginx-${nginx_ver} && ./configure && make && make install

CMD ["/usr/local/nginx/sbin/nginx","-g","daemon off;"]

ONBUILD RUN echo -e "\nSunny do an onbuild~\n" >> /etc/issue

 

构建镜像

[root@docker workshop]# docker build -t nginx:v6 ./

基于nginx:v6启动容器,此时/etc/issue还没写入echo要插入的信息

[root@docker workshop]# docker run -it --rm -P --name nginxv3 nginx:v6 /bin/bash

[root@16e90f7a6460 src]# cat /etc/issue

\S

Kernel \r on an \m

 

[root@16e90f7a6460 src]#

然后基于这个nginx:v6镜像,再次制作一个新镜像,编辑一个新的Dockerfile

 

[root@docker ~]# mkdir nginxv7

[root@docker ~]# cd nginxv7/

[root@docker nginxv7]# vim Dockerfile

FROM nginx:v6

MAINTAINER "sunny <sunny@ghbsunny.cn>"

CMD "/bin/bash"

构建镜像,注意,会提示执行一个build trigger,如下Executing 1 build trigger

[root@docker nginxv7]# docker build -t nginx:v7 ./

Sending build context to Docker daemon  2.048kB

Step 1/3 : FROM nginx:v6

# Executing 1 build trigger

 ---> Running in 6bb18c52af99

Removing intermediate container 6bb18c52af99

 基于新镜像nginx:v7启动新容器nginxv7

[root@docker nginxv7]# docker run -it --rm --name nginxv7 nginx:v7

[root@becc66948713 src]# cat /etc/issue

\S

Kernel \r on an \m

 

 

Sunny do an onbuild~

 

[root@becc66948713 src]#

此时,在旧的镜像中的dockerfile里的ONBUILD已经触发,把信息写入到/etc/issue里

LABEL

LABEL为磁盘映像文件添加元数据,可以基于这个LABEL调用这些元数据,一个LABEL就是一堆k/v值,一个镜像文件可以有多个LABEL