Dockerfile 是应用一系列自定义的命令和格式构成文本文件从而简化镜像构建的过程。但如果处理不当,也会跌坑里~ Caicloud 独家奉献 Dockerfile 的 best practice。
应用最好不要跑在特权用户(root)底下
Docker 默认所有的应用都会跑在容器的 root user 底下,但是这样会造成一些潜在的安全隐患。在 production 环境跑的 Container 最好是通过 USER 命令跑在非特权用户底下。
隐患在哪,来补充一下~
安全隐患是说如果这个 container 被 compromise 了,那么如果是 root 在跑这个 container 更可能使系统出现问题。但是用 root user 本身应该是没问题的。
是指的如果用 root 跑 container 会有问题吗?那为啥推荐用 USER 命令来改变 docker 的非 root?
就是 Docker 的隔离效力有限,如果一个 container 里的应用是恶意的,而且是 root,那如果它改了系统配置(root 权限,比如 unload 某个系统 module,更改了某个系统文件),也会影响其他的 container(share 一个 kernel)。
避免使用 apt-get upgrade
Upgrade 命令是用来升级当前基础镜像的。非特权用户无法 Upgrade 一些核心的应用。而且 Upgrade 命令会打乱已经缓存的镜像,使得编译时间加长。在一般情况下,选用正确的基础镜像是不需要升级的,如果真的需要,最好联系基本镜像的维护方,这样所有使用者都能从中获益。如果只是需要更新某个程序 foo,那么使用 apt-get install –y foo 就能到达这个目的。
尽量合并命令
Dockerfile 中的每一个命令都会创建一个新的 layer,而一个容器能够拥有的最多 layer 数是有限制的。所以尽量将逻辑上连贯的命令合并可以减少 layer 的层数,合并命令的方法可以包括将多个可以合并的命令(EXPOSE, ENV,VOLUME,COPY)合并。
Dockerfile 中的每一个命令都会创建一个新的 layer,而一个容器能够拥有的最多 layer 数是有限制的。所以尽量将逻辑上连贯的命令合并可以减少 layer 的层数,这也可以加快编译速度?
将多个可以合并的命令(EXPOSE, ENV,VOLUME,COPY)合并,比如:
使用“&&”来连接 RUN 命令,比如:
不过过度合并命令可能会影响 Dockerfile 的可读性,所以需要在优化代码和可读性之间做出权衡。
合理安排命令的顺序
命令的顺序会影响编译所需要的时间。每一个命令都会产生一个 layer。如果一个 layer 已经在缓存中,那么生成这个 layer 所需要的时间就很短。从第一个不在缓存的 layer 起,所有以后的命令都会被重新编译。因为这个原因,我们推荐将不常变动的命令放在前面,这样可以使得更多的 layer 被成功缓存,从而减少编译时间。
避免在容器中存储数据
容器需要是无状态的,这样方便启动新的 Container 来替代 down 掉的 Container。如果容器中包含状态,那么就需要额外的运维人员来恢复 down 掉 Container 的状态。
使用.dockerignore
使用.dockerignore 可以减少拷贝不必要的文件到 Container,这样可以减少镜像大小。比如很多地方都有.git 文件,但是这个文件就不需要拷贝到 Container 里面。
避免安装不必要的软件
安装不必要的软件既浪费空间又增加编译时间。比如一个数据库的 Container 就没有必要安装文字编辑软件。
更进一步,如果程序能够在本地编译,那么就不用在 Container 里安装编译程序所需要的软件和 lib 了。直接把本地编译好的 binary 拷贝到 Container 里就好。
本文转载自才云 Caicloud 公众号。
原文链接:https://mp.weixin.qq.com/s/mlfBH6qMtVGyTSsA4-S5IQ
评论