PyInstaller打包Python项目为可执行文件

使用 PyInstaller 可以将 Python 项目打包为自带环境的可执行文件。通过 Dockerfile 构建一个打包镜像,避免可执行文件在较旧版本的系统上执行时报错。


使用 PyInstaller

PyInstaller 使用起来非常简单:

# 激活 conda 环境(假设项目环境为 build-env)
$ mamba activate build-env

# 安装 pyinstaller
$ mamba install -y pyinstaller

# 打包到一个文件夹中(方便调试)
$ pyinstaller my_script.py

# 打包到一个文件中(方便使用)
$ pyinstaller --onefile my_script.py

执行打包命令后会在当前目录下创建两个目录和一个文件:

名称 内容
build/ 临时构建文件
dist/ 最终可执行文件或应用目录
*.spec 打包配置文件

我们需要的可执行文件位于 dist 目录下。

GLIBC 问题

GLIBC(GNU C Library)是 Linux 系统中最核心的运行时库,它为程序提供文件读写、内存管理、进程控制、网络通信等基础系统接口,并负责程序与 Linux 内核之间的交互。

当 PyInstaller 打包时系统的 glibc 版本比服务器上高,PyInstaller 生成的可执行文件可能依赖高版本 glibc,导致打包得到的二进制文件在服务器上运行时由于 glibc 版本报错。

为了解决 GLIBC 版本问题,需要在与服务器系统版本一致或接近的环境中打包,使用 Docker 可以很方便得到一个这样的环境。

容器内交互式打包

启动一个与服务器的系统版本一致或接近的容器,确保容器内的 glibc 版本与服务器一致,安装 Python 环境并使用 PyInstaller 打包:

# 启动一个 centos7 容器
$ docker run -dit --name=centos7-builder centos:7.9.2009 tail -f /dev/null

# 进入打包容器
$ docker exec -it centos7-builder bash

# 查看容器内的 glibc 版本
$ ldd --version
ldd (GNU lilbc) 2.17
...

# 在容器内安装 Python 环境,拉取项目代码,打包
...

打包完成后,在宿主机上执行命令,将容器内的打包产物复制出来:

$ docker cp centos7-builder:/root/my_py_prj/dist ./

构建打包镜像

miniforge 基础镜像

该镜像以 centos:7.9.2009 为基础,安装了 Miniforge 并将 conda 命令配置到环境变量中,为构建项目专用打包环境提供一个基础镜像。

在线构建会联网从 GitHub 下载 Miniforge 安装器,请确保当前网络能够访问 GitHub 或传入一个代理地址:

Dockerfile
ARG HTTPS_PROXY=""

FROM centos:7.9.2009

ARG HTTPS_PROXY

ENV CONDA_DIR=/opt/conda
ENV PATH=$CONDA_DIR/bin:$PATH

RUN set -ex && \
# 1. 修复 YUM 源(默认源已 EOL)
sed -i 's/^mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-*.repo && \
sed -i 's|^#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-*.repo && \
# 2. 下载 Miniforge 安装脚本(允许临时使用代理)
if [ -n "$HTTPS_PROXY" ]; then \
https_proxy="$HTTPS_PROXY" curl -fsSL -o /tmp/Miniforge3.sh "https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-$(uname)-$(uname -m).sh"; \
else \
curl -fsSL -o /tmp/Miniforge3.sh "https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-$(uname)-$(uname -m).sh"; \
fi && \
# 3. 安装 Miniforge
bash /tmp/Miniforge3.sh -b -p $CONDA_DIR && \
rm /tmp/Miniforge3.sh && \
# 4. 清理 conda 缓存
conda clean --all -y

WORKDIR /workspace

构建 miniforge 镜像:

# 构建 miniforge:centos7 镜像(无需代理或离线构建)
$ docker build -t miniforge:centos7 .

# 联网构建 miniforge:centos7 镜像(使用代理)
$ docker build --build-arg HTTPS_PROXY=$https_proxy -t miniforge:centos7 .

测试能否使用 conda 命令:

$ docker run --rm miniforge:centos7 conda --version
conda 26.3.2

项目专用打包镜像

当 Python 项目使用的模块不再频繁变动,可以考虑构建项目专用打包镜像。

由于 miniforge:centos7 镜像中不含 Python 解释器、项目所需模块以及 PyInstaller,构建专用打包镜像时需要将这些安装进来,并通过 ENTRYPOINT 脚本接收通过命令行传入的 pyinstaller 打包命令。

因此需要将入口脚本 entrypoint.sh 和项目的 environment.yml 放到 Dockerfile 同级目录。

Dockerfile 内容:

Dockerfile
FROM miniforge:centos7

ENV ENV_NAME="build-env"

COPY environment.yml /tmp/environment.yml

# 使用 conda 更新环境
RUN set -eux && \
conda env create -n $ENV_NAME -f /tmp/environment.yml && \
conda run -n $ENV_NAME pip install pyinstaller && \
conda clean --all -y

COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh

ENTRYPOINT ["/entrypoint.sh"]

入口脚本:

entrypoint.sh
#!/bin/bash
set -e
# 在 build-env 环境执行用户命令
exec conda run -n build-env "$@"

环境信息:

environment.yml
name: ranger-manager
channels:
- conda-forge
dependencies:
- openpyxl
- pandas
- python=3.12
- pyyaml
- pip:
- StrEnum==0.4.15
- apache-ranger==0.0.12

构建 ranger-manager-builder 镜像:

$ docker build  -t ranger-manager-builder:centos7 .

使用该镜像进行打包:

docker run --rm \
-u $(id -u):$(id -g) \
-v $(pwd):/workspace \
ranger-manager-builder:centos7 \
pyinstaller main.py --distpath ./output

参考资料

CI 管线中安装 miniforge
PyInstaller 的功能和工作原理

PyInstaller打包Python项目为可执行文件

https://thinklong.me/pyinstaller/

作者

ThinkLong

发布于

2026-05-07

更新于

2026-06-03

许可协议

评论

+