Docker 镜像体积从 110MB 降到 13MB 后端服务的瘦身

8 个服务镜像从平均 ~110MB 精简约 88%,降到平均 ~13MB。

一、以前 vs 现在:基底镜像

项 以前 现在
基底镜像 debian:bookworm-slim alpine:3.20
基底体积 ~70MB ~3.5MB
装了什么 ca-certificates ca-certificates + tzdata
运行用户 root 非 root(app 用户)

为什么选 alpine 而不是 distroless/scratch?

  • Go 服务是 CGO_ENABLED=0 纯静态二进制,任何最小基底都能跑

  • alpine 比 debian-slim 小约 90%,自带 busybox shell,容器里排查问题方便

  • apk add 装个证书就完事,无需包管理器红海

  • distroless/scratch 虽更小(2-3MB),但没有 shell,出问题无法进入排查

二、最终体积对比

服务 之前 (debian) 现在 (alpine) 节省
微服务 A ~177MB 19.0MB ~89%
微服务 B ~147MB 18.0MB ~88%
微服务 C ~133MB 16.0MB ~88%
微服务 D ~147MB 16.0MB ~89%
微服务 E ~37MB 10.0MB ~73%
微服务 F ~90MB 9.0MB ~90%
微服务 G ~80MB 9.0MB ~89%
微服务 H ~90MB 9.5MB ~89%
平均 ~110MB ~13MB ~88%

三、为什么以前那么大?

不是单纯的"debian 比 alpine 大"那点差距,真正的大头是 镜像里装了不必要的重量级工具:

  1. 图片转 WebP 用 ffmpeg 实现,多个服务都要装 ffmpeg(含大量共享库 + 构建依赖)

  2. 硬件能力探测 调用了 ffmpeg -encoders,导致核心服务也要装 ffmpeg

  3. 浏览器依赖 被误打进容器------某些工具依赖只在独立的 CLI 工具中,本不该进容器镜像

四、瘦身三板斧

1. 基底换 alpine

Dockerfile 运行阶段:

dockerfile

复制代码
FROM alpine:3.20 AS runtime
RUN apk add --no-cache ca-certificates tzdata \
    && addgroup -S app && adduser -S -G app app
USER app
COPY --from=build /out/app /app
ENTRYPOINT ["/app"]

2. 图片转 WebP 前移到前端

前端上传前用 canvas / OffscreenCanvas 完成 WebP 转换:

  • 等比缩放到最大 1920px

  • 质量参数 0.6

  • GIF/WebP 原样跳过

后端改成纯 pass-through,不再调用 exec ffmpeg。

额外收益: 上传前压缩节省了网络带宽和存储空间,绝大多数现代浏览器都支持 WebP。

3. 砍掉容器里根本不用的依赖

确认主服务不 import 某个工具模块 → 该模块的依赖(如浏览器)只保留在独立的 CLI 工具中,不进容器镜像。

五、验证结果

  • 所有镜像重建完成

  • 全部容器启动成功,进程日志无异常

  • 核心接口正常返回

  • 业务链路不受影响

六、还能不能更小?

可以,但投入产出比不高:

方案 收益 代价
distroless/scratch 再省 3-4MB 无 shell,排查问题困难,需从 gcr.io 拉取
去掉 tzdata 省 1-2MB 日志时间变 UTC
upx 压缩二进制 省十几 MB 增加复杂度,压缩后启动有额外开销

结论:alpine + 纯静态 Go + 前端处理图片 = 生产可用 + 最精简的甜点位。

七、核心经验

  1. 换基底镜像是最直接的瘦身手段 --- debian-slim → alpine,一步省 60+ MB

  2. 审视容器里真正需要什么 --- 不要把全量构建工具链带进运行镜像

  3. 能往前端推的就往前端推 --- 图片处理在浏览器端完成,后端只做透传

  4. 多阶段构建 + 非 root 用户 --- 安全与体积兼顾

  5. 定期审视依赖 --- 有些依赖只在特定场景使用,可以拆分到独立镜像

相关推荐
源图客3 分钟前
解决CentOS操作系统网络异常问题
linux·运维·centos
分布式存储与RustFS16 分钟前
K8s 集群备份落到自建对象存储:Velero 接 RustFS 配置指南
运维·云原生·开源·对象存储·分布式存储·s3·性能基准
梅孔立2 小时前
Docker 容器网络不通:Tomcat 无法解析 MySQL、Nginx 无法反代 Tomcat 的生产级排查与治理
网络·docker·tomcat
镜子AI9 小时前
镜子AI 技术复盘:三条自动化链路上的“停止条件“设计
运维·人工智能·自动化
tianyuanwo10 小时前
NetBox 数据库详解:当“关系型数据库”被装进一个网络运维的领域模型里
运维·数据库·netbox
螺蛳粉 螺蛳粉11 小时前
第 05 篇:etcd 深入:Raft 共识、watch 机制与快照备份恢复实战(底座认知 05)
docker·云原生·容器·kubernetes·etcd·分布式存储·kube-apiserver
知已难寻12 小时前
03 · OpenStack的计算管理 Nova
运维·服务器·开发语言·云原生·云计算·openstack·开源软件
huainingning12 小时前
Windows syslog日志服务器搭建与模拟器对接
运维·服务器·智能路由器
say_fall12 小时前
【Linux系统编程】Ext 文件系统:磁盘与存储、文件与目录、现代计算机究竟如何寻找文件
linux·运维·服务器·数据库·c++
wacsii13 小时前
【Linux进程(一)】Linux 进程初探:操作系统如何管理进程?fork() 为什么返回两次?
linux·运维·服务器