Docker系列之镜像瘦身(五)
前言
本节我们来讲讲在我们在构建镜像过程中不出问题,同时使得最后所构建的镜像文件大小尽可能最小,温馨提示:文中大图均可点击放大查看详细信息。
缓存(cache)
Docker的优势之一在于提供了缓存,加速镜像迭代构建,我们知道构建镜像使用docker build命令,也就是说通过docker build的缓存机制实现了镜像的复用,不仅节省镜像存储空间,也为镜像构建节省了大量时间。
Docker会由上至下逐步执行Dockerfile中的指令,按顺序执行每个指令,在检查每条指令时,Docker在其缓存中查找现有的中间图像,可能会重用而不是创建新的中间图像,如果缓存无效,则使其无效的指令和后续所有Dockerfile指令都会重新生成新的中间镜像。一旦缓存失效,就可以使用Dockerfile中的其余指令,所以从Dockerfile的顶部开始,如果基础映像(父镜像)已经在缓存中,则重用。然后继续执行下一条指令与从该基础图像导出的高速缓存中所有子镜像进较,比较每个缓存的中间镜像以查看指令是否找到并缓存是否命中,如果高速缓存未命中,则高速缓存无效,如此重复执行以上过程,最终到达Dockerfile的末尾。大多数新指令只是与中间镜像中的指令进行比较,如果匹配,则使用缓存副本。比如,当在Dockerfile中执行RUN pip install -r test.txt指令时,Docker会在其本地缓存的中间图像中搜索相同的指令,但是旧的和新的test.txt文件中的内容不会进行比较。如果我们使用新软件包更新test.txt文件并使用RUN pip install指令希望使用新软件包名称重新运行软件包安装,如果是这种情况可能会出现问题。同时呢,ADD和COPY与其他Docker指令不同,ADD和COPY指令需要Docker查看文件中的内容以确定是否存在缓存命中,Docker将会引用文件内容的校验和与现有中间图像中的校验和进行比较,如果文件内容或元数据已更改,则缓存无效。
从如上我们对Dokcer缓存机制的大致讲解,若我们对指令进行了更改,那么该指令的后续每一层可能会经常重建,所以为了更好的利用缓存,我们需要将可能需要更改的指令尽可能的放在比较低的位置。当我们在构建镜像时我们可以指定参数(--no-cache=true)来关闭缓存。当我们需要更新源时,我们通过链式调用apt-get-update和apt-get-install来避免缓存丢失问题。
在Docker中我们可以通过命令来监控文件镜像和容器文件大小,我们知道 docker container ls 命令查看容器列表, docker container ls -s 则可以查看容器大小,如下:

为了查看镜像构建中中间镜像历史记录,使用命令 docker image history imagename:tag ,为了更清晰看到镜像中每一层的内容,我们可以使用库https://github.com/wagoodman/dive,比如我们上一节所构建的镜像为webapi。我们安装完dive库后,然后查看镜像中的每一层,通过如下命令。
docker run --rm -it \
-v /var/run/docker.sock:/var/run/docker.sock \
quay.io/wagoodman/dive:latest \
webapi:latest

文件忽略(.dockerignore)
我们知道Docker有两个组件:客户端和守护进程,当我们编写docker命令时,我们使用客户端向Docker deamon发送命令,该命令执行所有工作,这里我们需要知道客户端和守护进程可以单独部署到两台独立机器上,为了让Docker守护进程使用docker build从Dockerfile文件中构建映像,客户端需要向其发送执行命令的“上下文”, 上下文基本上可以说是传递给docker build命令的目录中的所有文件,使用Dockerfile构建时,我们在客户端可以清楚看到发送的上下文,例如如下:

对于大型项目而言,上下文可能会变得非常大,毫无疑问这将会减缓通过Dockerfile构建镜像的速度,因为我们必须等待客户端将所有文件发送到守护进程。比如在ASP.NET Core应用程序中,在项目根目录下可能包含大量文件,这些文件对于大多数Dockerfile构建来说都不是必需的,比如Git文件或者SVN文件,obj、bin等文件, 所有这些附加文件在作为上下文的一部分发送时会减慢构建速度。docker为我们提供了解决方案,我们可以通过在根目录中创建.dockerignore文件来忽略不需要的文件,.dockerignore类似于.gitignore文件,其中包含Docker与文件名匹配的模式列表,并在制作镜像时忽略,比如如下忽略

