You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PyInstaller打包python-keystoneclient在Docker中运行失败求助

PyInstaller打包python-keystoneclient依赖应用的Docker部署问题

本地运行PyInstaller编译后的resourceuploader二进制文件正常,但部署到debian:trixie-slim容器时出现版本元数据找不到的错误,使用Python 3.10 + venv环境,尝试多种自定义Hook组合无效。


自定义Hook

# -*- mode: python ; coding: utf-8 -*-
from PyInstaller.utils.hooks import collect_submodules
from PyInstaller.utils.hooks import copy_metadata
from PyInstaller.utils.hooks import collect_data_files

import sys
from os import path
site_packages = next(p for p in sys.path if 'site-packages' in p)

hiddenimports = collect_submodules("python-swiftclient")


datas = collect_data_files('os_service_types',subdir='data')
datas += collect_data_files('keystoneauth1')
datas += collect_data_files('keystoneclient')

added_files = [
    (path.join(site_packages,'python_keystoneclient-5.3.0.dist-info'), 'python_keystoneclient-5.3.0.dist-info'),
]
added_files += copy_metadata('python-keystoneclient')
added_files += copy_metadata('keystoneauth1')
added_files += copy_metadata('fixtures')

打包命令

pyinstaller --add-data 'bootstrap.yml:.' \
    --additional-hooks-dir='custom_hooks' \
    --python .venv/bin/python \
    --clean \
    --onefile resourceuploader.py

Dockerfile

FROM debian:trixie-slim
ENV PYTHONUNBUFFERED=1
RUN mkdir /mnt/FTP
ADD dist/resourceuploader /resourceuploader
ADD dist/dev_config.yml /dev_config.yml
ENTRYPOINT ["/bin/bash"]
# ENTRYPOINT ["/resourceuploader"]

错误信息

Traceback (most recent call last):
  File "pbr/version.py", line 475, in _get_version_from_importlib_metadata
  File "importlib/metadata/__init__.py", line 969, in distribution
  File "importlib/metadata/__init__.py", line 548, in from_name
importlib.metadata.PackageNotFoundError: No package metadata was found for python-keystoneclient

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "resourceuploader.py", line 14, in <module>
  File "<frozen importlib._bootstrap>", line 1027, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1006, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 688, in _load_unlocked
  File "PyInstaller/loader/pyimod02_importers.py", line 419, in exec_module
  File "resourceuploader_handler.py", line 9, in <module>
  File "<frozen importlib._bootstrap>", line 1027, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1006, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 688, in _load_unlocked
  File "PyInstaller/loader/pyimod02_importers.py", line 419, in exec_module
  File "swiftclient/__init__.py", line 19, in <module>
  File "<frozen importlib._bootstrap>", line 1027, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1006, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 688, in _load_unlocked
  File "PyInstaller/loader/pyimod02_importers.py", line 419, in exec_module
  File "swiftclient/client.py", line 51, in <module>
  File "<frozen importlib._bootstrap>", line 1027, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1006, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 688, in _load_unlocked
  File "PyInstaller/loader/pyimod02_importers.py", line 419, in exec_module
  File "keystoneclient/__init__.py", line 36, in <module>
  File "pbr/version.py", line 505, in version_string
  File "pbr/version.py", line 498, in semantic_version
  File "pbr/version.py", line 482, in _get_version_from_importlib_metadata
  File "pbr/packaging.py", line 866, in get_version
Exception: Versioning for this project requires either an sdist tarball, or access to an upstream git repository. It's also possible that there is a mismatch between the package name in setup.cfg and the argument given to pbr.version.VersionInfo. Project name python-keystoneclient was given, but was not able to be found.
[8] Failed to execute script 'resourceuploader' due to unhandled exception!

解决建议

1. 修复Hook的元数据映射错误

你定义的added_files变量未被PyInstaller识别,PyInstaller只会读取Hook中的datas、hiddenimports等预设变量。同时手动指定dist-info路径容易出现版本兼容问题,修改Hook如下:

# -*- mode: python ; coding: utf-8 -*-
from PyInstaller.utils.hooks import collect_submodules, copy_metadata, collect_data_files

hiddenimports = collect_submodules("python-swiftclient")
hiddenimports.extend(collect_submodules('pbr'))  # 新增:确保pbr模块被导入

datas = collect_data_files('os_service_types',subdir='data')
datas += collect_data_files('keystoneauth1')
datas += collect_data_files('keystoneclient')
# 合并元数据到datas,替换原added_files代码
datas += copy_metadata('python-keystoneclient')
datas += copy_metadata('keystoneauth1')
datas += copy_metadata('fixtures')
datas += copy_metadata('pbr')  # 新增:pbr自身也需要元数据

2. 在容器内完成打包(推荐)

本地环境与debian容器的系统库可能存在差异,直接在目标容器环境内打包可避免兼容性问题:

  • 修改Dockerfile,先安装Python 3.10、venv、gcc等编译依赖;
  • 复制代码到容器,创建venv并安装所有依赖;
  • 执行PyInstaller打包命令;
  • 最后基于打包好的二进制文件构建轻量镜像。

3. 跳过pbr版本检测(终极方案)

如果上述方法无效,可通过mock跳过pbr的版本检测逻辑,在resourceuploader.py最顶部添加:

import sys
from unittest.mock import patch

# Mock pbr版本检测,返回已知版本号
with patch('pbr.version.VersionInfo.version_string') as mock_version:
    mock_version.return_value = '5.3.0'
    # 提前导入依赖模块
    import swiftclient
    import keystoneclient

# 后续正常编写业务代码

内容的提问来源于stack exchange,提问作者Cristian Diaz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 01:50:59