你在使用哪种编程语言?快来投票,亲手选出你心目中的编程语言之王 了解详情
写点什么

如何给 Docker 镜像瘦身?

2019 年 3 月 12 日

如何给Docker镜像瘦身?

在本文中,你将了解如何加快 Docker 构建周期并创建轻量级镜像。还是用比喻来说吧,给 Docker 镜像瘦身就跟我们减肥一样,减肥时期我们吃沙拉,拒绝披萨、甜甜圈和百吉饼。


这是备忘单。


FROM:指定基础(父)镜像。


标签:提供元数据。这里是包含维护者信息的好地方。


ENV:设置一个持久环境变量。


RUN:运行一个命令并创建一个图像层。用于将包安装到容器中。


COPY:将文件和目录复制到容器中。


ADD:将文件和目录复制到容器中。可以上传本地.tar 文件中。


CMD:为正在执行的容器提供命令和参数。可以覆盖参数。只能有一个 CMD。


WORKDIR:为下面的指令设置工作目录。


ARG:在构建时传递给 Docker 的变量。


ENTRYPOINT:为正在执行的容器提供命令和参数。关于这件事的争论一直在持续。


EXPOSE:公开端口。


VOLUME:创建一个目录挂载点来访问和存储持久数据。


现在让我们看看如何设计 dockerfile,以便在开发镜像和提取容器时节省时间。


缓存

Docker 的优点之一是提供缓存,帮助你更快地迭代镜像构建。


在构建映像时,Docker 按步骤遍历 Dockerfile 中的指令,按顺序执行每个指令。在检查每个指令时,Docker 会在其缓存中寻找一个可以重用的现有中间镜像,而不是创建一个新的(重复的)中间映像。


如果缓存无效,让无效的指令和所有后续 Dockerfile 指令生成新的中间镜像。一旦缓存失效,Dockerfile 中其余的指令也就失效了。


因此,从 Dockerfile 的顶部开始,如果基础镜像已经在缓存中,那么它将被重用。这将是高效命中。否则,缓存无效。



也是一击


然后将下一条指令与从该基础镜像派生的缓存中的所有子镜像进行比较。比较每个缓存的中间镜像,看指令是否在缓存命中。如果缓存失败,则缓存无效。重复相同的过程,直到到达 Dockerfile 的末尾。


大多数新指令只是简单地与中间镜像中的指令进行比较。如果匹配,则使用缓存的副本。


例如,当在 Dockerfile 中找到RUN pip install -r requiremtes .txt指令时,Docker 会在本地缓存的中间镜像中搜索相同的指令。不比较新旧 requirements.txt 文件的内容。


如果使用新包来更新 requirements.txt 文件,并使用RUN pip install并希望使用新包名称重新运行包安装,则此行为可能会出现问题。我一会儿会展示一些解决方案。


与其他 Docker 指令不同,ADD 和 COPY 指令确实需要 Docker 查看文件的内容,以确定是否存在缓存命中。将引用文件的校验和与现有中间镜像中的校验和进行比较。如果文件内容或元数据发生了更改,则缓存无效。


下面是一些有效使用缓存的技巧。


  • 可以通过传递--no-cache=Truedocker build关闭缓存。

  • 如果你要对指令进行更改,那么接下来的每一层都将频繁地重新构建。要利用缓存,请在 Dockerfile 中尽可能低地放置可能更改的指令。

  • 链接RUN apt-get updateapt-get install命令,以避免缓存丢失问题。

  • 如果你正在使用带有 requirements.txt 文件的包安装程序(如 pip),那么请遵循如下模型,以确保你不会收到带有 requirements.txt 中列出的旧包的陈旧的中间镜像。


COPY requirements.txt /tmp/RUN pip install -r /tmp/requirements.txtCOPY . /tmp/
复制代码


这些是有效使用 Docker 构建缓存的建议。


减小尺寸

Docker 镜像可能会变得很大。你想让它们尺寸变小,这样它们就可以快速拉起,使用很少的资源。让我们给你的镜像瘦身!



吃顿沙拉而不是百吉饼


Alpine base 镜像是一个完整的 Linux 发行版,没有太多其他东西。下载通常小于 5mb,但是它需要更多的时间为构建应用程序所需的依赖项编写代码。



Alpine 源自阿尔卑斯山脉


如果你的容器中需要 Python, Python Alpine 构建是一个不错的折衷方案。它包含 Linux 和 Python,你可以提供大多数其他东西。


我用最新的 Python Alpine 构建的带有打印脚本(“hello world”)的镜像大小为 78.5 MB。下面是 Dockerfile:


FROM python:3.7.2-alpine3.8COPY . /appENTRYPOINT [“python”, “./app/my_script.py”, “my_var”]
复制代码


