容器构建全跑在浏览器里:秒级出镜像的原型实验

2026-05-28 13 预计阅读时间:1 分钟
来源:oschina.net AI 摘要 原文链接

免责声明:本文为 AI 摘要整理,建议结合原文阅读。摘要可能省略上下文、版本差异或边界条件,不作为官方说明。

预计阅读时间:9 分钟

构建 Docker 镜像的日常体验是这样的:敲下 docker build,然后盯着终端看几十层镜像逐层下载、逐层执行,GiB 级的数据在本地磁盘和远程 registry 之间来回搬运。CI 环境里更慢——冷启动时拉基础镜像就能吃掉两三分钟。开发者 Octavio Agagavia 最近做了一个研究原型,把整个流程搬进了浏览器:选基础镜像、写启动脚本、构建镜像,全部在浏览器 tab 里完成,延迟压到秒级。

传统构建的瓶颈在哪

一次典型的 docker build 耗时主要分布在三个阶段:

  • 拉基础镜像:即使有层缓存,首次拉取 ubuntu:22.04 也要 70–120 MB,网络不好时更久。
  • 执行指令层:每条 RUN 都会创建新层,涉及文件系统变更和进程执行。
  • 推送镜像:构建完推到 registry,又是网络 I/O。

本地构建至少有 Docker daemon 和 overlayFS 做加速;CI 环境经常是冷启动,缓存命中率低。浏览器里没有 Docker daemon,没有 overlayFS,甚至没有真正的 Linux 内核——这正是这个原型要解决的核心难题。

浏览器里怎么"构建镜像"

Agagavia 的原型思路并不神秘,关键在于用 WebAssembly 模拟容器构建所需的三个核心能力:

  1. 文件系统模拟:用 WASM 版本的文件系统(如 browser-fs-access 或基于 Emscripten 的 MEMFS)在内存中搭建镜像层结构。
  2. 指令执行:把 Dockerfile 的 RUNCOPY 等指令映射为 WASM 环境下的操作——RUN apt-get install 变成在 WASM 编译的轻量 Linux 工具链里执行对应命令。
  3. 层打包与导出:将内存中的层文件打包成 OCI 格式的 tar 包,直接下载或推到远程 registry。

整个流程不需要安装任何本地工具,打开网页就能开始。

下面是一个传统 docker build 的对比示例,帮助理解浏览器方案省掉了什么:

# 传统方式:本地需要 Docker daemon,首次构建耗时分钟级
cat > Dockerfile <<'EOF'
FROM alpine:3.19
RUN apk add --no-cache curl jq
COPY entrypoint.sh /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
EOF

echo '#!/bin/sh' > entrypoint.sh
echo 'curl -s https://api.github.com/repos/moby/moby | jq .description' >> entrypoint.sh

# 构建并推送
docker build -t my-utility:latest .
docker push my-utility:latest
# 首次构建:拉 alpine ~7MB + apk install ~15s + push ~10s
# CI 冷启动:可能 2-3 分钟

在浏览器原型中,同样的流程变成:网页上选 alpine:3.19 作为基础镜像(镜像层从 CDN 预加载到内存),在编辑器里写几行脚本,点击 Build,几秒后拿到 OCI 格式的 tar 包下载链接。没有 Docker daemon,没有本地磁盘写入,没有 CI 冷启动。

实际能构建什么

目前这个原型是研究性质,能构建的范围有明确边界:

  • 适合的镜像类型:小体积基础镜像 + 少量包安装 + 简单脚本,比如 Alpine + 几个 CLI 工具、轻量 API 服务、静态站点打包。
  • 不适合的镜像类型:需要完整 systemd 的复杂服务、依赖 GPU 驱动的镜像、编译大型 C/C++ 项目的镜像(WASM 环境的工具链和性能还撑不住)。

