Docker部署Python包时__init__.py为空导致导入失败问题
根因分析
以下是导致该问题的两种最常见场景:
场景1:pip索引源优先级冲突
Docker容器内的pip默认配置了多个索引源,且公网PyPI的优先级高于你的Artifactory私服。公网PyPI上恰好存在同名同版本的my_utils==1.0.0第三方包,该包的__init__.py为空。Docker构建时pip优先从公网拉取到了错误的包,而你手动进入容器重装时,要么手动指定了私服源,要么本地临时的pip配置中私服优先级更高,因此拉取到了正确的包。
场景2:Docker构建层缓存复用
你在上传正确版本的my_utils==1.0.0到私服之前,曾经触发过一次Docker构建,当时私服上的1.0.0版本为内容异常的空包。Docker默认会复用未发生变化的构建层,即使你后续更新了私服上的包,只要requirements.txt内容没有修改,Docker都会复用之前缓存的RUN pip install层,导致容器内始终是旧的异常包。你手动进入容器卸载重装时,会重新从私服拉取最新的正确包,因此恢复正常。
验证方法
- 进入异常容器执行
pip show my_utils,比对返回的作者、主页等信息和你在setup.py中填写的内容是否一致,若不一致则可确认拉取到了第三方同名包。 - 在异常容器中执行
pip download my_utils==1.0.0 -d /tmp,下载对应安装包后解压,比对包内文件和你上传的私服包内容、哈希值是否一致。 - 执行
docker build --no-cache .强制跳过Docker层缓存重新构建镜像,若新镜像运行正常则可确认是构建缓存导致的问题。
解决方案
- 若为索引源冲突:pip安装时明确指定私服索引地址,例如
pip install --index-url <你的Artifactory PyPI地址> -r requirements.txt,也可以给私有包添加专属命名前缀,避免和公网包重名。 - 若为构建缓存问题:每次更新私有包时升级版本号,不要复用相同版本号覆盖上传,或者构建生产镜像时强制添加
--no-cache参数跳过缓存。
内容的提问来源于stack exchange,提问作者Egor Wexler
相关产品推荐
相关产品推荐

