如何给Docker镜像瘦身?

\u003cp\u003e在本文中,你将了解如何加快Docker构建周期并创建轻量级镜像。还是用比喻来说吧,给Docker镜像瘦身就跟我们减肥一样,减肥时期我们吃沙拉,拒绝披萨、甜甜圈和百吉饼。\u003c/p\u003e\n\u003cp\u003e这是备忘单。\u003c/p\u003e\n\u003cp\u003eFROM:指定基础(父)镜像。\u003c/p\u003e\n\u003cp\u003e标签:提供元数据。这里是包含维护者信息的好地方。\u003c/p\u003e\n\u003cp\u003eENV:设置一个持久环境变量。\u003c/p\u003e\n\u003cp\u003eRUN:运行一个命令并创建一个图像层。用于将包安装到容器中。\u003c/p\u003e\n\u003cp\u003eCOPY:将文件和目录复制到容器中。\u003c/p\u003e\n\u003cp\u003eADD:将文件和目录复制到容器中。可以上传本地.tar文件中。\u003c/p\u003e\n\u003cp\u003eCMD:为正在执行的容器提供命令和参数。可以覆盖参数。只能有一个CMD。\u003c/p\u003e\n\u003cp\u003eWORKDIR:为下面的指令设置工作目录。\u003c/p\u003e\n\u003cp\u003eARG:在构建时传递给Docker的变量。\u003c/p\u003e\n\u003cp\u003eENTRYPOINT:为正在执行的容器提供命令和参数。关于这件事的争论一直在持续。\u003c/p\u003e\n\u003cp\u003eEXPOSE:公开端口。\u003c/p\u003e\n\u003cp\u003eVOLUME:创建一个目录挂载点来访问和存储持久数据。\u003c/p\u003e\n\u003cp\u003e现在让我们看看如何设计dockerfile,以便在开发镜像和提取容器时节省时间。\u003c/p\u003e\n\u003ch2\u003e缓存\u003c/h2\u003e\n\u003cp\u003eDocker的优点之一是提供缓存,帮助你更快地迭代镜像构建。\u003c/p\u003e\n\u003cp\u003e在构建映像时,Docker按步骤遍历Dockerfile中的指令,按顺序执行每个指令。在检查每个指令时,Docker会在其缓存中寻找一个可以重用的现有中间镜像,而不是创建一个新的(重复的)中间映像。\u003c/p\u003e\n\u003cp\u003e如果缓存无效,让无效的指令和所有后续Dockerfile指令生成新的中间镜像。一旦缓存失效,Dockerfile中其余的指令也就失效了。\u003c/p\u003e\n\u003cp\u003e因此,从Dockerfile的顶部开始,如果基础镜像已经在缓存中,那么它将被重用。这将是高效命中。否则,缓存无效。\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://cdn-images-1.medium.com/max/800/1*FOCF2hBIRuQ0nB8o-VJCxA.jpeg\" alt=\"图片\" /\u003e\u003c/p\u003e\n \u003ccenter\u003e也是一击\u003c/center\u003e\n\u003cp\u003e然后将下一条指令与从该基础镜像派生的缓存中的所有子镜像进行比较。比较每个缓存的中间镜像,看指令是否在缓存命中。如果缓存失败,则缓存无效。重复相同的过程,直到到达Dockerfile的末尾。\u003c/p\u003e\n\u003cp\u003e大多数新指令只是简单地与中间镜像中的指令进行比较。如果匹配,则使用缓存的副本。\u003c/p\u003e\n\u003cp\u003e例如,当在Dockerfile中找到\u003ccode\u003eRUN pip install -r requiremtes .txt\u003c/code\u003e指令时,Docker会在本地缓存的中间镜像中搜索相同的指令。不比较新旧requirements.txt文件的内容。\u003c/p\u003e\n\u003cp\u003e如果使用新包来更新\u003cem\u003erequirements.txt\u003c/em\u003e文件,并使用\u003ccode\u003eRUN pip install\u003c/code\u003e并希望使用新包名称重新运行包安装,则此行为可能会出现问题。我一会儿会展示一些解决方案。\u003c/p\u003e\n\u003cp\u003e与其他Docker指令不同,ADD和COPY指令确实需要Docker查看文件的内容,以确定是否存在缓存命中。将引用文件的校验和与现有中间镜像中的校验和进行比较。如果文件内容或元数据发生了更改,则缓存无效。\u003c/p\u003e\n\u003cp\u003e下面是一些有效使用缓存的技巧。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e可以通过传递\u003ccode\u003e--no-cache=True\u003c/code\u003e给\u003ccode\u003edocker build\u003c/code\u003e关闭缓存。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e如果你要对指令进行更改,那么接下来的每一层都将频繁地重新构建。要利用缓存,请在Dockerfile中尽可能低地放置可能更改的指令。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e链接\u003ccode\u003eRUN apt-get update\u003c/code\u003e和\u003ccode\u003eapt-get install\u003c/code\u003e命令,以避免缓存丢失问题。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e如果你正在使用带有\u003cem\u003erequirements.txt\u003c/em\u003e文件的包安装程序(如pip),那么请遵循如下模型,以确保你不会收到带有\u003cem\u003erequirements.txt\u003c/em\u003e中列出的旧包的陈旧的中间镜像。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cpre\u003e\u003ccode\u003eCOPY requirements.txt /tmp/\nRUN pip install -r /tmp/requirements.txt\nCOPY . /tmp/\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e这些是有效使用Docker构建缓存的建议。\u003c/p\u003e\n\u003ch2\u003e减小尺寸\u003c/h2\u003e\n\u003cp\u003eDocker镜像可能会变得很大。你想让它们尺寸变小,这样它们就可以快速拉起,使用很少的资源。让我们给你的镜像瘦身!\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://cdn-images-1.medium.com/max/800/1*RFi86DbJQy39RjNQrQiD6A.jpeg\" alt=\"图片\" /\u003e\u003c/p\u003e\n\u003ccenter\u003e吃顿沙拉而不是百吉饼\u003c/center\u003e\n\u003cp\u003eAlpine base镜像是一个完整的Linux发行版,没有太多其他东西。下载通常小于5mb,但是它需要更多的时间为构建应用程序所需的依赖项编写代码。\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://cdn-images-1.medium.com/max/800/1*NnmWS0yPVhS_5nKW8jzSLg.jpeg\" alt=\"图片\" /\u003e\u003c/p\u003e\n\u003ccenter\u003eAlpine源自阿尔卑斯山脉\u003c/center\u003e\n\u003cp\u003e如果你的容器中需要Python, Python Alpine构建是一个不错的折衷方案。它包含Linux和Python,你可以提供大多数其他东西。\u003c/p\u003e\n\u003cp\u003e我用最新的Python Alpine构建的带有打印脚本(“hello world”)的镜像大小为78.5 MB。下面是Dockerfile:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003eFROM python:3.7.2-alpine3.8\nCOPY . /app\nENTRYPOINT [“python”, “./app/my_script.py”, “my_var”]\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e在Docker Hub上,基础镜像的大小为29MB,当构建子镜像时,需要下载并安装Python,尺寸就变得很大。\u003c/p\u003e\n\u003cp\u003e除了使用Alpine 基础镜像,另一种减小镜像大小的方法是使用多级构建。这种技术还会增加Dockerfile的复杂性。\u003c/p\u003e\n\u003ch2\u003e多级构建\u003c/h2\u003e\n\u003cp\u003e\u003cimg src=\"https://cdn-images-1.medium.com/max/600/1*DiW3ESMm1z2jAln_I62UAA.jpeg\" alt=\"图片\" /\u003e\u003cimg src=\"https://cdn-images-1.medium.com/max/600/1*8Ww_aVrssjTltt6f3EFQrQ.jpeg\" alt=\"图片\" /\u003e\u003c/p\u003e\n\u003ccenter\u003e一个舞台+另一个舞台=多级舞台\u003c/center\u003e\n\u003cp\u003e多阶段构建使用多个FROM指令。你可以有选择地将文件(称为构建工件)从一个阶段复制到另一个阶段。你可以在最终的镜像中扔掉任何你不想要的东西。这种方法可以减少整体镜像的大小。\u003c/p\u003e\n\u003cp\u003e每个FROM指令\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e开始构建的新阶段\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e去掉在之前阶段留下的任何状态\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e可以用不同的基础镜像\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e下面是\u003ca href=\"https://docs.docker.com/develop/develop-images/multistage-build/\"\u003eDocker文档\u003c/a\u003e中经过修改的多级构建示例:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003eFROM golang:1.7.3 AS build\nWORKDIR /go/src/github.com/alexellis/href-counter/\nRUN go get -d -v golang.org/x/net/html \nCOPY app.go .\nRUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .\nFROM alpine:latest \nRUN apk --no-cache add ca-certificates\nWORKDIR /root/\nCOPY --from=build /go/src/github.com/alexellis/href-counter/app .\nCMD [\u0026quot;./app\u0026quot;]\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e注意,我们通过给FROM指令增加一个名字来命名第一阶段。然后,被命名的阶段会通过\u003ccode\u003eCOPY --from=\u003c/code\u003e指令引用到 Dockerfile中。\u003c/p\u003e\n\u003cp\u003e在制造大量容器的情况下,多级构建是有意义的。多级构建可以帮助你从镜像大小中挤出每一寸空间。然而,有时多阶段构建会增加复杂性,使镜像更难维护,因此你可能不会在大多数构建中使用它们。参见此处对\u003ca href=\"https://blog.realkinetic.com/building-minimal-docker-containers-for-python-applications-37d0272c52f3\"\u003e折衷\u003c/a\u003e和\u003ca href=\"https://medium.com/@tonistiigi/advanced-multi-stage-build-patterns-6f741b852fae\"\u003e高级模式\u003c/a\u003e的进一步讨论。\u003c/p\u003e\n\u003cp\u003e相反,每个人都应该使用.dockerignore文件来帮助保持Docker镜像的简洁。\u003c/p\u003e\n\u003ch1\u003e.dockerignore\u003c/h1\u003e\n\u003cp\u003e如果你对Docker了解得足够多,那么*.dockerignore*就是一些你应该知道的东西。\u003c/p\u003e\n\u003cp\u003e.dockerignore类似于.gitignore。它是一个包含Docker模式列表的文件,Docker在生成镜像时需要匹配文件名并排除这些模式。\u003cbr /\u003e\n\u003cimg src=\"https://cdn-images-1.medium.com/max/800/1*yzTSAJgy7dM9qolu8qx_TA.jpeg\" alt=\"图片\" /\u003e\u003c/p\u003e\n\u003ccenter\u003e来.dockerignore一下\u003c/center\u003e\n\u003cp\u003e将.dockerignore文件与Dockerfile和构建上下文的其余部分放在同一个文件夹中。\u003c/p\u003e\n\u003cp\u003e运行docker build创建镜像时,docker检查.dockerignore文件。如果找到一个,则逐行检查文件并使用Go的\u003ca href=\"https://golang.org/pkg/path/filepath/#Match\"\u003efilepath。匹配规则\u003c/a\u003e——以及\u003ca href=\"https://docs.docker.com/v17.09/engine/reference/builder/#dockerignore-file\"\u003eDocker自己的一些规则\u003c/a\u003e——以匹配文件名以进行排除。想想unix风格的glob模式,而不是正则表达式。\u003c/p\u003e\n\u003cp\u003e因此\u003ccode\u003e*.jpg\u003c/code\u003e将排除扩展名为.jpg的文件。并且\u003ccode\u003e视频\u003c/code\u003e将排除视频文件夹及其内容。\u003c/p\u003e\n\u003cp\u003e您可以使用以\u003ccode\u003e#\u003c/code\u003e开头的注释来解释您在.dockerignore中所做的事情。\u003c/p\u003e\n\u003cp\u003e使用.dockerignore从Docker镜像中排除不需要的文件是个好主意。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e帮助你保守秘密。没有人想在镜像中使用密码。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e减少镜像大小。更少的文件意味着更小、更快的镜像。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e减少构建缓存失效。如果日志或其他文件正在发生变化,而你的镜像缓存因此而失效,则会减慢构建周期。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e这就是使用.dockerignore文件的原因。\u003c/p\u003e\n\u003ch2\u003e尺寸检查\u003c/h2\u003e\n\u003cp\u003e让我们看看如何从命令行找到Docker镜像和容器的大小。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e要查看正在运行的容器的大致大小,可以使用\u003ccode\u003edocker container ls -s\u003c/code\u003e命令。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e运行\u003ccode\u003edocker image ls\u003c/code\u003e显示镜像的大小。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e要查看组成镜像的中间镜像大小,请使用\u003ccode\u003edocker image history my_image:my_tag\u003c/code\u003e。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e运行\u003ccode\u003eDocker image inspect my_image:tag\u003c/code\u003e:该标签将显示跟镜像有关的信息,包括每个层的大小。图层与构成镜像略有不同。但是你可以把它们看成是一样的。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e安装和使用\u003ca href=\"https://github.com/wagoodman/dive\"\u003edive\u003c/a\u003e可以很容易地看到你的层内容。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e现在,让我们来看看一些最佳实践来给镜像瘦身。\u003c/p\u003e\n\u003ch2\u003e减少镜像大小和构建时间的八个最佳实践\u003c/h2\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e尽可能使用正式的基础镜像。官方镜像定期更新,比非官方镜像更安全。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e在可能的情况下使用不同的Alpine镜像,以保持你的镜像轻量级。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e3.如果使用apt,请在同一指令中将RUN apt-get update与apt-get install结合使用。然后在该指令中链接多个包。用\\字符在多行上按字母顺序列出包。例如:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003eRUN apt-get update \u0026amp;\u0026amp; apt-get install -y \\\n package-one \\\n package-two \n \u0026amp;\u0026amp; rm -rf /var/lib/apt/lists/*\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e这种方法减少了要构建的层的数量,并保持简洁。\u003c/p\u003e\n\u003col start=\"4\"\u003e\n\u003cli\u003e\n\u003cp\u003e在运行指令的末尾包含\u003ccode\u003e\u0026amp;\u0026amp; rm -rf /var/lib/apt/lists/*\u003c/code\u003e,以清理apt缓存,使其不存储在层中。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e聪明地使用缓存,将可能发生更改的指令放在Dockerfile中。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e使用.dockerignore文件将不需要的和不必要的文件从镜像中删除。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e查看\u003ca href=\"https://github.com/wagoodman/dive\"\u003edive\u003c/a\u003e——它的一个非常酷的工具,可以检查你的Docker镜像层,并帮助你削减多余的部分。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e不要安装你不需要的软件包。唉!但这种现象很常见。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2\u003e总结\u003c/h2\u003e\n\u003cp\u003e现在你知道了如何使Docker镜像快速构建、快速下载,并且不占用太多空间。和健康饮食一样,知道是成功的一半。享受你的蔬菜。\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://cdn-images-1.medium.com/max/1200/1*Stn2tBUIPslHrfaFsRAZDQ.jpeg\" alt=\"图片\" /\u003e\u003c/p\u003e\n\u003ccenter\u003e健康和美味\u003c/center\u003e\n\u003cp\u003e查看英文原文链接:\u003ca href=\"https://towardsdatascience.com/slimming-down-your-docker-images-275f0ca9337e\"\u003ehttps://towardsdatascience.com/slimming-down-your-docker-images-275f0ca9337e\u003c/a\u003e\u003c/p\u003e\n

你可能感兴趣的:(如何给Docker镜像瘦身?)