最近将一个 Spring Boot 项目编译成了 Spring Native 可执行文件,项目启动速度是上来了,但是可执行文件的大小可骤增至 350M 左右,导致 Docker 镜像的大小也一起增加了很多,考虑到 Docker 拉取本身的网络就很坎坷了,我就想有没有办法能再压缩下大小。
最开始的方案是使用 upx, 压缩率不错,压缩后可直接执行,但是发现这个工具是有代价的,因为他是执行时从内存中解压你原本的程序,所以你节省了多少可执行文件大小,就会额外占用多少内存,这对我是不可接受的,我觉得内存更可贵一些,这个方案可能更适合 go 程序使用,本身可执行文件大小不会太大,所以也不会导致增加很多内存占用。
第二个方案是无意中想到的,我能不能自己压缩文件放到镜像中,然后在运行时解压出来再执行,这相较于 upx 的方案来说是在硬盘解压,不会额外占用内存,但是这个要考虑解压的速度(压缩速度不是很重要,可以用 CI/CD 来跑),然后就找到了一个压缩算法 zstd,不论压缩率设置多高,解压缩的时间都是一样的 (如 350M 使用 zstd -19 最高级别,压缩时间 5 分钟,大小可达到 80M 左右,但解压时间仅 0.5 秒)。
然后在 Dockerfile 中给镜像安装 zstd ,并在最后运行时进行判断是否解压:
FROM debian:10-slim
ARG TARGETARCH
RUN apt update -y && apt install --no-install-recommends zstd -y && apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
# 省略其他
CMD if [ -f /data/app.zst ]; then zstd --no-progress -d /data/app.zst && rm -rf /data/app.zst && chmod +x /data/app && /data/app --spring.config.location=file:/root/application.properties; else chmod +x /data/app && /data/app --spring.config.location=file:/root/application.properties; fi
不知道这种方式算优雅,还是算丑陋,但至少解决了我的问题,希望也能帮助到有类似需求的人。
1
mayli 2 天前
有点闲,docker image 本身就是压缩的
https://docs.docker.com/build/exporters/#compression docker buildx build \ --output type=image,name=<registry>/<image>,push=true,compression=zstd . |
2
zhaojun1998 OP |
3
netnr 2 天前
专业的加个参数就搞定了 😂
|
4
pigeon2049 2 天前
另一个方法
使用 maven 作为运行时 base image 或者 dockerfile 里安装 maven springboot 使用 thin-launcher https://github.com/spring-projects-experimental/spring-boot-thin-launcher 这样打包时所有依赖都不会带上 配置好 maven 运行时会自动拉取 缺点是首次运行会慢很多 优点是极度节省 docker 镜像的空间 完整 jar 包 500M thin-layout 打出来 5M |
5
lower 2 天前
@pigeon2049 op 都打成 native image 了,这种应该不支持吧?
|