当我们在客户端执行docker build命令来创建映像时,Docker会检查.dockerignore文件,如果存在此文件,它会逐行浏览文件并使用Go的filepath.Match规则以及Docker自身的一些规则来匹配文件名以此来进行忽略。比如在.dockerignore文件中包含* .vs将排除带有.vs扩展名的文件。我们可以使用以#开头的注释来解释在.dockerignore中正在执行的操作。 .dockerignore可以帮助减小镜像大小,文件越少意味着镜像越小,镜像越快,减少构建缓存失效,如果日志或其他文件正在更改,并且我们的镜像因其缓存而使其缓存失效,则会降低构建周期。综上我们针对需要使得我们所构建的镜像可以注意以下几方面:
1.使用官方镜像,可能很多文章或博客讲解的镜像已过时。
2.若可能,尽可能使用Alpine镜像,以保持镜像轻量级。
3.如果使用apt,在同一指令中将RUN apt-get update与apt-get install结合使用, 然后在该链式指令中链接多个包, 使用\字符在多行中按字母顺序列出包,最后使用rm -rf /var/lib/apt/lists/* 的目的在于清除apt缓存而不会使其缓存保存到镜像层上。 例如:RUN apt-get update && apt-get install -y \package-one \package-two && rm -rf /var/lib/apt/lists/*
4.将可能需要更改的指令尽量放在Dockerfile比较低的位置(可能的话)
5..使用.dockerignore文件将不需要的和不必要的文件留在镜像之外。
6.可以尝试结合使用dive库监控镜像层,然后合理优化镜像大小。
.NET Core使用Docker优化镜像大小
接下来我们来一起看看针对上一节所写的Dockerfile文件进行分析,看看是否可以为镜像瘦身而进一步优化,上一节的构建镜像文件说明书如下:

首先我们获取基础镜像,然后只是复制项目文件而不是复制所有文件,这可以避免额外无关的还原,并允许我们重用中间镜像层,如果我们更改项目文件,只是会再次来一遍重新复制,这也就意味着更快的构建!如果是自包含的应用程序,我们下载对应的镜像而不包含运行时镜像,这样镜像大小最小,同时最后运行时自包含应用程序则无需使用dotnet命令,直接切换到项目根目录通过CMD执行即可。
移除未使用代码
FROM mcr.microsoft.com/dotnet/core/sdk:2.2-stretch AS build WORKDIR /app COPY *.csproj ./
RUN dotnet restore COPY . ./ RUN dotnet add package Microsoft.Packaging.Tools.Trimming -v 1.1.-preview1-- RUN dotnet publish -c Release -o out -r linux-arm /p:LinkDuringPublish=true FROM mcr.microsoft.com/dotnet/core/aspnet:2.2-stretch-slim AS runtime
WORKDIR /app COPY --from=build /app/out . ENV ASPNETCORE_URLS=http://+:8080 ENTRYPOINT ["dotnet", "WebApi.dll"]



由如上第一张图我们可以看到,当我们添加了忽略文件后,它将上下文从4.206MB减少到16.9KB,而无需花费更多时间来发送上下文,现在可以说是秒送。
总结
本节我们详细讲解了从哪几方面入手来瘦身镜像,下一节我们深入讲讲Docker中的网络内容,感谢您的阅读,下节再会。
Docker系列之镜像瘦身(五)的更多相关文章
- docker nginx-php容器镜像瘦身优化
1. 在安装好php环境的容器,参考上面贴出的链接那篇文章的部分,做好基础工作: #创建工作目录 mkdir /rootfs #进入工作目录 cd /rootfs #创建基础目录 mkdir -p b ...
- docker镜像瘦身思路
docker镜像瘦身思路 一.简介 docker镜像太大,带来了以下几个问题: 存储开销 这块影响其实不算很大,因为对服务器磁盘来说,15GB的存储空间并不算大,除非用户服务器的磁盘空间很紧张 部署时 ...
- Docker系列-(2) 镜像制作与发布
上篇文章引入了Docker的基本原理和操作,本节文章主要介绍如何制作Docker镜像和发布. 镜像文件结构 Docker镜像的本质是一系列文件的集合,这些文件依次叠加,形成了最后的镜像文件,类似于下图 ...
- 三个技巧帮助Docker镜像瘦身
在构建Docker容器时,应该尽量想办法获得体积更小的镜像,因为传输和部署体积较小的镜像速度更快. 但RUN语句总是会创建一个新层,而且在生成镜像之前还需要使用很多中间文件,在这种情况下,该如何获得体 ...
- Android性能优化系列之apk瘦身
Android性能优化系列之布局优化 Android性能优化系列之内存优化 为什么APK要瘦身.APK越大,在下载安装过程中.他们耗费的流量会越多,安装等待时间也会越长:对于产品本身,意味着下载转化率 ...
- Docker容器镜像瘦身的三个小窍门(转)
[转自:http://dockone.io/article/8174] 在构建Docker容器时,我们应尽可能减小镜像的大小.使用共享层的镜像尺寸越小,其传输和部署速度越快. 不过在每个RUN语句都会 ...
- docker 系列 - 基础镜像环境和Docker常用命令整理
=======================docker 基础镜像环境 alpine=======================可以使用 docker search 命令搜索指定的 image, ...
- docker系列之镜像服务器
docker 的镜像服务器 docker-registry 是 docker 项目的组成部分. 前面在谈 docker 的命令时, 它的 pull/push 命令就是和镜像服务器打交道. 并且, do ...
- 我可以减肥失败,但我的 Docker 镜像一定要瘦身成功!
作者|徐伟 来源|尔达 Erda 公众号 简介 容器镜像类似于虚拟机镜像,封装了程序的运行环境,保证了运行环境的一致性,使得我们可以一次创建任意场景部署运行.镜像构建的方式有两种,一种是通过 do ...
随机推荐
- Java项目案例之---登录和修改(JSP)
登录和修改(JSP) 通过案例学习jsp的常用知识点: 1.创建一个Map集合,用于存放学生信息,将学生信息存入Map中 2.通过page将需要的包导入 3.用request.getParameter ...
- Android/AndroidStudio/idea使用教程之git使用(详细)(码云)
已经安装好了AndroidStudio,安装教程 本教程是作者自己摸索出来的,有不足之处还请大家海涵.多多拍砖,互相学习. 第一步:下载git,安装git客户端 直接百度git,下载git 安装g ...
- jmeter性能小试全流程
大纲: 1.添加线程组:虚拟用户 2.添加测试对象:比如http请求 3.查看结果 一.添加线程组. 1.线程是what: JMeter是由Java实现的,并且使用一个Java线程来模拟一个用户,因此 ...
- Windows环境下main()函数传入参数
最近几天在写一个模仿windows自带的ping程序,也从网上找过一些源码,但大都需要向主函数main中传入参数,这里简单总结一下向主函数中传参的方法. 方法一:项目->属性->调试-&g ...
- Python基础总结之第五天开始【认识简单的条件语句,也可以叫判断语句】(新手可相互督促)
周五更新很累... 坚持,年薪20万又进了一步~~ python中的条件语句以[ if ]开头,条件语句成立时,运行该代码块,如果条件不成立,则跳过该代码块,执行后面的代码块. 简单的小示例: 输入性 ...
- 手写C语言字符库
鉴于以前碰到过很多这样的题目,甚至上次月考核也考了,马上就要考试了,就再重新写一遍,加深印象,但是肯定和库函数有区别,丢失许多细节 1.strlen函数(求字符串长度) int strlen(char ...
- http的无状态
无状态协议是指协议对务处理没有记忆能力.缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大.另一方面,在服务器不需要先前信息时它的应答就较快. Http协议不 ...
- Selenium浏览器自动化测试框架
selenium简介 介绍 Selenium [1] 是一个用于Web应用程序测试的工具.Selenium测试直接运行在浏览器中,就像真正的用户在操作一样.支持的浏览器包括IE(7, 8, 9, 1 ...
- Linux学习笔记03
一.Linux常见命令 file:查看文件类型(windows用扩展名识别文件类型) 语法:file [options] [args] -b:显示结果时,不显示文件名 -c:显示执行file命令的执行 ...
- python 的几种数据类型
列表 列表是 Python 的主力数据类型.当提到 " 列表 " 时,您脑海中可 能会闪现" 必须进一步声明大小的数组,只能包含同一类对象 " 等想法.千 ...