镜像压缩:离线、零依赖的 Docker/OCI 镜像层合并工具 oci-squash
项目地址:GitHub - lyon-v/oci-squash
背景与痛点
容器镜像在持续迭代中会快速膨胀,层数会不断变多:
- 基于
apt install
、构建产物、临时文件的层不断堆叠,最终镜像体积变大。 - 多层带来重复元数据与存储负担,拉取/推送耗时增加,CI/CD 变慢。
- 在离线/半离线环境,需要在“只有镜像 tar 包”的前提下进行瘦身与整合。
现有工具常见问题:
- 依赖 Docker 守护进程或第三方库,不适合离线环境。
- 对 OCI/Docker 不同布局兼容性不一,或导出后不能稳定
docker load
。 - 白化文件(whiteout)与不透明目录(opaque)处理不完善,可能导致文件系统状态不一致。
方案
OCI-Squash 通过“直接操作镜像 tar 包”的方式,把多层合并为更少的层,既减少体积,也简化历史记录;全程使用 Python 标准库,无需 Docker 守护进程,适用于离线与安全敏感场景。
功能亮点
- 零依赖与离线友好:仅用 Python 标准库工作于镜像 tar 包
- Docker 与 OCI 双支持:自动识别
index.json
或manifest.json
- 稳定输出:始终生成 Docker 风格层结构,保证
docker load
可靠 - 元数据正确性:重算
diff_ids
、保留/更新 config、history - 白化处理:支持 whiteout 与 opaque 目录语义
- 灵活标记:支持设定新镜像 tag、commit message
- 体积报告:比较原/新 tar 包大小与百分比变化
- 简单易用:单命令完成合并导出
工作原理(简述)
- 解包镜像 tar,自动识别格式(Docker/OCI)
- 读取 config/manifest,重建完整层序列(含虚拟空层)
- 选定需要合并的层(支持按“自顶向下”数量或指定层 ID)
- 进行文件系统重组,正确处理 whiteout/opaque 语义
- 写出新的 Docker 风格层结构与
manifest.json
、repositories
- 重新计算
diff_ids
,更新 config、rootfs、history - 打包成可被
docker load
直接导入的 tar
快速开始
安装:
pip install oci-squashoci-squash -h
一条命令完成压缩:
# 镜像导出为压缩包docker save -o source.tar lyonv/ubuntu-dev:latest# oci-squash压缩oci-squash -f 8 -t myrepo/myimage:squashed -m \"squashed\" -o squashed.tar source.tar
导入 Docker 并查看历史:
docker load -i squashed.tardocker history myrepo/myimage:squashed
端到端演示
以下为对 lyonv/ubuntu-dev:latest
的一次真实合并过程。
- 查看原始历史:
docker history lyonv/ubuntu-dev:latest
IMAGE CREATED CREATED BY SIZE COMMENTb23aed85a512 10 hours ago RUN /bin/sh -c rm -f /bigfile # buildkit 0B buildkit.dockerfile.v0 10 hours ago RUN /bin/sh -c dd if=/dev/zero of=/bigfile b… 105MB buildkit.dockerfile.v0 10 hours ago WORKDIR /app && USER appuser && echo Ver… 0B buildkit.dockerfile.v0 10 hours ago RUN /bin/sh -c apt-get clean && rm -rf /… 4.1kB buildkit.dockerfile.v0 10 hours ago RUN /bin/sh -c mkdir -p /app/{conf,logs} /va… 0B buildkit.dockerfile.v0 10 hours ago RUN /bin/sh -c apt-get install -y --no-insta… 2.83MB buildkit.dockerfile.v0 10 hours ago RUN /bin/sh -c apt-get install -y --no-insta… 78.1MB buildkit.dockerfile.v0 10 hours ago RUN /bin/sh -c ln -snf /usr/share/zoneinfo/A… 58.4MB buildkit.dockerfile.v0 11 months ago sh -c sleep 36000 4.1kB build img 15 months ago /bin/sh -c #(nop) CMD [\"/bin/bash\"] 0B 15 months ago /bin/sh -c #(nop) ADD file:e7cff353f027ecf0a… 79.5MB 15 months ago /bin/sh -c #(nop) LABEL org.opencontainers.… 0B 15 months ago /bin/sh -c #(nop) LABEL org.opencontainers.… 0B 15 months ago /bin/sh -c #(nop) ARG LAUNCHPAD_BUILD_ARCH 0B 15 months ago /bin/sh -c #(nop) ARG RELEASE 0B
- 保存、合并并导入:
docker save -o source.tar lyonv/ubuntu-dev:latestoci-squash -f 8 -t lyonv/ubuntu-dev:squashed -m squashed -o squashed.tar source.tardocker load -i squashed.tar
示例输出(节选):
2025-08-30 17:18:56,654 cli.py:106 INFO Extracting tar: source.tar2025-08-30 17:18:56,859 cli.py:109 INFO Detected format: oci2025-08-30 17:18:56,859 cli.py:116 INFO Attempting to squash last 8 layers2025-08-30 17:18:57,965 cli.py:162 INFO Exporting to: squashed.tar2025-08-30 17:18:58,393 cli.py:164 INFO Done. New image id: sha256:1ae6a77f5b834850e9a9b2c4e3a6f8f715efb8c46af92635a49640c53e3db3472025-08-30 17:18:58,393 cli.py:171 INFO Original tar size: 299.76 MB2025-08-30 17:18:58,393 cli.py:172 INFO Squashed tar size: 143.15 MB2025-08-30 17:18:58,393 cli.py:175 INFO Tar size decreased by 52.24 %2025-08-30 17:18:58,484 cli.py:186 INFO Squashed image Done.Loaded image: lyonv/ubuntu-dev:squashed
- 查看合并后的历史:
docker history lyonv/ubuntu-dev:squashed
IMAGE CREATED CREATED BY SIZE COMMENT927444bd87b4 31 seconds ago 79.9MB squashed 11 months ago sh -c sleep 36000 4.1kB build img 15 months ago /bin/sh -c #(nop) CMD [\"/bin/bash\"] 0B 15 months ago /bin/sh -c #(nop) ADD file:e7cff353f027ecf0a… 79.5MB 15 months ago /bin/sh -c #(nop) LABEL org.opencontainers.… 0B 15 months ago /bin/sh -c #(nop) LABEL org.opencontainers.… 0B 15 months ago /bin/sh -c #(nop) ARG LAUNCHPAD_BUILD_ARCH 0B 15 months ago /bin/sh -c #(nop) ARG RELEASE 0B
结果:tar 体积从 299.76 MB 降至 143.15 MB,降低 52.24%。
适用场景
- CI/CD 合并层以减少镜像体积与层数,缩短推拉时间
- 离线/内网环境,只能操作镜像 tar 包的瘦身与归档
- 基础镜像清理:将中间构建层(下载、解压、临时文件)合并掉
- 制作交付镜像:减少层历史暴露,便于合规与分发
与其他方案对比
- 相比依赖 Docker 守护进程的工具:OCI-Squash 完全离线、零依赖
- 相比仅支持 Docker 布局的工具:同时支持 Docker 与 OCI,输出稳定可
docker load
- 注重元数据正确性:重算
diff_ids
、保留历史语义、处理 whiteout/opaque
限制与注意事项
- 需要足够磁盘空间用于解包与重打包
- 当前以 Linux 镜像为主;特殊平台/层格式请先测试
- 不进行安全扫描/合规检查(可与其他工具配合)
- 合并层不会“神奇压缩”所有文件,更多是消除中间层冗余与历史
路线图
- 更丰富的进度与统计输出
- 多架构/多平台镜像体验优化
- 更细粒度的层选择与排除策略
- 更多安装方式支持(conda、homebrew 等)
开源与参与
- 仓库地址:GitHub - lyon-v/oci-squash
- 欢迎提交 Issue、PR,或在实际生产使用中反馈你的场景与需求
如果你也被“镜像层越堆越厚、部署越来越慢”困扰,不妨试试 OCI-Squash,用一次简单的离线合并,换来持续的轻量与高效。