高效编写 Dockerfile 的几条准则

2018-07-11 22:34:29 +08:00
 hansonwang99


概述

然而写 Dockerfile 也像写代码一样,一份精心设计、Clean Code 的 Dockerfile 能在提高可读性的同时也大大提升 Docker 的使用效率

因此下面就结合实践来讲几条 Dockerfile 的实践心得!



基础镜像的选择有讲究

在我的文章 《利用 K8S 技术栈打造个人私有云(连载之:基础镜像制作与实验)》 中,我们是基于某个 Linux 基础镜像作为底包,然后打包进我需要的功能从而形成自己的镜像。

这里选择基础镜像时是有讲究的:

就典型的 Linux 基础镜像来说,大小关系如下:

Ubuntu > CentOS > Debian

因此相比 Ubuntu,其实更推荐使用最轻量级的 Debian 镜像,而且它也是一个完整的 Release 版,可以放心使用



多使用标签 Tag 有好处

docker build -t=“ centos:wordpress" .

例如上面的这个 centos 镜像是用来做 wordpress 用的,所以已经集成了 wordpress 功能,这一看就很清晰明了

FROM debian:codesheep


充分利用镜像缓存

什么是镜像缓存?

由 Dockerfile 最终构建出来的镜像是在基础镜像之上一层层叠加而得,因此在过程中会产生一个个新的 镜像层。Docker daemon 在构建镜像的过程中会缓存一系列中间镜像。

docker build 镜像时,会顺序执行 Dockerfile 中的指令,并同时比较当前指令和其基础镜像的所有子镜像,若发现有一个子镜像也是由相同的指令生成,则 命中缓存,同时可以直接使用该子镜像而避免再去重新生成了。

为了有效地使用缓存,需要保证 Dockerfile 中指令的 连续一致,尽量将相同指令的部分放在前面,而将有差异性的指令放在后面

**举例:**假如我想用 Dockerfile 方式 基于最基本的 CentOS 镜像来构建两个不同的镜像时,两个 Dockerfile 的开头可以相同:

FROM centos:latest

# 下面安装两个常用的工具
RUN yum install -y net-tools.x86_64

RUN yum install lrzsz

######## 上面为两个 Dockerfile 文件中相同的部分######

######## 下面为两个 Dockerfile 文件中不同的部分######

......



ADD 与 COPY 指令的正确使用

虽然两者都可以添加文件到镜像中,但在一般用法中,还是推荐以 COPY 指令为首选,原因在于 ADD 指令并没有 COPY 指令来的纯粹,ADD 会添加一些额外功能,典型的如下 ADD 一个压缩包时,其不仅会复制,还会自动解压,而有时我们并不需要这种额外的功能。

ADD codesheep.tar.gz /path

除此之外,在需要添加多个文件到镜像中的时候,不要一次性集中添加,而是选择 按需 在必要时 逐个 添加即可,因为这样有利于利用镜像缓存



##尽量使用 docker volume

虽然上面一条原则说推荐通过 COPY 命令来向镜像中添加多个文件,然而实际情况中,若文件 大而多 的时候还是应该优先用 docker -v 命令来挂载文件,而不是依赖于 ADD 或者 COPY



CMD 和 ENTRYPOINT 指令 的正确理解使用

Dockerfile 制作镜像时,会组合 CMD 和 ENTRYPOINT 指令来作为容器运行时的默认命令:即 CMD + ENTRYPOINT。此时的默认命令组成中:

举个例子:

FROM debian:latest

MAINTAINER codesheep@163.com

ENTRYPOINT [ "ls", "-l"]
CMD ["-a"]

若以默认命令运行容器,可以发现,执行的是 ls -a -l 命令:

docker run 中增加参数 -t

docker run -it --rm --name test debian:codesheep -t

也可以发现执行的是 ls -l -t,即 Dockerfile 中的 CMD 原参数被覆盖了:

因此推荐的使用方式是:



不推荐在 Dockerfile 中 做端口映射

Dockerfile 可以通过 EXPOSE 指令 将容器端口映射到主机端口上,但这样会导致镜像在一台主机上仅能启动一个容器!

