资讯专栏INFORMATION COLUMN

高效编写Dockerfile的几条准则

RyanQ / 1252人阅读

摘要:本文已获得原作者授权。在构建镜像的过程中会缓存一系列中间镜像。镜像时,会顺序执行中的指令,并同时比较当前指令和其基础镜像的所有子镜像,若发现有一个子镜像也是由相同的指令生成,则命中缓存,同时可以直接使用该子镜像而避免再去重新生成了。

本文已获得原作者 CodeSheep 授权。

概述

Dockerfile 是专门用来进行自动化构建镜像的编排文件(就像 Jenkins 2.0时代的 Jenkinsfile 是对 Jenkins 的 Job 和 Stage 的编排一样),我们可以通过 docker build命令来自动化地从 Dockerfile 所描述的步骤来构建自定义的 Docker镜像,这比我们去命令行一条条指令执行的方式构建高效得多。

另一方面,由于 Dockerfile 提供了统一的配置语法,因此通过这样一份配置文件,我们可以在各种不同的平台上进行分发,需要时通过 Dockerfile 构建一下就能得到所需的镜像。

最后一个必须提的优点便是:Dockerfile 通过与镜像配合使用,使得 Docker 镜像构建之时可以充分利用 “镜像的缓存功能”,因此也提效不少!

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

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

基础镜像的选择有讲究

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

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

一是应当尽量选择官方镜像库里的基础镜像;

二是应当选择轻量级的镜像做底包

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

Ubuntu > CentOS > Debian

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

多使用标签 Tag 有好处

构建镜像时,给其打上一个易读的镜像标签有助于帮助了解镜像的功能,比如:

docker build -t=“centos:wordpress" .

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

再者,我们也应该在 Dockerfile 的 FROM 指令中明确指明标签 Tag,不要再让 Docker daemon 去猜,如

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。此时的默认命令组成中:

ENTRYPOINT 指令部分固定不变,容器运行时是无法修改的

而 CMD 部分的指令也可以改变,表现在运行容器时,docker run命令中提供的参数会覆盖CMD的指令内容。

举个例子:

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 原参数被覆盖了:

因此推荐的使用方式是:

使用 exec 格式的 ENTRYPOINT 指令 设置固定的默认命令和参数

使用 CMD 指令 设置可变的参数

不推荐在 Dockerfile 中 做端口映射

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

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

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

#选择仅仅暴露端口即可,端口映射的任务交给 docker run 去做
EXPOSE 8080
使用 Dockerfile 来共享镜像

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

通过 Dockerfile 构建的镜像用户可以清楚地看到构建的过程

就像 Jenkinsfile 可以加入版本控制从而追踪CI系统的变迁和步骤的回滚一样,Dockerfile 作为一个编排文件同样可以入库做版本控制,这样也可以回溯

使用 Dockerfile 构建的镜像具有确定性,没有玄学的成分

后记

作者更多的原创文章在此,欢迎观赏

作者:CodeSheep
链接:https://juejin.im/post/5b4615b0f265...
来源:掘金

更多相关文章:
使用 Dockerfile 定制镜像
用 Dockerfile 打造你的自动化构建工具
Docker 底层技术

如果你还想了解更多,想和技术同僚分享切磋,可扫下方二维码,回复 yw,加入掘金运维技术交流群

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/8063.html

相关文章

  • 高效编写Dockerfile几条准则

    摘要:在构建镜像的过程中会缓存一系列中间镜像。镜像时,会顺序执行中的指令,并同时比较当前指令和其基础镜像的所有子镜像,若发现有一个子镜像也是由相同的指令生成,则命中缓存,同时可以直接使用该子镜像而避免再去重新生成了。 showImg(https://segmentfault.com/img/remote/1460000015606308?w=2000&h=1428); 概述 Docker...

    Alan 评论0 收藏0
  • SpringBoot应用Docker化

    摘要:微服务的基本思想在于考虑围绕着业务领域组件来创建应用,这些应用可独立地进行开发管理和加速。在分散的组件中使用微服务云架构和平台,使部署管理和服务功能交付变得更加简单。 showImg(https://segmentfault.com/img/remote/1460000014332184); 概述 当下web服务端开发中最火的名词中绝对有微服务的一席之地,其也成为当下互联网后端服务架...

    U2FsdGVkX1x 评论0 收藏0
  • Spring Boot Admin 2.0开箱体验

    摘要:概述在我之前的应用监控实战一文中,讲述了如何利用版本来可视化地监控应用。接下来我们就来创建一个待监控的示例。 showImg(https://segmentfault.com/img/remote/1460000015671446); 概述 在我之前的 《Spring Boot应用监控实战》 一文中,讲述了如何利用 Spring Boot Admin 1.5.X 版本来可视化地监控 ...

    CastlePeaK 评论0 收藏0
  • SpringBoot热部署加持

    摘要:概述进行的开发过程中,我们很多时候经常需要重启服务器才能保证修改的源代码文件或者一些诸如的配置文件以及一些静态文件生效,这样耗时又低效。 showImg(https://segmentfault.com/img/remote/1460000015363888); 概述 进行SpringBoot的Web开发过程中,我们很多时候经常需要重启Web服务器才能保证修改的 源代码文件、或者一些...

    ixlei 评论0 收藏0
  • SpringBoot应用部署于外置Tomcat容器

    摘要:但考虑到实际的情形中,我们的服务器一般是另外部署好了的,有专门的维护方式。此时我们需要剥离掉应用内置的服务器,进而将应用发布并部署到外置的容器之中,本文就实践一下这个。 showImg(https://segmentfault.com/img/remote/1460000015173574); 0x01. 概述 SpringBoot平时我们用的爽歪歪,爽到它自己连Tomcat都自集成...

    draveness 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<