一.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指令中指定的命令,這樣就可以達到動態執行的效果。
