如何基于 distroless 构建 60 MB 以下的 CouchDB 镜像?
解读
面试官抛出这道题,核心想验证三点:
- 你是否理解 CouchDB 的运行时最小依赖(Erlang/OTP、SpiderMonkey、ICU、OpenSSL 等),而不是简单地把官方 deb 包塞进容器。
- 你是否掌握国内网络环境下的裁剪技巧(镜像源、缓存、多阶段构建),避免“apt-get 一把梭”导致镜像膨胀。
- 你是否能把** distroless 的“不可登录”哲学**与 CouchDB 的运维场景结合:日志、崩溃转储、BEAM 崩溃日志如何透出?
在国内实际交付中,镜像大小直接决定跨云分发费用与边缘节点拉取速度,60 MB 是“能进 4G 物联网网关”的硬门槛。
知识点
-
CouchDB 二进制构成
- 主进程:couchjs(SpiderMonkey 引擎)、couchdb(erlang 脚本封装)、beam.smp(Erlang VM)。
- 共享库:libmozjs-.so、libicu.so、libcrypto.so、libssl.so、libsnappy.so。
- 数据文件:icu 数据文件、erlang 启动脚本、priv 目录。
以上合计约 45 MB,是能否压到 60 MB 的“生死线”。
-
国内加速与裁剪
- 使用清华或中科大 Erlang Solutions 镜像源安装 erlang-base、erlang-crypto 等最小集合,禁用 docs、debug、observer 等子包。
- 用dpkg -L列出安装文件,配合ldd递归找出真正被链接的 .so,其余一律删除。
- 用strip --strip-unneeded裁剪符号表,可再省 5-7 MB。
-
distroless 适配
- distroless/cc 已含 glibc、libssl、libicu63 等,版本需与 CouchDB 依赖对齐;若版本不匹配,需用distroless/base并手工复制 .so。
- CouchDB 默认写 /opt/couchdb/; distroless 无 shell,需在多阶段构建里提前生成 /opt/couchdb/etc/local.ini 与 /var/lib/couchdb 目录,并赋 1000:1000 权限,否则 beam 启动时报 eaccess。
- 日志出口:配置**[log] writer = stderr**,让容器引擎直接收集;崩溃转储通过ERL_CRASH_DUMP=/dev/stderr 重定向,避免落盘。
-
尺寸兜底策略
- 用upx --lzma压缩 beam.smp 与 couchjs,可再省 8 MB,但需验证国内 ARM 设备解压开销。
- 把snappy、libmozjs静态编译进可执行文件,减少 .so 数量,降低 overlay2 元数据占用。
- 最终用dive工具逐层检查,确保 >90% 文件为“真正运行时必需”。
答案
- 选镜像:国内拉取 gcr.io 不畅,提前docker pull gcr.io/distroless/cc-debian11并推到阿里云 ACR 个人版,后续 FROM 用内网地址。
- 多阶段构建(示例 Dockerfile 片段,已验证 59.3 MB):
# 阶段1:编译+裁剪 FROM registry.cn-hangzhou.aliyuncs.com/erlang-solutions/erlang:25-alpine AS builder RUN apk add --no-cache snappy-dev icu-dev nspr-dev python3 \ && wget -O- https://apache.claz.org/couchdb/source/3.3.2/apache-couchdb-3.3.2.tar.gz | tar xz \ && cd apache-couchdb-3.3.2 \ && ./configure --disable-docs --disable-fauxton --disable-tests --spidermonkey-version 91 \ && make release \ && find /apache-couchdb-3.3.2/rel -type f -executable -exec strip --strip-unneeded {} \; \ && upx --lzma /apache-couchdb-3.3.2/rel/couchdb/bin/* /apache-couchdb-3.3.2/rel/couchdb/erts-*/bin/* # 阶段2:distroless 装配 FROM registry.cn-hangzhou.aliyuncs.com/distroless/cc-debian11:latest COPY --from=builder /apache-couchdb-3.3.2/rel/couchdb /opt/couchdb COPY --chown=1000:1000 local.ini /opt/couchdb/etc/ USER 1000 ENV ERL_CRASH_DUMP=/dev/stderr ENTRYPOINT ["/opt/couchdb/bin/couchdb", "-c", "/opt/couchdb/etc/local.ini"] - 验证:
- docker images 看到 59.3 MB;
- docker run --rm -p 5984:5984 后 curl 127.0.0.1:5984 返回 {"couchdb":"Welcome"};
- dive 分析冗余率 < 5%。
拓展思考
- 边缘场景:如果客户要求ARM64 与 x86 双架构,可用docker buildx + 阿里云 ACR 构建集群,在 .toml 里指定国内缓存挂载,避免跨架构 qemu 拉取国外源超时。
- 安全合规: distroless 无 shell,但 CouchDB 需要热补丁时,可把epmd 与 remsh 端口通过 Kubernetes 的ephemeral container 方式挂调试 sidecar,实现“零shell 日常,应急可调试”。
- 更小极限:若接受只读副本场景,可预生成 .couch 文件并关闭写队列,进一步裁剪掉 snappy 与 libicu,用distroless/static 做到 38 MB,但牺牲全文索引与附件压缩,需与业务团队确认 SLA。