两个奇技淫巧,将 Docker 镜像体积减小 99%

Posted 程序猿DD

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了两个奇技淫巧,将 Docker 镜像体积减小 99%相关的知识,希望对你有一定的参考价值。


回复“资源”获取独家整理的学习资料!

前言

对于刚接触容器的人来说,他们很容易被自己构建的 Docker 镜像体积吓到,我只需要一个几 MB 的可执行文件而已,为何镜像的体积会达到 1 GB 以上?本文将会介绍几个奇技淫巧来帮助你精简镜像,同时又不牺牲开发人员和运维人员的操作便利性。本系列文章将分为三个部分:

第一部分着重介绍多阶段构建(multi-stage builds),因为这是镜像精简之路至关重要的一环。在这部分内容中,我会解释静态链接和动态链接的区别,它们对镜像带来的影响,以及如何避免那些不好的影响。中间会穿插一部分对 Alpine 镜像的介绍。

第二部分将会针对不同的语言来选择适当的精简策略,其中主要讨论 Go,同时也涉及到了 JavaNodePythonRuby 和 Rust。这一部分也会详细介绍 Alpine 镜像的避坑指南。什么?你不知道 Alpine 镜像有哪些坑?我来告诉你。

第三部分将会探讨适用于大多数语言和框架的通用精简策略,例如使用常见的基础镜像、提取可执行文件和减小每一层的体积。同时还会介绍一些更加奇特或激进的工具,例如 BazelDistrolessDockerSlim 和 UPX,虽然这些工具在某些特定场景下能带来奇效,但大多情况下会起到反作用。

本文介绍第一部分。

01

万恶之源

我敢打赌,每一个初次使用自己写好的代码构建 Docker 镜像的人都会被镜像的体积吓到,来看一个例子。

让我们搬出那个屡试不爽的 hello world C 程序:

/* hello.c */
int main () {
puts("Hello, world!");
return 0;
}

并通过下面的 Dockerfile 构建镜像:

FROM gcc
COPY hello.c .
RUN gcc -o hello hello.c
CMD ["./hello"]

然后你会发现构建成功的镜像体积远远超过了 1 GB。。。因为该镜像包含了整个 gcc 镜像的内容。

如果使用 Ubuntu 镜像,安装 C 编译器,最后编译程序,你会得到一个大概 300 MB 大小的镜像,比上面的镜像小多了。但还是不够小,因为编译好的可执行文件还不到 20 KB

$ ls -l hello
-rwxr-xr-x 1 root root 16384 Nov 18 14:36 hello

类似地,Go 语言版本的 hello world 会得到相同的结果:

package main

import "fmt"

func main () {
fmt.Println("Hello, world!")
}

使用基础镜像 golang 构建的镜像大小是 800 MB,而编译后的可执行文件只有 2 MB 大小:

$ ls -l hello
-rwxr-xr-x 1 root root 2008801 Jan 15 16:41 hello

还是不太理想,有没有办法大幅度减少镜像的体积呢?往下看。

为了更直观地对比不同镜像的大小,所有镜像都使用相同的镜像名,不同的标签。例如:hello:gcchello:ubuntuhello:thisweirdtrick 等等,这样就可以直接使用命令 docker images hello 列出所有镜像名为 hello 的镜像,不会被其他镜像所干扰。

02

多阶段构建

要想大幅度减少镜像的体积,多阶段构建是必不可少的。多阶段构建的想法很简单:“我不想在最终的镜像中包含一堆 C 或 Go 编译器和整个编译工具链,我只要一个编译好的可执行文件!”

多阶段构建可以由多个 FROM 指令识别,每一个 FROM 语句表示一个新的构建阶段,阶段名称可以用 AS 参数指定,例如:

FROM gcc AS mybuildstage
COPY hello.c .
RUN gcc -o hello hello.c
FROM ubuntu
COPY --from=mybuildstage hello .
CMD ["./hello"]

本例使用基础镜像 gcc 来编译程序 hello.c,然后启动一个新的构建阶段,它以 ubuntu 作为基础镜像,将可执行文件 hello 从上一阶段拷贝到最终的镜像中。最终的镜像大小是 64 MB,比之前的 1.1 GB 减少了 95%

以上是关于两个奇技淫巧,将 Docker 镜像体积减小 99%的主要内容,如果未能解决你的问题,请参考以下文章

三个技巧,将Docker镜像体积减小90%

docker容器共享宿主机环境,从而为镜像体积减负

Alipne镜像Dockerfile构建自己的镜像

我的docker随笔28:基于容器的升级方案实验

Docker镜像构建的优化总结

如何减小 RHEL/Centos/Fedora Docker 镜像的大小