Docker系列之镜像瘦身(五)

前言

本节咱们来说讲在咱们在构建镜像过程当中不出问题,同时使得最后所构建的镜像文件大小尽量最小,舒适提示:文中大图都可点击放大查看详细信息。linux

缓存(cache)

Docker的优点之一在于提供了缓存,加速镜像迭代构建,咱们知道构建镜像使用docker build命令,也就是说经过docker build的缓存机制实现了镜像的复用,不只节省镜像存储空间,也为镜像构建节省了大量时间。git

 

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将会引用文件内容的校验和与现有中间图像中的校验和进行比较,若是文件内容或元数据已更改,则缓存无效。github

 

从如上咱们对Dokcer缓存机制的大体讲解,若咱们对指令进行了更改,那么该指令的后续每一层可能会常常重建,因此为了更好的利用缓存,咱们须要将可能须要更改的指令尽量的放在比较低的位置。当咱们在构建镜像时咱们能够指定参数(--no-cache=true)来关闭缓存。当咱们须要更新源时,咱们经过链式调用apt-get-update和apt-get-install来避免缓存丢失问题。web

 

在Docker中咱们能够经过命令来监控文件镜像和容器文件大小,咱们知道 docker container ls 命令查看容器列表, docker container ls -s 则能够查看容器大小,以下:docker

为了查看镜像构建中中间镜像历史记录,使用命令 docker image history imagename:tag ,为了更清晰看到镜像中每一层的内容,咱们可使用库https://github.com/wagoodman/dive,好比咱们上一节所构建的镜像为webapi。咱们安装完dive库后,而后查看镜像中的每一层,经过以下命令。api

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能够帮助减少镜像大小,文件越少意味着镜像越小,镜像越快,减小构建缓存失效,若是日志或其余文件正在更改,而且咱们的镜像因其缓存而使其缓存失效,则会下降构建周期。综上咱们针对须要使得咱们所构建的镜像能够注意如下几方面:app

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执行便可。

咱们使用预发布的包工具《https://www.nuget.org/packages/Microsoft.Packaging.Tools.Trimming/1.1.0-preview1-25818-01》,经过它咱们能够查看应用程序并删除没有调用的代码和二进制文件,接下来咱们包括Microsoft.Packaging.Tools.Trimming添加包以及忽略文件基于上一节构建镜像进行以下改造。
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.0-preview1-25818-01

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中的网络内容,感谢您的阅读,下节再会。 

相关文章
相关标签/搜索