如何实现一个小体积的 js docker 镜像

在服务端一般使用 node 来运行 js ,除了 node 外流行的还有 bun/deno。

但这三个运行时的打包体积都不小,在精简的情况下也在 50 mb 以上,我在这里记录一下我是如何将一个原来使用 node 开发的服务迁移为 3.78MB 的 docker 镜像。

image-20240831145324-mzsh9nq

https://hub.docker.com/layers/llej0/web-font/latest

选择 js 运行时 (llrt

要实现这么小的镜像肯定不能再使用 node 这种等级的 js 运行时了,现在最流行的轻量级 js 运行时可以锁定为 QuickJS

我要迁移的项目是我之前写的一个字体裁剪工具 web-font , 它除了纯 js 的部分外还涉及到文件读写和 http server 部分的 api ,QuickJS 作为纯粹的解释器是没有这方面的 api 的。

现有的比较成熟的基于 QuickJS 实现的微型 js 运行时有 txiki.jsllrt , 经过实践发现 llrt 可以完美运行在 docker 中 ,txiki.js 则没那么方便 (按照文档编译出来的 tjs 还会依赖其他库)

所以我选择使用 llrt 来作为运行时。

迁移遇到的问题

主要问题是 llrt 没有提供 http 模块(tixiki.js 也是), 幸运的是它提供了 net 模块

所以我基于 net.createServer 手搓了一个简易 http 服务和洋葱路由 server.ts

这期间还发现了 llrt 一个 cpu 占用异常:https://github.com/awslabs/llrt/issues/546

打包微小体积的 docker 镜像

1. 代码打包

这方面我使用的是 tsup 将 ts 源码打包为一个 js 文件。

然后使用 llrt compile 命令将 js 文件编译为 .lrt 文件(这一步也能减少差不多 30% 的体积)

2. Dockerfile

得益于 llrt ,可以不用依赖任何环境,直接使用 FROM scratch​ 来得到最小的 docker 镜像体积

FROM scratch
WORKDIR /home/
COPY dist_backend/app.lrt /home/app.lrt
COPY llrt /home/llrt
COPY dist/ /home/dist/
CMD ["/home/llrt", "/home/app.lrt"]

再经过 docker 的压缩后就得到了 3.78MB 这个数字。

使用情况

llrt 的运行速度比 node 还是慢了许多,在我这个场景下它比 node 要慢上两倍,gc 的运行速度也要慢许多。

但初始内存占用和启动速度是碾压 node 的。

由于运行时还不是特别完善的问题,很容易踩坑,所以除非你急需压缩 js 的运行内存占用/冷启动速度或者和我一样就是想要这么做,还是建议直接使用 node 吧。

  • JavaScript

    JavaScript 一种动态类型、弱类型、基于原型的直译式脚本语言,内置支持类型。它的解释器被称为 JavaScript 引擎,为浏览器的一部分,广泛用于客户端的脚本语言,最早是在 HTML 网页上使用,用来给 HTML 网页增加动态功能。

    729 引用 • 1327 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...