65.9K
CodeProject 正在变化。 阅读更多。
Home

5 个减少 Docker 镜像大小的技巧

starIconstarIconstarIconstarIconstarIcon

5.00/5 (4投票s)

2016 年 9 月 28 日

CPOL

4分钟阅读

viewsIcon

17623

5 个减少 Docker 镜像大小的技巧 Docker 镜像很快会达到 1 GB 或更大。  尽管千兆字节的价格正在下降,但保持 Docker 镜像轻量级将带来一些好处。 这篇文章将向您介绍 5 个技巧,帮助您减小 Docker 镜像大小,以及为什么关注它很重要。

Docker 镜像很快会达到 1 GB 或更大。  尽管千兆字节的价格正在下降,但保持 Docker 镜像轻量级将带来一些好处。 这篇文章将向您介绍 5 个技巧,帮助您减小 Docker 镜像大小,以及为什么关注它很重要。

为什么镜像大小如此重要?

减小 Docker 最终镜像的大小将最终导致

  • 减少构建时间
  • 减少磁盘使用量
  • 减少下载时间
  • 由于占用空间更小,安全性更高
  • 更快的部署

什么是层?

要减小镜像大小,了解什么是层很重要。 每个 Docker 镜像都由多个中间镜像(层)组成,这些中间镜像构成了最终镜像。 这种层堆叠允许 Docker 在找到相似的指令时重用镜像。

每个 Dockerfile 指令在构建时都会创建一个层

FROM ubuntu                  # This base image is already composed of X layers (4 at the time of writing)
MAINTAINER Florian Lopes     # One layer
RUN mkdir -p /some/dir       # One layer
RUN apt-get install -y curl  # One layer

镜像层的概述

让我们构建这个镜像

$ docker build -t curl .
[...]

$ docker images curl
REPOSITORY            TAG            IMAGE ID            CREATED            VIRTUAL SIZE
test                  latest         732afd2af5a9        About an hour ago  199.3 MB

要查看镜像的中间层,请键入以下命令

$ docker history curl
IMAGE               CREATED             CREATED BY                                      SIZE
732afd2af5a9        About an hour ago   /bin/sh -c apt-get install -y curl              11.32 MB
912b76f3dd8e        About an hour ago   /bin/sh -c mkdir -p /some/dir                   0 B
525804109d88        About an hour ago   /bin/sh -c #(nop) MAINTAINER Florian Lopes      0 B
c88b54fedc4f        9 days ago          /bin/sh -c #(nop) CMD ["/bin/bash"]             0 B
44802199e669        9 days ago          /bin/sh -c sed -i 's/^#\s*\(deb.*universe\)$/   1.895 kB
74a2c71e6050        9 days ago          /bin/sh -c set -xe                                                  && echo '#!/bin/sh' > /u   194.5 kB
140d9fb3c81c        9 days ago          /bin/sh -c #(nop) ADD file:ed7184ebed5263e677   187.8 MB

您可以在下方看到,每个层都有一个大小和与之关联的命令来创建它。 从此 Dockerfile 构建的最终镜像包含 3 层以及所有 Ubuntu 镜像层。

虽然这可能有点难以理解,但这种结构非常重要,因为它允许 Docker 缓存层以使构建更快。 在构建镜像时,Docker 守护进程将检查中间镜像(由指令创建的层)是否已存在于其缓存中以重用它。 如果找不到中间层或已更改,Docker 守护进程将拉取或重建它。

如何减小镜像大小

正如我们刚刚看到的,层在最终镜像大小中起着重要作用。 要减小最终大小,我们必须专注于中间层。 尽管其中一些无法减小(尤其是您开始使用的那个),但我们可以使用一些技巧来帮助减小最终镜像大小。

尽可能将命令组合成 一个 指令(不要在多个 RUN 指令中执行多个安装)

安装软件包

单独的指令

为了说明这一点,让我们使用两个单独的 RUN 指令构建一个镜像,该指令安装 curl  mysql-client  软件包

FROM ubuntu:16.04

MAINTAINER Florian Lopes

