写点什么

最优 Dockerfile

用户头像
Damon
关注
发布于: 2021 年 06 月 11 日

作者:Damon

博客:http://www.damon8.cn

程序猿 Damon | 微服务 | 容器化 | 自动化


在介绍 Dockerfile 最佳实践前,这里再强调一下,生产实践中一定优先使用 Dockerfile 的方式构建镜像。 因为使用 Dockerfile 构建镜像可以带来很多好处:


  • 易于版本化管理,Dockerfile 本身是一个文本文件,方便存放在代码仓库做版本管理,可以很方便地找到各个版本之间的变更历史;

  • 过程可追溯,Dockerfile 的每一行指令代表一个镜像层,根据 Dockerfile 的内容即可很明确地查看镜像的完整构建过程;

  • 屏蔽构建环境异构,使用 Dockerfile 构建镜像无须考虑构建环境,基于相同 Dockerfile 无论在哪里运行,构建结果都一致。


虽然有这么多好处,但是如果你 Dockerfile 使用不当也会引发很多问题。比如镜像构建时间过长,甚至镜像构建失败;镜像层数过多,导致镜像文件过大。所以,这一课时我就教你如何在生产环境中编写最优的 Dockerfile。


在介绍 Dockerfile 最佳实践前,我们再聊一下我们平时书写 Dockerfile 应该尽量遵循的原则。

Dockerfile 书写原则

遵循以下 Dockerfile 书写原则,不仅可以使得我们的 Dockerfile 简洁明了,让协作者清楚地了解镜像的完整构建流程,还可以帮助我们减少镜像的体积,加快镜像构建的速度和分发速度。


(1)单一职责

由于容器的本质是进程,一个容器代表一个进程,因此不同功能的应用应该尽量拆分为不同的容器,每个容器只负责单一业务进程。


(2)提供注释信息

Dockerfile 也是一种代码,我们应该保持良好的代码编写习惯,晦涩难懂的代码尽量添加注释,让协作者可以一目了然地知道每一行代码的作用,并且方便扩展和使用。


(3)保持容器最小化

应该避免安装无用的软件包,比如在一个 nginx 镜像中,我并不需要安装 vim 、gcc 等开发编译工具。这样不仅可以加快容器构建速度,而且可以避免镜像体积过大。


(4)合理选择基础镜像

容器的核心是应用,因此只要基础镜像能够满足应用的运行环境即可。例如一个 Java 类型的应用运行时只需要 JRE,并不需要 JDK,因此我们的基础镜像只需要安装 JRE 环境即可。


(5)使用 .dockerignore 文件

在使用 git 时,我们可以使用.gitignore 文件忽略一些不需要做版本管理的文件。同理,使用.dockerignore 文件允许我们在构建时,忽略一些不需要参与构建的文件,从而提升构建效率。.dockerignore 的定义类似于.gitignore。


(6)尽量使用构建缓存

Docker 构建过程中,每一条 Dockerfile 指令都会提交为一个镜像层,下一条指令都是基于上一条指令构建的。如果构建时发现要构建的镜像层的父镜像层已经存在,并且下一条命令使用了相同的指令,即可命中构建缓存。


Docker 构建时判断是否需要使用缓存的规则如下:

  • 从当前构建层开始,比较所有的子镜像,检查所有的构建指令是否与当前完全一致,如果不一致,则不使用缓存;


  • 一般情况下,只需要比较构建指令即可判断是否需要使用缓存,但是有些指令除外(例如 ADD 和 COPY);

  • 对于 ADD 和 COPY 指令不仅要校验命令是否一致,还要为即将拷贝到容器的文件计算校验和(根据文件内容计算出的一个数值,如果两个文件计算的数值一致,表示两个文件内容一致 ),命令和校验和完全一致,才认为命中缓存。


因此,基于 Docker 构建时的缓存特性,我们可以把不轻易改变的指令放到 Dockerfile 前面(例如安装软件包),而可能经常发生改变的指令放在 Dockerfile 末尾(例如编译应用程序)。

例如,我们想要定义一些环境变量并且安装一些软件包,可以按照如下顺序编写 Dockerfile:

FROM centos:7
# 设置环境变量指令放前面
ENV PATH /usr/local/bin:$PATH
# 安装软件指令放前面
RUN yum install -y make
# 把业务软件的配置,版本等经常变动的步骤放最后
复制代码

按照上面原则编写的 Dockerfile 在构建镜像时,前面步骤命中缓存的概率会增加,可以大大缩短镜像构建时间。


(7)正确设置时区

我们从 Docker Hub 拉取的官方操作系统镜像大多数都是 UTC 时间(世界标准时间)。如果你想要在容器中使用中国区标准时间(东八区),请根据使用的操作系统修改相应的时区信息,下面我介绍几种常用操作系统的修改方式:

  • Ubuntu 和 Debian 系统

Ubuntu 和 Debian 系统可以向 Dockerfile 中添加以下指令:

RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
RUN echo "Asia/Shanghai" >> /etc/timezone
复制代码
  • CentOS 系统

CentOS 系统则向 Dockerfile 中添加以下指令:

RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
复制代码


精彩推荐

结束福利

开源实战利用 k8s 作微服务的架构设计代码:

欢迎大家 star,多多指教。

关于作者

  笔名:Damon,技术爱好者,长期从事 Java 开发、Spring Cloud 的微服务架构设计,以及结合 Docker、K8s 做微服务容器化,自动化部署等一站式项目部署、落地。目前主要从事基于 K8s 云原生架构研发的工作。Golang 语言开发,长期研究边缘计算框架 KubeEdge、调度框架 Volcano 等。公众号 程序猿Damon 发起人。个人微信 MrNull008,个人网站:Damon | Micro-Service | Containerization | DevOps,欢迎來撩。

欢迎关注:InfoQ

欢迎关注:腾讯自媒体专栏


欢迎关注


发布于: 2021 年 06 月 11 日阅读数: 14
用户头像

Damon

关注

God bless the fighters. 2020.03.11 加入

欢迎关注公众号:程序猿Damon,长期从事Java开发,研究Springcloud的微服务架构设计。目前主要从事基于K8s云原生架构研发的工作,Golang开发,长期研究边缘计算框架KubeEdge、调度框架Volcano、容器云KubeSphere研究

评论

发布
暂无评论
最优 Dockerfile