dockerfile是为快速构建docker image而设计的,当你使用docker build 命令的时候,docker 会读取当前目录下的命名为Dockerfile(首字母大写)的纯文本文件并执行里面的指令构建出一个docker image。
而另一种构建docker iamge 的方法是pull一些基础镜像下来启动成容器,然后进入容器内安装各种需要的程序以及配置好需要的环境,最后commit成一个镜像。但是相比之 Dockerfile的方法会更加自动化,更加方便快捷,而且功能也更强大。(Docker build方法底层里也是在基础镜像下启动容器然后commit的,但是这些不需要我们手动去commit以及rm,都是自动化的。)
======(注:以下大部分内容均参考自官方文档)
首先,是关于构建docker image的一些优化建议
我们希望构建出的image对应的容器应该是可以在服务群中暂停(解耦性)并且快速替换,这要求容器可以在极短的时间内完成启动并配置运行起来。
优化手段:
使用.dockerignore文件 .
dockerignore文件的设计是为了在docker build的过程中排除不需要用到的文件以及目录,目的是为了docker build这个过程可以尽可能地快速高效以及构建出来的image没有多余的“垃圾”。
不要安装不必要的程序包
我们希望构建出来的image尽可以的轻小、依赖性小以及构建过程尽可能地快。这就需要你在构建的时候不要安装不必要的程序,例如,一个存储数据的数据库容器不需要安装文本编辑器。
单一容器只运行单一的服务
大部分情况下一个容器只建议运行一个服务,这样的好处在于:减小耦合度、利于容器复用以及提高容器的横向可扩展性。如果服务之间是需要联系的,就应该把服务放在不现的容器内,然后用container linking来关联这些容器以达到目的。
最小化镜像层数(layers)
关于镜像层数(layers)的概念请参考:docker镜像与容器存储结构分析http://www.programfish.com/blog/?p=9
把镜像层数减到最少可能加快容器的启动速度,但是这里也要权衡另一个问题:dockerfile的可读性。你可以把一个dockerfile写得很 复杂以达到构建出最小层数的镜像,但同时你的dockerfile可读性也降低了。所以我们要在镜像层数和dockerfile可读性之间做出让步与妥 协。
对多行参数进行排序(一般按字母顺序)
对参数排序可以方便以后修改更新这些参数以及确保不会重复重复输入了某些参数。例如官方的一个例子是:
RUN apt-get update && apt-get install -y \
bzr \
cvs \
git \
mercurial \
Subversion
把要安装的程序包名按字母排序可以方便管理。
构建的时候使用cache
Docker build期间docker会按你提供的dockerfile文件里面的指令按顺序逐条执行。Docker在首先检查每一条指令的时候会去cache里搜 查是否有执行过这条指令并且可以复用的镜像,如果没有再去构造一个新的镜像。这是默认的情况,如果你指定不要这个过程可以在docker build里用如下参数:
–no-cache=true
Docker查找cache的过程:
首先在cache里从base image(详见:docker镜像与容器存储结构分析http://www.programfish.com/blog/?p=9)起,docker会比较dockerfile里的下一条指令与这个base image的每一个子镜像的构建指令是否匹配,如果匹配则命中,否则cache标为无效。
对于一般指令这样简单比较就足够了,但是有些精确的指令要求更详细精确的比较或者说明。 (add和copy指令见官方文档https://docs.docker.com/articles/dockerfile_best-practices/) 一旦cache在dockerifle里某一条指令检查时被标为无效,执行这个dockerfile以后的指令就不再使用cache。
Dockerfile主要指令简介:
FROM
dockerfile里的第一条指令,后面跟有效的镜像名(如果该镜像你的本地仓库没有则会从远程仓库Pull取)。后面的指令在些镜像中执行。
FROM <image>:<tag>
MAINTAINER
MAINTAINER <name> 作者信息
RUN
后跟要执行的linux命令,每一条RUN指令(可能会有多条linux命令)会在当前容器最上面的可读写层执行并且提交成一个新的镜像层,接下来的指令会在这个新的镜像层里执行。
RUN <command> (the command is run in a shell – /bin/sh -c – shell form)
RUN ["executable", "param1", "param2"] (exec form)
注意下面的情况:
不要在一条RUN指令里单一使用apt-get update命令,这样可能会导致以后的apt-get install 安装出错。
避免使用RUN apt-get upgrade 或者dist-upgrade,这样有些重要的软件包可能更新失败,如果你确实想要更新某个包A,使用apt-get install install -y A 。这样会自动更新这个软件包。
更多请参考官方文档。
CMD
CMD指令指定你制作出来的镜像在启动成容器时运行命令的默认的参数。
CMD有三种写法:
CMD ["executable","param1","param2"] (exec form, this is the preferred form)
CMD ["param1","param2"] (as default parameters to ENTRYPOINT)
CMD command param1 param2 (shell form)
第一种是可执行文件加参数,第二种是作为ENTRYPOINT的参数,第三种是作为”/bin/sh -c”的参数。
这里CMD与ENTRYPOINT的区别强烈推荐你去看 论docker CMD与ENTRYPOINT的大区别 http://www.cnblogs.com/programfish/p/4101884.html 这篇文章。看完你就懂了。
ENTRYPOINT
ENTRYPOINT字面意思指定容器的进入点。可以把你的容器制作成类似可执行文件的用法。这个指令会覆盖它前面的CMD指令,而多个 ENTRYPOINT指令只有最后一个生效(后面覆盖前面)。同时你也可以在在启动container 的时候指定–entrypoint参数来覆盖dockerfile里的ENTRYPOINT。详见官方文档。
例如我用了这样的指令制作镜像名叫echotest:
ENTRYPOINT ["/bin/echo"]
然后之后这样运行:
docker run -it echotest “this is a echo”
实际上是平时这样的命令:
docker run -it echotest /bin/echo “this is a echo”
这样你应该明白了吧。 这样一个容器的行为就很类似一个可执行文件了。 这里CMD与ENTRYPOINT的区别强烈推荐你去看 论docker CMD与ENTRYPOINT的大区别 http://www.cnblogs.com/programfish/p/4101884.html 这篇文章。看完你就懂了。
EXPOSE
EXPOSE指定容器对外暴露的端口号。
ENV
指定环境变量的值,例如你要确保CMD[“nginx”]能成功启动,你应该用ENV PATH /usr/local/nginx/bin:$PATH设定环境变量。另外你可以设定另外一些变量用于RUN命令里以便于dockerfile文件的维护:
ENV PG_MAJOR 9.3
ENV PG_VERSION 9.3.4
RUN curl -SL http://example.com/postgres-$PG_VERSION.tar.xz | tar -xJC /usr/src/postgress && …
ENV PATH /usr/local/postgres-$PG_MAJOR/bin:$PATH
这样多次出现版本号就可以通过一个变量来管理方便维护。
VOLUME
VOLUME ["path"] 创建指定的挂载点。
WORKDIR
进入指定目录工作。
其它指令详情见官方文档:https://docs.docker.com/reference/builder/
这里引用官方的一个dockerfile例子:
# Nginx
#
# VERSION 0.0.1
FROM ubuntu
MAINTAINER Victor Vieux <victor@docker.com>
RUN apt-get update && apt-get install -y inotify-tools nginx apache2 openssh-server
# Firefox over VNC
#
# VERSION 0.3
FROM ubuntu
# Install vnc, xvfb in order to create a ‘fake’ display and firefox
RUN apt-get update && apt-get install -y x11vnc xvfb firefox
RUN mkdir ~/.vnc
# Setup a password
RUN x11vnc -storepasswd 1234 ~/.vnc/passwd
# Autostart firefox (might not be the best way, but it does the trick)
RUN bash -c ‘echo “firefox” >> /.bashrc ‘
EXPOSE 5900
CMD ["x11vnc", "-forever" , "-usepw", "-create" ]
# Multiple images example
#
#VERSION 0.1
FROM ubuntu
RUN echo foo > bar
# Will output something like ===> 907ad6c2736f
FROM ubuntu
RUN echo moo > oink
# Will output something like ===> 695d7793cbe4
# You᾿ll now have two images, 907ad6c2736f with /bar, and 695d7793cbe4 with
# /oink.
#号为注释符,这里一个dockerfile构建4个镜像。
写好Dockerfile文件后就可以在该目录下运行docker build . 命令了(可以用 -t 参数指定tag)。
欢迎访问本人网站:http://www.programfish.com
LinuxCoder 社区: http://linuxcoder.org
注意:转载请注明 “作者:广州Linux爱好者+云计算 ***金明”