Dockerfile编写的注意事项

一.Dockerfile合理分层

Dockerfile的写法不合理,有时候会导致镜像膨胀,由于Docker是分层设计,而在Dockerfile中,每一条指令都拥有自己的context,而执行到下一条指令时,则会将下一层的构建层叠加到上一层上。因此,假如你在上一层指令做了一些包下载操作安装操作,然后在下一层再做清理,其实没什么用,只能说明你下一层引入的diff是0而已。

可以实验一下:

对照组A:下载清理操作全在同一层

FROM centos
MAINTAINER **

RUN yum -y update
RUN yum -y install wget

RUN wget --no-cookies --no-check-certificate --header "Cookie: gpw_e24=http%3A%2F%2Fwww.oracle.com%2F; oraclelicense=accept-securebackup-cookie" "http://download.oracle.com/otn-pub/java/jdk/8u121-b13/e9e7ea248e2c4826b92b3f075a80e441/jdk-8u121-linux-x64.tar.gz" -O /tmp/jdk8_x64.tar.gz && gunzip /tmp/jdk8_x64.tar.gz && tar -C /opt -xf /tmp/jdk8_x64.tar && ln -s /opt/jdk1.8.0_121 /opt/jdk && yum clean all && rm -fr /tmp/*

对照组B:下载清理操作放在不同层

FROM centos
MAINTAINER **

RUN yum -y update
RUN yum -y install wget

RUN wget --no-cookies --no-check-certificate --header "Cookie: gpw_e24=http%3A%2F%2Fwww.oracle.com%2F; oraclelicense=accept-securebackup-cookie" "http://download.oracle.com/otn-pub/java/jdk/8u121-b13/e9e7ea248e2c4826b92b3f075a80e441/jdk-8u121-linux-x64.tar.gz" -O /tmp/jdk8_x64.tar.gz && gunzip /tmp/jdk8_x64.tar.gz && tar -C /opt -xf /tmp/jdk8_x64.tar && ln -s /opt/jdk1.8.0_121 /opt/jdk 
RUN yum clean all 
RUN rm -fr /tmp/*

分别执行构建操作,得到的镜像差异很大,其中test1为对照组A的构建结果,test2为对照组B的构建结果,两者相差400M.

alex@ubuntu:~/workspace/docker_project$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
test2               latest              a65c6cced43b        13 minutes ago      1.1 GB
test1               latest              67897397b053        14 minutes ago      729 MB

 二.CMD跟ENTRYPOINT的合理使用

举个例子,假设你需要容器启动时,去执行一个后台常驻脚本,那我们一般想到的是在CMD中执行脚本即可。

假设对照组A的Dockerfile:

FROM centos
MAINTAINER **

EXPOSE 8000
WORKDIR /

CMD [ "/bin/bash","-c","/usr/bin/python2.7 -m SimpleHTTPServer" ]

那正常镜像构建成功后,启动容器

alex@ubuntu:~/test$ docker build -t test1 .
Sending build context to Docker daemon 2.048 kB
Step 1/5 : FROM centos
 ---> 98d35105a391
Step 2/5 : MAINTAINER shufeng, shufeng.lsf@alibaba-inc.com
 ---> Using cache
 ---> 054ed64f1b34
Step 3/5 : EXPOSE 8000
 ---> Running in e706b62c3c16
 ---> f1fd512940dc
Removing intermediate container e706b62c3c16
Step 4/5 : WORKDIR /
 ---> daa58d7899df
Removing intermediate container 5c51961e6e87
Step 5/5 : CMD /bin/bash -c /usr/bin/python2.7 -m SimpleHTTPServer
 ---> Running in 5dfa9742ccaf
 ---> 6ff71edb9bad
Removing intermediate container 5dfa9742ccaf
Successfully built 6ff71edb9bad

启动容器:

alex@ubuntu:~/test$ docker run -it -d -p 8001:8000 6ff71edb9bad
a4318a775ec005473f6bc9342cd3c14b55981b334cc6160e7ea17e802f6eff15

查看一下映射情况

可以发现映射成功了。但这样启动有适合什么情况呢,只适合后台启动的情况,让我们试试另一种启动容器的方式

alex@ubuntu:~/test$ docker run -it -d -p 8001:8000 6ff71edb9bad /bin/bash
0fdaf33f00fb9307394e4b91577af026627801ab6364ef6729aaf9754eb84455
alex@ubuntu:~/test$ 
alex@ubuntu:~/test$ telnet 127.0.0.1 8001
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
Connection closed by foreign host.

可以发现当我需要在容器启动后进入命令行时,/bin/bash的操作直接将CMD的指令覆盖了。因此,这时候需要用ENTRYPOINT来代替CMD,对应的Dockerfile如下。

FROM centos
MAINTAINER **

EXPOSE 8000
WORKDIR /
ENTRYPOINT ["/bin/bash","-c","/usr/bin/python2.7 -m SimpleHTTPServer"]

在这里说下CMD跟ENTRYPOINT的区别。

docker run命令行可以覆盖CMD指令,而ENTRYPOINT则不会,此外,可以通过docker run在命令行中指定的参数,来传递给ENTRYPOINT指令中指定的命令,这样就可以达到动态执行的效果。

原文地址:https://www.cnblogs.com/alexkn/p/6658642.html