前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >微型容器挑战:构建一个 6kB 的容器化 HTTP 服务器

微型容器挑战:构建一个 6kB 的容器化 HTTP 服务器

作者头像
深度学习与Python
发布2023-04-01 17:28:07
4670
发布2023-04-01 17:28:07
举报

作者 | devopsdirective.com

译者 | 张健欣

策划 | 施尧

我着手构建一个我所能构建的最小且仍然有一些用途的容器镜像。通过利用多阶段构建、一个 scratch 基础镜像以及一个微型的基于汇编语言的 http 服务器,我将这个镜像减小到 6.32kB!

膨胀的容器

容器通常被吹捧为一颗银弹,能够解决与操作软件相关的每一个挑战。虽然我喜欢容器,但我经常遇到有各种各样问题的容器镜像。一个常见的问题是容器大小,容器镜像有时候会达到几个 GB!

正因为如此,我决定进行挑战,来构建尽可能最小的镜像。

挑     战

规则很简单:

  • 这个容器应该在你指定的端口上通过 http 提供一个文件的内容
  • 不允许挂载卷(也即“Marek 规则”)

初始方案

为了获得符合基准的镜像大小,我们可以使用 node.js 创建一个简单的服务器 index.js:

代码语言:javascript
复制
const fs = require("fs");const http = require('http');const server = http.createServer((req, res) => { res.writeHead(200, { 'content-type': 'text/html' }) fs.createReadStream('index.html').pipe(res)})server.listen(port, hostname, () => { console.log(Server: http://0.0.0.0:8080/);});

然后将它构建到一个启用官方的 node 基础镜像的镜像中:

代码语言:javascript
复制
FROM node:14COPY . .CMD ["node", "index.js"]

这就有 943MB!

更小的基础镜像

减小镜像大小的最简单最明显的策略之一就是使用一个更小的基础镜像。官方的 node 镜像有一个 slim 变体(仍然基于 debian,但是预装的依赖更少),以及一个基于 Alpine Linux 的 alpine 变体。

使用 node:14-slim 和 node:14-alpine 作为基础镜像可以分别将镜像大小降低到 167MB 和 116MB。

由于 docker 镜像是添加型的,每一层都是构建在另一层的基础上,因此我们不能做太多别的事情来进一步减小 node.js 方案。

编译型语言

为了更进一步,我们可以转换到一个具有更少运行时依赖的编译型语言。有很多选项,但对于构建 Web 服务,golang 是一个比较流行的选择。

我创建了一个基础的文件服务器 server.go:

代码语言:javascript
复制
package mainimport ( "fmt" "log" "net/http")func main() { fileServer := http.FileServer(http.Dir("./")) http.Handle("/", fileServer) fmt.Printf("Starting server at port 8080\n") if err := http.ListenAndServe(":8080", nil); err != nil { log.Fatal(err) }}

然后将它构建到一个使用官方的 golang 基础镜像的容器镜像:

代码语言:javascript
复制
FROM golang:1.14COPY . .RUN go build -o server .CMD ["./server"]

这有 818MB. 这里的问题是 golang 基础镜像有很多预安装的依赖,这些依赖在构建 go 软件时有用,但是在运行软件时并不是必需的。

多阶段构建

Docker 有一个叫做“多阶段构建(multi-stage builds)”的特性,它可以轻易在一个具有所有必需依赖的环境中构建代码,然后将可执行结果拷贝到另一个不同的镜像中。

这样做有很多好处,但最明显的是镜像大小!通过如下重构 dockerfile:

代码语言:javascript
复制
build stageFROM golang:1.14-alpine AS builderCOPY . .RUN go build -o server .run stageFROM alpine:3.12COPY --from=builder /go/server ./serverCOPY index.html index.htmlCMD ["./server"]

结果镜像只有 13.2MB! 🙂

静态编译 +scratch 镜像

13MB 还不错,但我们还可以利用一些手段将镜像变得更小。

有一个名为 scratch 的基础镜像,它是空的且大小为零。由于 scratch 内部没有任何内容,因此任何基于它构建的镜像必须包含所有必需的依赖。

为了使我们的 go 基础服务器能够运行,我们需要在编译步骤中添加几个标志,从而确保必要的库静态链接到可执行程序中:

代码语言:javascript
复制
build stageFROM golang:1.14 as builderCOPY . .RUN go build \ -ldflags "-linkmode external -extldflags -static" \ -a server.gorun stageFROM scratchCOPY --from=builder /go/server ./serverCOPY index.html index.htmlCMD ["./server"]

具体来说,我们将链接模式设置为 external,并将 -static 标志传给外部链接器。这两个更改使得镜像大小减小到 8.65MB😀

ASM 决定胜局!

一个小于 10MB、用 Go 这样的语言编写的镜像,对于任何情况来说都已经是很小了... 但是我们可以让它变得更小!Github 用户 nemasu 在名为 assmttpd 的 github 上用汇编语言编写了一个功能齐全的 http 服务器。

在运行提供的 make release 脚本之前,需要将一些构建依赖安装到 ubuntu 基础镜像中,从而进行容器化:

代码语言:javascript
复制
build stageFROM ubuntu:18.04 as builderRUN apt updateRUN apt install -y make yasm as31 nasm binutilsCOPY . .RUN make release run stageFROM scratchCOPY --from=builder /asmttpd /asmttpdCOPY /web_root/index.html /web_root/index.htmlCMD ["/asmttpd", "/web_root", "8080"]

然后将生成的 asmttpd 可执行文件复制到 scratch 镜像中,并使用 CMD 调用。这样下来,镜像大小只有 6.34kB! 🥳

容器镜像大小的进展!

希望你能从我们这段从最初的 943MB 的 Node.js 镜像一直到微型的 6.34kB 的汇编镜像的过程中,学到一些技术,将来用于减小你的容器镜像大小。

作者介绍:

devopsdirective.com

原文链接:

https://devopsdirective.com/posts/2021/04/tiny-container-image/index.html?fileGuid=KxkC6jGXydCvRRrg

今日好文推荐

如何用18个月搞出聚集全球5000余位开发者的操作系统开源社区?

Python之父:Python 4.0可能不会有了

字节跳动年营收2366亿元;985名校毕业生组团开发App诈骗,涉案金额过亿;谷歌最新薪资曝光,开发岗年薪超200万 | Q资讯


每周精要上线移动端,立刻订阅,你将获得

InfoQ 用户每周必看的精华内容集合:

资深技术编辑撰写或编译的全球 IT 要闻

一线技术专家撰写的实操技术案例

InfoQ 出品的课程技术活动报名通道;

“码”上关注,订阅每周新鲜资讯

点个在看少个 bug👇

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-06-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 InfoQ 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档