为什么Docker容器镜像这么大?

我通过Fedora的Dockerfile(最初为320 MB)制作了一个简单的图像。

添加了Nano(这个1MB大小的微型编辑器),图像的大小已经上升到530 MB。 我已经添加了Git(30-MB),然后我的图像大小天空火箭到830 MB。

疯了吗?

我试图导出和导入容器来删除历史/中间图像。 这项工作节省了25 MB,现在我的图像大小是804 MB。 我也试着在一个RUN上运行很多命令,但是我仍然得到了相同的初始830MB。

我怀疑是否值得使用Docker。 我的意思是,我几乎没有安装任何东西,而我正在打1GB。 如果我不得不添加一些像数据库这样严重的东西,我可能会用完磁盘空间。

任何人都有可笑的大小的图像? 你如何解决?

除非我的Dockerfile是非常不正确的?

 FROM fedora:latest MAINTAINER Me NotYou <email@dot.com> RUN yum -y install nano RUN yum -y install git 

但很难想象这里会出现什么问题。

正如@rexposadas所说,图像包含了所有的图层,每个图层都包含了您所安装的所有依赖项。 还有一点很重要,那就是基本映像(比如fedora:latest往往是非常简单的,你可能会惊讶于安装的软件所依赖的数量。

我可以通过将yum -y clean all添加到每行来使安装显着缩小:

 FROM fedora:latest RUN yum -y install nano; yum -y clean all RUN yum -y install git; yum -y clean all 

对于每个RUN,在提交图层之前执行此操作非常重要,否则删除操作不会实际删除数据。 也就是说,在联合/写时复制文件系统中,最后的清理并不能真正减less文件系统的使用,因为真正的数据已经被委托给较低层。 为了解决这个问题,你必须清理每一层。

 $ docker history bf5260c6651d IMAGE CREATED CREATED BY SIZE bf5260c6651d 4 days ago /bin/sh -c yum -y install git; yum -y clean a 260.7 MB 172743bd5d60 4 days ago /bin/sh -c yum -y install nano; yum -y clean 12.39 MB 3f2fed40e4b0 2 weeks ago /bin/sh -c #(nop) ADD file:cee1a4fcfcd00d18da 372.7 MB fd241224e9cf 2 weeks ago /bin/sh -c #(nop) MAINTAINER Lokesh Mandvekar 0 B 511136ea3c5a 12 months ago 0 B 

Docker的图片并不大,你只是build立大的图片。

scratch图像是0B ,如果可以将代码编译为静态二进制文件,则可以使用它来打包代码。 例如,您可以编译Go程序并将其打包在头顶上,以制作一个小于5MB的完全可用的图像。

关键是不要使用官方的Docker镜像,它们太大了。 从头开始并不是那么实际,所以我build议使用Alpine Linux作为您的基本映像。 它是~5MB,然后只添加你的应用程序所需的东西。 这篇关于Microcontainers的文章向您展示了如何在Alpine基础上构build非常小的图像。 最后, Iron.io为几乎所有的编程语言都提供了一套基于Alpine的图像 。

是的,这些大小是荒谬的,我真的不知道为什么这么less人注意到这一点。

我做了一个实际上是最小的Ubuntu镜像(不像其他所谓的“最小”镜像)。 这叫做textlab/ubuntu-essential ,有textlab/ubuntu-essential

 FROM textlab/ubuntu-essential RUN apt-get update && apt-get -y install nano 

上图是安装nano后的82MB。

 FROM textlab/ubuntu-essential RUN apt-get update && apt-get -y install nano git 

Git有更多的先决条件,所以图像变大,大约192 MB。 这还不如大多数图像的初始尺寸。

你也可以看看我写的为Docker制作最小的Ubuntu镜像的脚本 。 你也许可以适应Fedora,但是我不确定你能卸载多less。

这里有一些你可以做的事情 :

  • 尽可能避免多个RUN命令。 将一个RUN命令放入一个RUN命令(使用&&
  • 清理不必要的工具,比如wget或者git(你只需要下载或者构build东西,而不是运行你的程序)

有了这些和@Andy和@michau的build议,我可以将我的nodejs映像从1.062 GB调整到542 MB。

编辑:更重要的是: “我花了一段时间才明白,每个Dockerfile命令都会创build一个带有deltas的新容器。[…]如果你在后面的命令中使用rm -rf命令,他们继续存在于一些中间层的容器中“。 所以现在我设法把apt-get installwgetnpm install (用git依赖)和apt-get remove到一个RUN命令中,所以现在我的映像只有438MB。

编辑29/06/17

在Docker v17.06中,有一个Dockerfiles的新function:在一个Dockerfile中可以有多个FROM语句,只有最后一个FROM的东西会在你的最终的Docker镜像中。 这对于缩小图像大小非常有用,例如:

 FROM nodejs as builder WORKDIR /var/my-project RUN apt-get install ruby python git openssh gcc && \ git clone my-project . && \ npm install FROM nodejs COPY --from=builder /var/my-project /var/my-project 

将导致只有nodejs基本映像的图像加上/ var / my-project从第一步的内容 – 但没有 ruby,python,git,openssh和gcc!

以下帮助了我很多:

删除我的容器内的未使用的软件包(例如redis 1200 mb释放)后,我做了以下工作:

  1. docker export [containerID] -o containername.tar
  2. docker导入-m“在这里提交消息”containername.tar imagename:标签

图层变平。 新图像的大小将会变小,因为我已经从上面所述的容器中移除了包。

这花了很多时间来理解这个,这就是为什么我添加了我的评论。

Docker壁球是一个非常好的解决scheme。 你可以在最后一步$packagemanager clean而不是每一行,然后运行一个docker squash来摆脱所有的图层。

https://github.com/jwilder/docker-squash

对于最佳实践,您应该执行单个RUN命令,因为Dockerfile中的每个RUN指令都会在映像中写入一个新层,并且每个层都需要额外的磁盘空间。 为了保持数字图层的最小化,任何文件操作,如安装,移动,提取,删除等,理想情况下应该在一个单一的运行指令

 FROM fedora:latest RUN yum -y install nano git; yum -y clean all 

是的层系统是相当惊人的。 如果您有一个基础图像,并通过执行以下操作来增加它:

 # Test # # VERSION 1 # use the centos base image provided by dotCloud FROM centos7/wildfly MAINTAINER JohnDo # Build it with: docker build -t "centos7/test" test/ # Change user into root USER root # Extract weblogic RUN rm -rf /tmp/* \ && rm -rf /wildfly/* 

图像的大小完全相同。 这实际上意味着,你必须设法将你的RUN步骤放到很多的提取,安装和清理魔法中,使得图像和安装的软件一样小。

这使得生活变得更加困难。

dockerBuild缺less提交的RUN步骤。