本文是 Dockerfile 编写教程下半部分: Dockerfile 是应用一系列自定义的命令和格式构成文本文件从而简化镜像构建的过程。
一个容器只放一个应用
在一个 Container 中安装多个应用既使得镜像更大又使得可读性和逻辑性更差。所以类似一个函数只干一件事的思想,一个 Container 也只应该放一个应用。
合理使用 CMD 和 ENTRYPOINT 命令
CMD 和 ENTRYPOINT 都能用来指定开始运行的程序,而且这两个命令都有两种不用的语法:
CMD foo a b c
或者:
CMD [“ foo ”, “ a ”, “ b ”, “ c ”]
对于第一种语法, docker 会自动加入“/bin/sh – c ”到命令中,这样就有可能导致意想不到的行为。为了避免这种行为,我们推荐所有的 CMD 和 ENTRYPOINT 都应该使用第二种语法。
如果两个同时使用,请确定确定他们的含义没有错误。一般来说需要两个同时使用的情况只有 ENTRYPOINT 指定需要运行的 binary , CMD 给出运行的默认参数。
挑选合适的基础镜像
一个合适的基础镜像是能满足运行应用所需要的最小的镜像。这里包括
-如果不需要操作系统,那么使用 scratch 镜像就好;能使用小的镜像就不要使用大的。
-指定的基础镜像需要有版本号,比如 debian 就有很多不同的版本。不指定版本号就永远用的 latest ,这个会一直变。因为不同版本的系统和安装的软件有兼容性问题,所以不指定版本会使得 Dockerfile 不稳定。
-如果多个镜像需要安装一系列相同的软件,那么可以考虑新建一个基础镜像来安装这些软件。以后的镜像直接使用新生成的基础镜像就好
优化 apt-get 相关操作
将多个 apt-get 操作合成一个既能减少 layer 数,又能更好的管理安装的东西(避免重复安装)。在 apt-getinstall 之前,最好使用 apt-getupdate 这样可以保证安装的程序是最新版本的。在安装完之后最好使用 apt-get clean 来清理中间结果。下面给出了一个比较推荐的 apt-get 操作的格式:
RUN apt-get update && apt-get install -y \
package-bar \
package-baz \
package-foo &&
apt-get clean
需要安装的软件最好按字母序排列,这样以后要查找或者增加新的软件方便。
合理使用 ADD 命令
1 、 ADD 命令和 COPY 命令在很大层度上功能是一样的。但是 COPY 语义更加直接,所以我们推荐尽量使用 COPY 命令。唯一例外的是 ADD 命令自带解压功能,如果需要拷贝并解压一个文件到镜像中,那么我们可以使用 ADD 命令。除此之外,我们都推荐使用 COPY 命令。
2 、
ADD http://example.com/big.tar.xz /usr/src/things/ RUN tar -xJf /usr/src/things/big.tar.xz -C /usr/src/things RUN make -C /usr/src/things all
我们不推荐使用 ADD 命令来获取网络资源。网络资源应该使用 RUN wget 或者 curl 命令来获取。因为使用 wget 或者 curl 更加方便清理存储的中间文件和临时文件,同时这样也能使用更少的 layer 来完成同样的事情。比如命令:
可以由以下命令代替:
RUN mkdir -p /usr/src/things
&& curl -SL http://example.com/big.tar.xz
| tar -xJC /usr/src/things
&& make -C /usr/src/things all
不要设置公共端口
Dockerfile 支持 mapping 私有端口和公共端口(比如命令 EXPOSE 80 : 8080 ),但是我们不推荐 mapping 公共端口因为 Container 在编译的时候无法确定这个公共端口在它运行的环境中是否已经被其他程序占用。
清理没用的中间结果
中间结果可以包括:
-安装的对最后应用没有的软件。比如安装 foo 需要软件 bar ,但是最后的应用不需要 bar 。那么在安装完成 foo 之后就可以把 bar 删了。
-拷贝的临时文件
-安装产生的中间结果
如果需要转载,请联系我们,尊重知识产权人人有责; 0
1
bdbai 2016-08-19 13:36:08 +08:00 via Android
同之前,能用 Alpine 就别用 Ubuntu 、 Debian ,这也不提?直接用 scratch 怎么用?
清理中间过程的时候,另起一次 RUN 命令反而会增大镜像体积。一般跟在产生临时文件的那一次 RUN 后面,用 && 连接。很多包管理器和命令行程序支持 --no-cache 选项,要多加利用。 |
2
caicloud2015 OP @bdbai alpine 还是有一些坑的,特别是在 kubernetes 上用 alpine 的镜像的时候。 alpine 的 libc 是用的 musl libc , musl libc 不支持 search domain ,这会导致 pod 只能通过 FQDN 去找 kubernetes service 。具体可以参考 https://github.com/gliderlabs/docker-alpine/blob/master/docs/caveats.md
|
3
bdbai 2016-08-19 14:49:14 +08:00
@caicloud2015 并不搞集群。不过直接用 scratch 有哪些适用场景?
|
4
Nexvar 2016-09-02 12:43:34 +08:00
感谢分享,原创内容不容易
做 caas 也不容易啊,加油! |
5
caicloud2015 OP @Nexvar 感谢关注
|