Dockerfile构建Ubuntu16.04镜像apt装包报dpkg错误码(1)
问题背景
基于ubuntu:16.04官方基础镜像编写Dockerfile构建业务镜像,通过构建参数nf动态传入待安装的私有软件包名称,使用的原始Dockerfile内容如下:
FROM ubuntu:16.04 ENTRYPOINT ["/sbin/init"] SHELL ["/bin/bash", "-c"] ARG nf RUN touch /etc/apt/sources.list.d/cinar.list RUN echo -e $"<repository addresses are here>" >> /etc/apt/sources.list.d/cinar.list RUN apt-get update RUN apt-get install -y $nf
构建执行到RUN apt-get install -y $nf步骤时抛出固定错误:
E: Sub-process /usr/bin/dpkg returned an error code (1) The command '/bin/bash -c apt-get install -y $nf' returned a non-zero code: 100
删除该安装行先完成基础镜像构建,启动容器后进入容器手动执行apt-get install -y 对应包名命令可正常安装,无任何报错。常规dpkg错误码1修复操作全部无效,无法支撑自动化构建流水线落地。
根因分析
该问题和dpkg本身损坏、源配置错误无直接关系,核心差异点是Docker构建阶段和容器运行阶段的环境不一致:
- Dockerfile中定义的
ENTRYPOINT ["/sbin/init"]仅在docker run启动容器时生效,执行RUN指令的构建临时容器不会加载ENTRYPOINT配置,构建环境中没有运行的systemd/init进程 - 待安装的私有软件包(尤其是带系统服务注册逻辑的包)在安装过程中会执行postinst配置脚本,脚本默认会尝试和init进程交互、重载服务配置、触发服务启动,构建环境中不存在可用的init进程,直接导致脚本执行失败,触发dpkg返回错误码1
- 手动进入容器安装时,容器是通过ENTRYPOINT的/sbin/init正常启动的,systemd环境完整,postinst脚本可正常执行,因此不会报错
修复方案
按如下逻辑调整Dockerfile即可解决问题,无需修改私有软件包本身:
- 调整指令顺序,将ENTRYPOINT配置移到Dockerfile末尾,避免无效前置配置
- 构建阶段写入dpkg服务拦截规则,让所有包的postinst脚本在安装时跳过服务启动/重载操作,适配无init的构建环境
- 配置debconf为非交互模式,避免安装过程中出现交互弹窗导致构建卡住
- 安装完成后删除临时拦截规则,不影响容器启动后的正常服务运行
修正后的Dockerfile参考:
FROM ubuntu:16.04 SHELL ["/bin/bash", "-c"] ARG nf # 写入私有软件源配置 RUN cat > /etc/apt/sources.list.d/cinar.list <<EOF <替换为实际私有仓库地址> EOF # 配置非交互安装模式 RUN echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections # 写入服务拦截规则,屏蔽构建阶段的服务操作请求 RUN echo '#!/bin/sh\nexit 101' > /usr/sbin/policy-rc.d && chmod +x /usr/sbin/policy-rc.d # 执行软件安装 RUN apt-get update && apt-get install -y --no-install-recommends $nf # 清理构建缓存和临时规则 RUN rm -f /usr/sbin/policy-rc.d && apt-get clean && rm -rf /var/lib/apt/lists/* # 启动配置放在最后,仅对容器运行阶段生效 ENTRYPOINT ["/sbin/init"]
补充排查手段
如果按上述配置调整后仍有报错,可通过以下方式定位具体错误点:
- 将安装命令修改为
apt-get install -y --no-install-recommends $nf 2>&1 | tee /tmp/install.log,把完整安装日志落盘 - 构建失败后,通过
docker cp <构建失败输出的临时容器ID>:/tmp/install.log ./将日志拷贝到宿主机,直接查看具体是哪个包的哪条执行语句报错,无需被通用的dpkg错误码1提示误导 - 不要尝试在RUN步骤中启动/sbin/init,构建阶段的临时容器默认没有特权权限、未挂载对应cgroup资源,无法正常运行systemd
内容的提问来源于stack exchange,提问作者jouab
相关产品推荐
相关产品推荐