在 Docker Hub 上,基础镜像的大小为 29MB,当构建子镜像时,需要下载并安装 Python,尺寸就变得很大。


除了使用 Alpine 基础镜像,另一种减小镜像大小的方法是使用多级构建。这种技术还会增加 Dockerfile 的复杂性。


多级构建



一个舞台+另一个舞台=多级舞台


多阶段构建使用多个 FROM 指令。你可以有选择地将文件(称为构建工件)从一个阶段复制到另一个阶段。你可以在最终的镜像中扔掉任何你不想要的东西。这种方法可以减少整体镜像的大小。


每个 FROM 指令


  • 开始构建的新阶段

  • 去掉在之前阶段留下的任何状态

  • 可以用不同的基础镜像


下面是Docker文档中经过修改的多级构建示例:


FROM golang:1.7.3 AS buildWORKDIR /go/src/github.com/alexellis/href-counter/RUN go get -d -v golang.org/x/net/html  COPY app.go .RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .FROM alpine:latest  RUN apk --no-cache add ca-certificatesWORKDIR /root/COPY --from=build /go/src/github.com/alexellis/href-counter/app .CMD ["./app"]
复制代码


注意,我们通过给 FROM 指令增加一个名字来命名第一阶段。然后,被命名的阶段会通过COPY --from=指令引用到 Dockerfile 中。


在制造大量容器的情况下,多级构建是有意义的。多级构建可以帮助你从镜像大小中挤出每一寸空间。然而,有时多阶段构建会增加复杂性,使镜像更难维护,因此你可能不会在大多数构建中使用它们。参见此处对折衷高级模式的进一步讨论。


相反,每个人都应该使用.dockerignore 文件来帮助保持 Docker 镜像的简洁。


.dockerignore

如果你对 Docker 了解得足够多,那么*.dockerignore*就是一些你应该知道的东西。


.dockerignore 类似于.gitignore。它是一个包含 Docker 模式列表的文件,Docker 在生成镜像时需要匹配文件名并排除这些模式。



来.dockerignore 一下


将.dockerignore 文件与 Dockerfile 和构建上下文的其余部分放在同一个文件夹中。


运行 docker build 创建镜像时,docker 检查.dockerignore 文件。如果找到一个,则逐行检查文件并使用 Go 的filepath。匹配规则——以及Docker自己的一些规则——以匹配文件名以进行排除。想想 unix 风格的 glob 模式,而不是正则表达式。


因此*.jpg将排除扩展名为.jpg 的文件。并且视频将排除视频文件夹及其内容。


您可以使用以#开头的注释来解释您在.dockerignore 中所做的事情。


使用.dockerignore 从 Docker 镜像中排除不需要的文件是个好主意。


  • 帮助你保守秘密。没有人想在镜像中使用密码。

  • 减少镜像大小。更少的文件意味着更小、更快的镜像。

  • 减少构建缓存失效。如果日志或其他文件正在发生变化,而你的镜像缓存因此而失效,则会减慢构建周期。


这就是使用.dockerignore 文件的原因。


尺寸检查

让我们看看如何从命令行找到 Docker 镜像和容器的大小。


  • 要查看正在运行的容器的大致大小,可以使用docker container ls -s命令。

  • 运行docker image ls显示镜像的大小。

  • 要查看组成镜像的中间镜像大小,请使用docker image history my_image:my_tag

  • 运行Docker image inspect my_image:tag:该标签将显示跟镜像有关的信息,包括每个层的大小。图层与构成镜像略有不同。但是你可以把它们看成是一样的。

  • 安装和使用dive可以很容易地看到你的层内容。


现在,让我们来看看一些最佳实践来给镜像瘦身。


减少镜像大小和构建时间的八个最佳实践

  1. 尽可能使用正式的基础镜像。官方镜像定期更新,比非官方镜像更安全。

  2. 在可能的情况下使用不同的 Alpine 镜像,以保持你的镜像轻量级。


3.如果使用 apt,请在同一指令中将 RUN apt-get update 与 apt-get install 结合使用。然后在该指令中链接多个包。用\字符在多行上按字母顺序列出包。例如:


