使用PyInstaller打包Python脚本

使用 PyInstaller 可以将 Python 脚本打包为自带环境的可执行程序。如果需要在 glibc 版本差异较大的系统上执行 Python 程序,推荐构建一个专用打包镜像。


使用 PyInstaller

PyInstaller 使用起来非常简单:

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

# 安装 pyinstaller
$ mamba install -y pyinstaller

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

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

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

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

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

容器内打包

选择与目标服务器版本相近的基础镜像打包 Python 脚本,可以避免一些兼容性问题。例如,当打包环境的 glibc 版本(glibc 2.39)比服务器环境(glibc 2.17)新时,PyInstaller 生成的可执行文件可能意外依赖高版本 glibc,该文件在服务器上运行就会报错。

启动打包容器

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

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

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

打包完成后,可以在宿主机上将容器内的打包产物复制出来:

$ docker cp centos7-build:/root/my_script/dist/my_script ./

查看 glibc 版本

# 查看当前系统的 glibc 版本
$ ldd --version
ldd (Ubuntu GLIBC 2.39-0ubuntu8.7) 2.39
...

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

# 查看某个二进制文件依赖的 glibc 版本
$ objdump -T libstdc++.so.6.0.34 | grep GLIBC_ | sed 's/.*GLIBC_//' | sort -V | tail -1
2.17) secure_getenv

构建专用打包镜像

基础打包镜像

该基础打包镜像使用 CentOS 7 镜像作为基础,修复已经 EOL 的默认 YUM 源,安装 wget 下载工具,通过代理从 github 下载 miniforge 安装脚本,创建名为 py312 的 conda 环境(仅安装 python 3.12 和 pyinstaller 模块):

ARG HTTP_PROXY=""
ARG HTTPS_PROXY=""

FROM centos:7.9.2009

ARG HTTP_PROXY
ARG HTTPS_PROXY

RUN set -ex && \
# 1. 修复 YUM 源
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. 安装 wget
yum install -y wget && yum clean all && \
# 3. 仅在 wget 下载时临时使用代理(如果提供了代理)
if [ -n "$HTTPS_PROXY" ]; then \
https_proxy="$HTTPS_PROXY" wget -O /tmp/Miniforge3.sh "https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-$(uname)-$(uname -m).sh"; \
else \
wget -O /tmp/Miniforge3.sh "https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-$(uname)-$(uname -m).sh"; \
fi && \
# 4. 安装 Miniforge(不需要代理)
bash /tmp/Miniforge3.sh -b -p /root/conda && \
rm /tmp/Miniforge3.sh && \
# 5. 创建 conda 环境
export PATH="/root/conda/bin:$PATH" && \
conda create -n py312 python=3.12 pyinstaller -c conda-forge -y && \
conda clean --all -y

ENV PATH="/root/conda/envs/py312/bin:/root/conda/bin:$PATH"
WORKDIR /workspace

制作基础打包镜像,可以通过命令行传入代理配置:

# 构建 pyinstaller-centos7:latest 镜像
$ docker build --build-arg HTTPS_PROXY=$https_proxy -t pyinstaller-centos7 .

使用基础打包镜像进行打包,注意需要位于 Python 项目脚本文件 my_scritp.py 和依赖文件 environment.yml 所在目录:

$ docker run --rm -v $(pwd):/workspace pyinstaller-centos7 bash -c "\
conda env update -f /workspace/environment.yml -n py312 && \
pyinstaller --onefile my_scritp.py"

专用打包镜像

使用基础打包镜像时每次都需要下载安装 environment.yml 中的模块,如果 Python 项目使用的模块不变,可以为该项目制作一个专用打包镜像:

FROM pyinstaller-builder:latest

# 复制项目的 environment.yml 到镜像中
COPY environment.yml /tmp/environment.yml

# 使用 conda 更新环境
RUN source /root/conda/etc/profile.d/conda.sh && \
conda activate py312 && \
conda env update -f /tmp/environment.yml -n py312 && \
conda clean --all -y

制作专用打包镜像,需要将 environment.yml 复制到 Dockerfile 同目录:

# 构建 my-script-builder:latest 镜像
$ docker build -t my-script-builder .

使用专用打包镜像进行打包:

$ docker run --rm -v $(pwd):/workspace my-script-builder pyinstaller --onefile my_scritp.py

参考资料

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

使用PyInstaller打包Python脚本

https://thinklong.me/pyinstaller/

作者

ThinkLong

发布于

2026-05-07

更新于

2026-05-07

许可协议

评论

+