从头构建 100kB Docker 镜像

2025-06-10

从头构建 100kB Docker 镜像

📓要点

你可能觉得 100MB 的 Alpine 镜像已经很小了——但 100kB 的镜像呢?更小的镜像传输速度更快,而且包含的攻击向量更少。此外,通过优化镜像,你可以发现并精准地隔离应用运行所需的资源。

让我们进行优化。

基于 scratch 的 docker 镜像有两个关键特征:

  1. Dockerfile 有两个构建阶段:
    • 构建器——包含所有构建依赖项,包括源、库和工具等。
    • 最终映像,包含二进制文件和任何运行时依赖项(配置文件、证书和动态链接库)
  2. 最终的镜像是FROM scratch——空的docker镜像

通过这种方法,您的运行时映像将包含应用程序运行所需的全部内容 - 无需可能配置错误或被利用的额外配置文件、守护程序或库。

让我们先来看一下一个基本的静态 Hello World 临时镜像。我们将使用 C 语言,因为它所需的依赖最少,并且生成的 ELF 目标二进制文件非常小。

创建 Hello World

hello.c

#include <stdio.h>
int main(void){
    puts("Hello World\n");
}

Makefile

hello: hello.c
    gcc -o $@  $< -static 

Dockerfile

.dockerignore

# this prevents our host binary from sneaking into the build
hello

Dockerfile

FROM alpine:latest as builder
WORKDIR /build
RUN apk update && \
    apk add gcc make libc-dev
COPY .  ./
RUN make

FROM scratch
WORKDIR /
COPY --from=builder /build/hello .
CMD ["/hello"]

注意,我们有两个FROMs,其中一个叫做builder。最终的镜像将是我们的运行器。使用COPY --from我们可以指定哪些文件需要放入暂存镜像。对于静态 ELF 二进制文件,我们只需要/build/hello

构建并运行

$ docker build . -t hello-scratch|tail -n 1
Successfully tagged hello-scratch:latest
$ docker run hello-scratch                 
Hello World

我们的最终图像为 82.7kB

$ docker images |grep hello-scratch | egrep -o '[^ ]+$'
82.7kB

里面有什么?

使用docker save您可以检查图像并发现它只layer.tar包含一个文件:hello


$ mkdir hello-scratch && cd hello-scratch 
$ docker save hello-scratch |tar -x
$ ls
3e69d91b5842be72dcd4175adcf218a03f78826504be6a46ed41c099e97520e8.json  e599e214ce17b356493f9524fa57f7ef816d21dd78020019196020c770a39954  manifest.json  repositories
$ ✗ tar -tf e599e214ce17b356493f9524fa57f7ef816d21dd78020019196020c770a39954/layer.tar 
hello

后续步骤

在接下来的文章中,我将展示一些更复杂的示例。对于 C、C++、golang 和 Rust 等静态编译的应用程序来说,这个过程最简单。但是,只要使用合适的工具,假设您将所有运行时依赖项都收集到最终scratch镜像中,就可以构建任何镜像。

鏂囩珷鏉ユ簮锛�https://dev.to/tononymet/build-100kb-docker-images-from-scratch-4ll5
PREV
使用 ToolJet 和 Scraper API 构建一个高级 Web 数据抓取工具!🚀 🛠️ 简介步骤 3:显示抓取的数据
NEXT
React 中的原子状态管理库介绍