所以应该在 docker run 命令中来用 -p 参数来指定端口映射,而不要将该工作置于 Dockerfile 之中:

#尽量避免这种方式
EXPOSE 8080:8899

#选择仅仅暴露端口即可,端口映射的任务交给 docker run 去做
EXPOSE 8080


使用 Dockerfile 来共享镜像

推荐通过共享 Dockerfile 的方式来共享镜像,优点多多:



后记

如果有兴趣,也可以抽点时间看看作者一些关于容器化、微服务化方面的文章:

作者相关的 SpringBt 实践文章在此:



4594 次点击
所在节点    程序员
36 条回复
wl2358
2018-07-11 22:40:20 +08:00
最近在学 dicker, mark
mason961125
2018-07-11 22:41:36 +08:00
所以,开头放张图的意义是什么?
ngg0707
2018-07-11 22:44:58 +08:00
很有帮助
AlphaTr
2018-07-11 22:49:26 +08:00
有一点不太认同,希望能讨论讨论:tag 那个,我更倾向于 wordpress:v4.3.3 这样的,对于用户来说,不需要关心底层镜像是 centos 还是 ubuntu,关心的是 wordpress 的版本或者其他信息;私以为这里的 tag 类似于 git 的 tag,多用于版本
hansonwang99
2018-07-11 22:59:45 +08:00
我觉得楼上的理解也挺好呢
lizheming
2018-07-11 23:21:04 +08:00
@AlphaTr 我觉得只是他的例子举的不太好,意思都是差不多,作者想说的应该和你的意思一样。
ofnh
2018-07-11 23:32:18 +08:00
是 ls -l -a 吧
mritd
2018-07-12 00:13:02 +08:00
@lizheming 无版本号 / 时间戳 tag 等同于 latest
yuanfnadi
2018-07-12 00:42:21 +08:00
很重要的多部构建没有提到。可以极大的缩小镜像体积。
shiny
2018-07-12 00:50:20 +08:00
不谈谈 alpine linux 吗
billwsy
2018-07-12 01:40:36 +08:00
Tag 成 centos:wordpress 真的好吗?不怕冲突?以后上传到 registry 也不方便啊
billwsy
2018-07-12 01:45:06 +08:00
另外 Entrypoint 运行时也是可以改的

至于所说的 layer,倒不如造一个自己的 base,所有其他 image 从中继承;我们系统里的 57 个 image 就组织成了这样的树状,然后一个脚本自动解析依赖关系
blless
2018-07-12 02:28:19 +08:00
感觉只是基础的构建…官方构建一般不会有两个 yum install,而且推荐安装跟清理一起做了 不然下一层清理体积并不会减小
blless
2018-07-12 02:30:33 +08:00
添加文件按需逐个添加效率也太低了…而且如果第二个文件就不一样 后面缓存也全没用了…
blless
2018-07-12 02:31:15 +08:00
……楼主你这文章就不要用"准则"了,明显误导别人
ysicing
2018-07-12 07:04:24 +08:00
基础镜像很少用 centos 的吧,不应该是最常用 alpine 或 debian😉
sdrzlyz
2018-07-12 07:27:38 +08:00
确定 Expose 是这个意思?这个“准则”有点误认啊。。。基础镜像不提 alpine ?
naiba
2018-07-12 07:34:35 +08:00
层数越多占用空间越大…
hxsf
2018-07-12 07:54:25 +08:00
@blless +1
to 楼主 layer 越多越容易缓存也越大,
有 run 的时候基本缓存失效 不如一把梭,layer 少点还小
entrypoint 也是能改的
推荐用-v 挂文件什么意思 有些东西要持久化才挂载 其他作为容器一部分就好了,不然分发的时候除了 image 还得分发其他文件。

另外:标题确实不太好
0312birdzhang
2018-07-12 08:11:08 +08:00
@blless +1 不认同楼主的“镜像缓存”,这样只是方便你本地下次打镜像更快一点而已,但是却浪费了空间,使镜像多了一层。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/470037

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX