当前位置:   article > 正文

Docker 镜像制作优化教程:Alpine 并不是万能的,针对不同语言的精简策略

docker alpine

公众号关注 「奇妙的 Linux 世界」

设为「星标」,每天带你玩转 Linux !

f453a156e92c1c8c3ad6667526c42a00.jpeg

本系列文章将分为三个部分:

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

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

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

本文介绍第二部分。

1. Go 语言镜像精简

Go 语言程序编译时会将所有必须的依赖编译到二进制文件中,但也不能完全肯定它使用的是静态链接,因为 Go 的某些包是依赖系统标准库的,例如使用到 DNS 解析的包。只要代码中导入了这些包,编译的二进制文件就需要调用到某些系统库,为了这个需求,Go 实现了一种机制叫 cgo,以允许 Go 调用 C 代码,这样编译好的二进制文件就可以调用系统库。

也就是说,如果 Go 程序使用了 net 包,就会生成一个动态的二进制文件,如果想让镜像能够正常工作,必须将需要的库文件复制到镜像中,或者直接使用 busybox:glibc 镜像。

当然,你也可以禁止 cgo,这样 Go 就不会使用系统库,使用内置的实现来替代系统库(例如使用内置的 DNS 解析器),这种情况下生成的二进制文件就是静态的。可以通过设置环境变量 CGO_ENABLED=0 来禁用 cgo,例如:

  1. FROM golang
  2. COPY whatsmyip.go .
  3. ENV CGO_ENABLED=0
  4. RUN go build whatsmyip.go
  5. FROM scratch
  6. COPY --from=0 /go/whatsmyip .
  7. CMD ["./whatsmyip"]

由于编译生成的是静态二进制文件,因此可以直接跑在 scratch 镜像中 本文内容由网友自发贡献,转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/480853

推荐阅读
相关标签