一个典型的适用场景是快速构建"一次性工具镜像"——比如你需要一个带 curl + jq + yq 的 Alpine 镜像来做 API 调试,传统方式要等本地 Docker 拉镜像、装包;浏览器里几秒就能拿到。

下面是一个用 OCI 规范手动组装最小镜像层的示例,展示了浏览器原型在内存中做的事情的本质——你可以本地跑这段脚本来理解原理:

# 手动组装一个最小 OCI 镜像层(模拟浏览器原型在内存中做的事)
mkdir -p /tmp/oci-demo/rootfs /tmp/oci-demo/blobs

# 1. 创建 rootfs 内容
echo '#!/bin/sh' > /tmp/oci-demo/rootfs/entrypoint.sh
echo 'echo "Hello from browser-built container"' >> /tmp/oci-demo/rootfs/entrypoint.sh
chmod +x /tmp/oci-demo/rootfs/entrypoint.sh

# 2. 打包为层 tar
tar -C /tmp/oci-demo/rootfs -cf /tmp/oci-demo/blobs/layer.tar .

# 3. 计算层 digest(OCI 规范要求 sha256)
LAYER_DIGEST=$(sha256sum /tmp/oci-demo/blobs/layer.tar | cut -d' ' -f1)
mv /tmp/oci-demo/blobs/layer.tar /tmp/oci-demo/blobs/sha256-${LAYER_DIGEST}.tar

# 4. 生成层 descriptor 的 config
cat > /tmp/oci-demo/blobs/config.json <<EOF
{
  "architecture": "amd64",
  "os": "linux",
  "config": {
    "Entrypoint": ["/entrypoint.sh"]
  },
  "rootfs": {
    "type": "layers",
    "diff_ids": ["sha256:${LAYER_DIGEST}"]
  }
}
EOF

CONFIG_DIGEST=$(sha256sum /tmp/oci-demo/blobs/config.json | cut -d' ' -f1)
mv /tmp/oci-demo/blobs/config.json /tmp/oci-demo/blobs/sha256-${CONFIG_DIGEST}.json

echo "层 digest: sha256:${LAYER_DIGEST}"
echo "配置 digest: sha256:${CONFIG_DIGEST}"
echo "查看 blobs 目录:"
ls -lh /tmp/oci-demo/blobs/

这段脚本做的事情,就是浏览器原型在 WASM 内存里完成的:把文件打包成层、计算 sha256 digest、按 OCI 规范组织 blobs。区别只是浏览器版用内存文件系统替代了 /tmp,用 WASM 工具替代了 tarsha256sum

限制与取舍

把构建搬进浏览器不是万能方案,目前有几个硬限制:

  • 包生态不完整:WASM 环境下能跑的包管理器有限,apk 的部分包可以,aptyum 大量包依赖原生动态链接,跑不了。
  • 性能天花板:WASM 的计算性能接近原生但 I/O 受限,大文件操作(编译、数据库初始化)会比本地慢。
  • 安全边界:浏览器沙箱本身是安全优势,但也意味着无法访问外部网络资源(除非通过 CORS 代理),RUN curl ... 这类指令需要特殊处理。
  • 镜像体积:内存文件系统意味着构建过程中所有层数据都在 JS 堆内存里,镜像超过几百 MB 就可能触发浏览器内存限制。

什么时候值得尝试

现阶段这个原型更适合以下场景:

  • 教学与演示:在培训或文档中让读者零安装体验容器构建流程。
  • 轻量工具镜像:快速组装带 2-3 个 CLI 工具的 Alpine 镜像,省掉本地 Docker 安装。
  • CI 预览层:在 CI pipeline 之前快速验证 Dockerfile 语法和层结构是否合理。

如果你已经在本地有成熟的 Docker 环境、构建的镜像体积大或依赖复杂,浏览器方案暂时没有优势。但作为"零安装、秒级出结果"的方向,它指向了一个有趣的未来:容器构建可能不再需要"先装 Docker",而是打开一个网页就够了。


相关推荐