RUN apt-get update
RUN apt-get install -y curl
RUN apt-get install -y mysql-client
$ docker build  -t tip1 .
[...]
$ docker images tip1 
 REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
 tip1                latest              7e9105c27586        3 minutes ago       248.4 MB

单个指令

现在,让我们将两个指令组合成一个

FROM ubuntu:16.04

MAINTAINER Florian Lopes
RUN apt-get update && apt-get install -y curl mysql-client

让我们再次构建我们的镜像

$ docker build  -t tip1 .
[...]
$ docker images tip1 
REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
tip1                latest              2886d17dc7f4        9 seconds ago       248 MB

尽管大小差异不是那么显著,但当安装多个软件包时,您可以获得更好的结果。

删除软件包

单独的指令

让我们看另一个有趣的例子,在其中我们在单独的指令中删除一个 临时 软件包

FROM ubuntu:16.04                    
MAINTAINER Florian Lopes          
RUN apt-get update && apt-get install -y curl && curl http://[...]
RUN apt-get remove -y curl

您可以在这里看到,curl 软件包在安装后立即在单独的指令中被删除。 让我们看看最终的镜像大小

$ docker build -t tip2 .
[...]
$ docker images tip2 
REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE 
tip1                latest              632f4bf8667c        8 seconds ago       182.7 MB

单个指令

这次,让我们将这些指令组合成一行

FROM ubuntu:16.04
MAINTAINER Florian Lopes
RUN apt-get update && apt-get install -y curl && curl http://[...] && apt-get remove -y curl
$ docker build -t tip3 .
[...]
$ docker images tip3
REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
tip1                latest              bfea5f186684        11 seconds ago      182.1 MB

您可以看到镜像的大小略有减小。 同样,这里的差异不是很大,因为我们只删除一个软件包。

为什么会有差异?

正如我们之前看到的,Docker 守护进程为每个指令创建一个镜像来执行相关的命令。 在单独的指令示例中,所有这些镜像的叠加创建了最终的镜像。 由于这种策略,mysql-client 软件包仍然是最终镜像的一部分(实际上在第三层),尽管稍后被删除。

在单独的指令中删除软件包

在单个指令中删除软件包

安装软件包时,不要安装软件包建议 (–no-install-recommends)

RUN apt-get update apt-get install -y --no-install-recommends curl

如果可能,在 同一个 指令中删除不再需要的软件包或文件

软件包示例

RUN apt-get update && \ 
apt-get install -y --no-install-recommends curl && \
curl http://download.app.com/install.sh && \
.install.sh && apt-get remove -y curl

在此示例中, curl 软件包仅用于检索安装文件。 由于不再需要它,因此可以删除它(在 同一个 指令中)。

文件示例

<code>RUN wget ${APP_URL} -o /tmp/app/install.sh && \
./tmp/app/install.sh && \ rm -rf /tmp/app/ && \
rm -rf /var/lib/apt/lists/*

从更小的基础镜像开始

您是否需要每个 Ubuntu(或其他基础镜像)软件包? 如果没有,您应该考虑从更小的基础镜像开始,例如 Alpine (),它可能会成为所有官方 Docker 镜像的基础镜像 (Jenkins, Maven)。 这种基础镜像的重量约为 5MB,而 Ubuntu 镜像的重量约为 188MB。 您可以在这里看到 Docker 基础镜像的绝佳比较:https://www.brianchristner.io/docker-image-base-os-size-comparison/

检查 DockerHub 中的镜像

要轻松检查 DockerHub 镜像,您可以使用 MicroBadger 服务:https://microbadger.com/

MicroBadger – Ubuntu 层

简而言之

  1. 尽可能将命令组合成 一个 指令
  2. 不要安装软件包建议 (–no-install-recommends)
  3. 同一个 指令中删除不再需要的软件包或文件
  4. 在安装软件包后清理 apt-cache
  5. 从更小的基础镜像开始:Alpine

如果您太忙(或懒惰)而无法专注于减小镜像大小,您可以使用此工具:https://github.com/jwilder/docker-squash

文章 5 个减少 Docker 镜像大小的技巧 首次出现在 Florian Lopes 的博客上。

© . All rights reserved.