加入收藏 | 设为首页 | 会员中心 | 我要投稿 云计算网_泰州站长网 (http://www.0523zz.com/)- 视觉智能、AI应用、CDN、行业物联网、智能数字人!
当前位置: 首页 > 服务器 > 搭建环境 > Windows > 正文

如何打造更小巧的容器镜像

发布时间:2019-03-28 20:35:56 所属栏目:Windows 来源:Chris Collins
导读:副标题#e# 五种优化 Linux 容器大小和构建更小的镜像的方法。 Docker 近几年的爆炸性发展让大家逐渐了解到容器和容器镜像的概念。尽管 Linux 容器技术在很早之前就已经出现,但这项技术近来的蓬勃发展却还是要归功于 Docker 对用户友好的命令行界面以及使用

以下这个 Dockerfile 基于 golang:1.8 镜像构建一个小的 Hello World 应用程序镜像:

  1. FROM golang:1.8
  2.  
  3. ENV GOOS=linux
  4. ENV appdir=/go/src/gohelloworld
  5.  
  6. COPY ./ /go/src/goHelloWorld
  7. WORKDIR /go/src/goHelloWorld
  8.  
  9. RUN go get
  10. RUN go build -o /goHelloWorld -a
  11.  
  12. CMD ["/goHelloWorld"]

构建出来的镜像中包含了二进制文件、源代码以及基础镜像层,一共 716MB。但对于应用程序运行唯一必要的只有编译后的二进制文件,其余内容在镜像中都是多余的。

如果在编译的时候通过指定参数 CGO_ENABLED=0 来禁用 cgo,就可以在编译二进制文件的时候忽略某些函数的 C 语言库:

  1. GOOS=linux CGO_ENABLED=0 go build -a goHelloWorld.go

编译出来的二进制文件可以加到一个空白(或框架)镜像:

  1. FROM scratch
  2. COPY goHelloWorld /
  3. CMD ["/goHelloWorld"]

来看一下两次构建的镜像对比:

  1. [ chris@krang ] $ docker images
  2. REPOSITORY TAG IMAGE ID CREATED SIZE
  3. goHello scratch a5881650d6e9 13 seconds ago 1.55 MB
  4. goHello builder 980290a100db 14 seconds ago 716 MB

从镜像体积来说简直是天差地别了。基于 golang:1.8 镜像构建出来带有 goHelloWorld 二进制的镜像(带有 builder 标签)体积是基于空白镜像构建的只包含该二进制文件的镜像的 460 倍!后者的整个镜像大小只有 1.55MB,也就是说,有 713MB 的数据都是非必要的。

正如上面提到的,这种缩减镜像体积的方式在 Golang 社区非常流行,因此不乏这方面的文章。Kelsey Hightower 有一篇文章专门介绍了如何处理这些库的依赖关系。

压缩镜像层

除了前面几节中讲到的将多个命令链接成一个命令的技巧,还可以对镜像进行压缩。镜像压缩的实质是导出它,删除掉镜像构建过程中的所有中间层,然后保存镜像的当前状态为单个镜像层。这样可以进一步将镜像缩小到更小的体积。

在 Docker 1.13 之前,压缩镜像层的的过程可能比较麻烦,需要用到 docker-squash 之类的工具来导出容器的内容并重新导入成一个单层的镜像。但 Docker 在 Docker 1.13 中引入了 --squash 参数,可以在构建过程中实现同样的功能:

  1. FROM fedora:28
  2. LABEL maintainer Chris Collins <collins.christopher@gmail.com>
  3.  
  4. RUN dnf install -y nginx
  5. RUN dnf clean all
  6. RUN rm -rf /var/cache/yum
  7.  
  8. [chris@krang] $ docker build -t squash -f Dockerfile-squash --squash .
  9. [chris@krang] $ docker images --format "{{.Repository}}: {{.Size}}" | head -n 1
  10. squash: 271 MB

通过这种方式使用 Dockerfile 构建出来的镜像有 271MB 大小,和上面连接多条命令的方案构建出来的镜像体积一样,因此这个方案也是有效的,但也有一个潜在的问题,而且是另一种问题。

“什么?还有另外的问题?”

好吧,有点像以前一样的问题,以另一种方式引发了问题。

过头了:过度压缩、太小太专用了

容器镜像之间可以共享镜像层。基础镜像或许大小上有几 Mb,但它只需要拉取/存储一次,并且每个镜像都能复用它。所有共享基础镜像的实际镜像大小是基础镜像层加上每个特定改变的层的差异内容,因此,如果有数千个基于同一个基础镜像的容器镜像,其体积之和也有可能只比一个基础镜像大不了多少。

因此,这就是过度使用压缩或专用镜像层的缺点。将不同镜像压缩成单个镜像层,各个容器镜像之间就没有可以共享的镜像层了,每个容器镜像都会占有单独的体积。如果你只需要维护少数几个容器镜像来运行很多容器,这个问题可以忽略不计;但如果你要维护的容器镜像很多,从长远来看,就会耗费大量的存储空间。

回顾上面 Nginx 压缩的例子,我们能看出来这种情况并不是什么大的问题。在这个镜像中,有 Fedora 操作系统和 Nginx 应用程序,没有缓存,并且已经被压缩。但我们一般不会使用一个原始的 Nginx,而是会修改配置文件,以及引入其它代码或应用程序来配合 Nginx 使用,而要做到这些,Dockerfile 就变得更加复杂了。

(编辑:云计算网_泰州站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读