写点什么

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

devopsdirective.com

  • 2021-06-15
  • 本文字数:2112 字

    阅读完需:约 7 分钟

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

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


膨胀的容器


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

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


挑战


规则很简单:

  • 这个容器应该在你指定的端口上通过 http 提供一个文件的内容

  • 不允许挂载卷(也即“Marek 规则”)


初始方案


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


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 基础镜像的镜像中:


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


这就有943MB


更小的基础镜像


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


使用node:14-slimnode:14-alpine作为基础镜像可以分别将镜像大小降低到167MB116MB

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


编译型语言


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


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


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 基础镜像的容器镜像:


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


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


多阶段构建


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


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


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


结果镜像只有13.2MB! 🙂


静态编译 +scratch 镜像


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


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


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


### build stage ###FROM golang:1.14 as builderCOPY . .RUN go build \  -ldflags "-linkmode external -extldflags -static" \  -a server.go### run stage ###FROM 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 基础镜像中,从而进行容器化:


### build stage ###FROM ubuntu:18.04 as builderRUN apt updateRUN apt install -y make yasm as31 nasm binutils COPY . .RUN make release### run stage ###FROM 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


2021-06-15 15:572587
用户头像

发布了 74 篇内容, 共 29.2 次阅读, 收获喜欢 83 次。

关注

评论

发布
暂无评论
发现更多内容

Databend 为什么能帮用户降低 90% 成本?

Databend

天池云上智能降雨量预测总决赛-优胜奖RIOFGROUP队攻略分享

阿里云天池

什么是自助服务门户?

ServiceDesk_Plus

IT服务 IT服务管理 自助服务

客户成功案例3:企业数据模型搭建、灾害预警解决方案

八爪鱼采集器︱RPA机器人

爬虫 采集

ChatGPT 向更多用户推出高级语音模式:支持 50 种语言;字节发布两款新视频生成大模型丨 RTE 开发者日报

声网

Lightroom Classic 2022(lrc2022)支持(Win&Mac)版

你的猪会飞吗

LRC2022 mac破解软件下载 lrc2022下载

AI加速数字员工智能化落地——中国数字员工市场发展及企业数字员工落地建议

易观分析

第一届POLARDB数据库性能大赛-亚军0xCC☣☢比赛攻略

阿里云天池

智源研究院发布中文互联网语料库CCI3.0 推动数据共建共享

智源研究院

深度解析拍立淘API:揭秘卖家与店铺数据的全面掌控

代码忍者

API 测试 pinduoduo API

Windows 10 version 22H2 (updated Sep 2024) 中文版、英文版下载

sysin

windows 10

Spark“数字人体”AI挑战赛_脊柱疾病智能诊断大赛_GPU赛道亚军比赛攻略_triple-Z团队

阿里云天池

In-depth analysis: IPQ5332 and QCN9274 together to create a Wi-Fi 7 network solution

wifi6-yiyi

WiFi7

“AI+Security”系列第3期(四):360安全大模型业务实践

云起无垠

企业如何通过ETL工具实现主数据的同步

RestCloud

数据处理 ETL 主数据 企业数据

爬虫如何帮助构建比价系统|涨姿势

八爪鱼采集器︱RPA机器人

爬虫 采集

CVPR2021 安全AI挑战者计划第六期赛道一第二名方案分享 (UM-SIAT队)

阿里云天池

鸿蒙智行首款轿跑SUV智界R7上市,小艺化身贴心随行的用车顾问

Geek_2d6073

macOS 15 Blank OVF - macOS Sequoia 虚拟化解决方案

sysin

macos 虚拟化 sequoia ovf

Windows 11 version 23H2 中文版、英文版 (x64、ARM64) 下载 (updated Sep 2024)

sysin

windows 11

客户成功案例(1):新闻媒体/招投标/行业资讯数据聚合

八爪鱼采集器︱RPA机器人

爬虫 采集 爬虫软件

Windows Server 2022 中文版、英文版下载 (updated Sep 2024)

sysin

windows Server 2022

如何根据拍立淘API返回值进行商品数据分析

技术冰糖葫芦

API Gateway api 货币化 API 接口 API 测试 pinduoduo API

面试官:谈谈你对 IoC 和 AOP 的理解!

JavaGuide

Java spring aop ioc

人工智能 | 手工测试用例转Web自动化测试生成

测吧(北京)科技有限公司

测试

打造数据平台:Cloudera下载安装全流程!

敏捷调度TASKCTL

hadoop cloudera 大数据运维 CDH 大数据 Hadoop

解锁境外旅行新姿势,四个小tips助你玩转国庆假期

最新动态

体验3A云游戏,无需购买高端显卡

Ogcloud

云游戏 3A云游戏 云游戏发行 游戏云化

Windows 10 on ARM, version 22H2 (updated Sep 2024) ARM64 AArch64 中文版、英文版下载

sysin

windows arm 10

洞察药监局数据,挖掘万亿价值

八爪鱼采集器︱RPA机器人

爬虫 采集

链藏“万亿金矿”的新能源,汽车企业如何抓住客户体验数字化新机遇?

八爪鱼采集器︱RPA机器人

爬虫 采集

微型容器挑战:构建一个6kB的容器化HTTP服务器_语言 & 开发_InfoQ精选文章