RUN apt-get update && apt-get install -y \    package-one \    package-two  && rm -rf /var/lib/apt/lists/*
复制代码


这种方法减少了要构建的层的数量,并保持简洁。


  1. 在运行指令的末尾包含&& rm -rf /var/lib/apt/lists/*,以清理 apt 缓存,使其不存储在层中。

  2. 聪明地使用缓存,将可能发生更改的指令放在 Dockerfile 中。

  3. 使用.dockerignore 文件将不需要的和不必要的文件从镜像中删除。

  4. 查看dive——它的一个非常酷的工具,可以检查你的 Docker 镜像层,并帮助你削减多余的部分。

  5. 不要安装你不需要的软件包。唉!但这种现象很常见。


总结

现在你知道了如何使 Docker 镜像快速构建、快速下载,并且不占用太多空间。和健康饮食一样,知道是成功的一半。享受你的蔬菜。



健康和美味


查看英文原文链接:https://towardsdatascience.com/slimming-down-your-docker-images-275f0ca9337e


2019 年 3 月 12 日 15:006876
用户头像

发布了 124 篇内容, 共 36.1 次阅读, 收获喜欢 157 次。

关注

评论 5 条评论

发布
用户头像
图片再次丢失
2021 年 03 月 04 日 14:51
回复
用户头像
配图已挂!!
2019 年 03 月 13 日 14:21
回复
已修复。
2019 年 03 月 13 日 15:14
回复
用户头像
骷髅图和沙拉不太搭配啊。。。
2019 年 03 月 12 日 21:06
回复
非礼勿听、非礼勿言、非礼勿视?
2019 年 03 月 13 日 15:15
回复
没有更多了
发现更多内容

SpringSecurity基础——权限管理

程序员小毕

Java 源码 程序员 安全 springsecurity

MySQL 8.0.23中复制架构从节点自动故障转移

程序员小毕

Java MySQL 架构 高可用 MySQL优化

阿里巴巴正式推出2021年金三银四1000道Java工程师面试题手册(含答案)

Java架构追梦

Java 阿里巴巴 架构师 金三银四 1000道面试题

安卓驱动开发!系统盘点Android开发者必须掌握的知识点,搞懂这些直接来阿里入职

欢喜学安卓

android 程序员 面试 移动开发

百度信息流和搜索业务中的弹性近线计算探索与应用 | 文末送福利

百度Geek说

Java 前端工程 算法工程师 技术宅

阿里Java性能优化最佳实践指南全新发布!(编程、多线程、JVM、设计模式、数据库优化全都有)

程序员小毕

Java 面试 性能优化 JVM 数据库调优

不明白线程池?那看看这篇,附10道面试题

田维常

线程池

十年运维经验总结出的智能运维系统落地方案

小术晓术

人工智能 运维 企业信息化 运维自动化 信息化

前端知识总结输出文章目录大全

梁龙先森

JavaScript 前端 编程语言 28天写作

【CSS】波纹效果

学习委员

CSS小技巧 28天写作 纯CSS

漫谈HTTP协议

架构精进之路

HTTP 七日更 28天写作

高阶段位机房管理:3D集装箱数据中心,触发科技“火苗”的燃烧

一只数据鲸鱼

数据可视化 3D可视化 机房管理 数据中心可视化 集装箱式数据中心

【Android Tips】小厂的扫码还能怎么做?

李小四

机器学习 二维码 扫码 微信扫码

Elasticsearch 批量查询 mget

escray

elastic 七日更 28天写作 死磕Elasticsearch 60天通过Elastic认证考试

【CSS】不规则阴影

学习委员

css3 html/css CSS小技巧 28天写作 纯CSS

Flink + Iceberg 全场景实时数仓的建设实践

Apache Flink

flink

【Mysql-InnoDB 系列】幻读、死锁与事务调度

程序员架构进阶

MySQL 架构 innodb 事务 28天写作

《论雨伞道德》- 不要和自己的良心捉迷藏

石云升

读书笔记 28天写作 雨伞道德

IDEA 异常退出 解决方法

任广印

IDEA

Vue 3自定义指令开发

Geek_Willie

[高并发]高并发分布式锁架构大解密,不是所有的锁都是分布式锁!!

for

android开发面试准备!Android高级工程师进阶学习,已开源

欢喜学安卓

android 程序员 面试 移动开发

微服务容错时,这些技术你要立刻想到

华为云开发者社区

微服务 线程 服务雪崩 断路器 服务降级

灵雀云Kube-OVN进入CNCF沙箱,成为CNCF首个容器网络项目

York

灵雀云 Kubernetes Kube-OVN

美国大选期间美股迎来大涨,舆情到底有何魔力?

星环科技

人工智能 人工智能大数据

区块链应用底层baas公共服务平台搭建,农产品溯源系统开发

WX13823153201

甲方日常 91

句子

工作 随笔杂谈 日常

即构SDK新增焦点语音功能,可实现特定用户语音的聚焦

ZEGO即构

就业篇 - 如何抉择自己合适的路(二)

小诚信驿站

深度思考 程序员人生 就业 成长笔记 28天写作

CSS实现数据统计

学习委员

前端 CSS小技巧 28天写作 纯CSS

数据中台:建立在数据网络效应之上的赛道

奇点云

大数据 数据中台 云原生 数据

PingCAP DevCon 现场直播

PingCAP DevCon 现场直播

如何给Docker镜像瘦身?-InfoQ