1. 项目概述与安装方案选型
1.1 为什么要自己动手装 Python 3.10
只要你是做运维或后端开发的,大概率会遇到这个场景:新项目用了 Python 3.10 的新语法,代码在本地跑得好好的,一上服务器就报错。一查,CentOS 7 自带的还是 Python 2.7.5,CentOS 8 带的是 3.6,CentOS 9 是 3.9,离 3.10 都差着版本。更麻烦的是,系统的 yum 包管理器底层依赖的是旧版 Python,你不能直接“升级”系统自带的 Python,否则 yum 立刻罢工。
这时候最稳妥的办法,就是在 CentOS 上单独编译安装一套 Python 3.10,放在独立的目录里,跟系统 Python 完全隔离。装完之后,你可以在命令行敲python3.10使用新版,也可以给项目单独建一个虚拟环境,互不干扰。整个过程并不复杂,但坑不少:依赖库缺一个,pip 可能装上就废;openssl 版本不够,ssl 模块直接不可用;configure 参数选错,编译的时间能翻好几倍。
这篇文章我就把完整流程拆开讲清楚,从方案选型、依赖准备、编译参数到常见问题排查,全部按我实际在服务器上操作的顺序来写。适合刚接触 Linux 的后端开发,也适合要批量部署环境的运维同学。照着我这个走一遍,基本十分钟能编译上,后面踩坑点我也都给你标出来了。
1.2 四种安装方式,到底选哪个
先说结论:服务器环境最推荐“源码编译安装”,没有之一。但我也把其他方式列出来,方便你根据场景自己判断。
| 安装方式 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| yum / EPEL 源安装 | 对版本要求不严格 | 命令少、速度快 | EPEL 仓库往往没有 Python 3.10,有也是 3.6/3.8 级别,版本不可控 |
| SCL(Software Collections) | CentOS 7 老环境应急 | 不覆盖系统 Python | 部分 SCL 源已停止维护,配置源比较折腾 |
| 源码编译 | 生产服务器、版本敏感项目 | 版本精确、目录隔离、可定制性强 | 编译耗时长,依赖库要手动补齐 |
| pyenv | 开发机多版本切换 | 版本切换方便、用户级安装 | 生产环境多一层管理工具,增加了复杂度 |
实际上,你如果去查 CentOS 官方源,Python 3.10 基本是找不到的。CentOS 7 的生命周期已经结束,官方源里 Python 还是老版本;CentOS Stream 9 自带 3.9,但很多业务偏偏要 3.10 的特性,比如match语句、更清晰的类型报错、性能优化等,只能走源码编译这条路。源码编译看起来麻烦,但你只要把依赖装全,后面的坑就少一大半。
1.3 整体思路:避免“污染”系统 Python
整个安装过程可以拆成四步:装依赖、下源码、编译安装、配置环境。这里面最核心的一条原则是:绝对不要用 make install 直接覆盖系统路径下的python或python3命令,因为 CentOS 的 yum、firewalld、selinux 等一堆系统工具都依赖旧版 Python。我用的是make altinstall,这个名字里有 “alt” 就是告诉你,它只会生成python3.10这样的独立命令,不动系统原来的 Python。
目录规划上,我把 Python 3.10 装到/usr/local/python3.10,这样卸载也方便,删一个目录就干净了。后面所有项目的虚拟环境也都基于这个路径创建,跟系统环境完全隔离,出问题也不影响其他服务。这就是整个方案的核心思路。
2. 安装前准备:依赖与源码获取
2.1 基础编译工具链一次装齐
源码编译第一步,先把编译器和依赖库装好。我习惯这样一把梭:
yum -y groupinstall "Development Tools" yum -y install wget tar zlib-devel bzip2-devel openssl-devel libffi-devel \ readline-devel sqlite-devel ncurses-devel gdbm-devel tk-devel xz-devel第一行是安装 gcc、make、patch 这一整套编译工具。如果你用的 CentOS 是最小化安装,这一步尤其重要,别跳。第二行的每个包都不是随便装的,少了哪一个,后面编译出来的 Python 就缺对应的功能模块。比如zlib-devel缺失,pip装包时一解压就报错;libffi-devel缺失,ctypes模块直接编译失败,而很多第三方库都依赖 ctypes。
这里提醒一句:Development Tools这个组包比较大,下载大概几百 MB,耗时要几分钟,属于正常现象。如果服务器网络比较慢,可以先把 yum 源换成国内镜像,比如清华源或阿里源,速度能快不少。换源的方法很简单,修改/etc/yum.repos.d/CentOS-Base.repo里的 baseurl 就行,这里不展开,你网上搜“centos 换国内源”就有现成配置。
2.2 这几个关键库,提前解释一下用途
很多人装完 Python,发现pip install的时候报一个很诡异的错:ModuleNotFoundError: No module named '_ssl'。问题往往就出在编译前没装openssl-devel,或者系统的 openssl 版本太老。
Python 3.10 的 ssl 模块要求 OpenSSL 1.1.1 以上,而 CentOS 7 默认的 openssl 是 1.0.2k,不够用。这个问题我先埋个伏笔,后面“常见问题”部分详细讲。除了 openssl,这几个库也值得留意:
readline-devel:装完这个,Python 交互式命令行才能用方向键查找历史命令,否则按上下键会出现乱码。sqlite-devel:Python 内置 sqlite3 模块依赖它,Django 等框架默认数据库迁移脚本会用到。libffi-devel:cffi 库和 Python 标准库里的ctypes都靠它,很多 C 扩展的 Python 包必须用。zlib-devel:pip 安装包时处理压缩数据依赖它,缺失会导致tarfile解压失败。
总之,这一步多花两分钟,后面至少少折腾两小时。
2.3 下载 Python 3.10 源码包并校验
源码不建议去乱七八糟的第三方网站下载,直接到 Python 官方 FTP 下:
cd /usr/local/src wget https://www.python.org/ftp/python/3.10.11/Python-3.10.11.tgz我推荐用 3.10.11,这是 Python 3.10 的最终维护版本,比 3.10.0 到 3.10.10 修复了大量 bug,新装环境没必要选旧版。下载完解压:
tar xzf Python-3.10.11.tgz cd Python-3.10.11习惯上我会顺手校验一下文件完整性,防止下载过程损坏:
wget https://www.python.org/ftp/python/3.10.11/Python-3.10.11.tgz.asc gpg --verify Python-3.10.11.tgz.asc Python-3.10.11.tgz不过国内网络环境下访问 python.org 可能有点慢,如果下载超时,可以用华为云、阿里云上的 Python 镜像目录,路径结构一致,速度更快。校验签名不是必须步骤,但如果你是在生产环境装,花一分钟做一下更放心。
3. 核心实操:编译安装全流程
3.1 configure 参数怎么选,影响有多大
进入源码目录后,第一步是执行 configure。这一步会根据你当前系统的环境,生成 Makefile,决定后续编译行为。我用的命令是:
./configure --prefix=/usr/local/python3.10 \ --enable-optimizations \ --with-ensurepip=install这三个参数的含义我得逐个说一下,因为你如果不懂它们,后面出了问题都不知道该怪谁:
--prefix指定安装目录,这个最重要。我装在/usr/local/python3.10,所有配套命令、库文件都在这下面,卸载时直接删目录,不污染系统。--enable-optimizations会启用 PGO(Profile-Guided Optimization),也就是编译时先跑一遍测试程序,根据运行数据做针对性优化。好处是装出来的 Python 运行速度更快,代价是编译时间会翻倍,甚至三倍。我第一次没经验,开着这个参数在低配服务器上编译,硬生生等了四十分钟。如果机器性能一般,或者你只是想在测试环境快速装一个,可以去掉这个参数。--with-ensurepip=install则是让安装过程自动带上 pip,省得后面手动装。
需要说明的是,configure 执行完后会输出一段配置摘要,里面会显示你系统里检测到的几个关键库,比如OpenSSL、libffi、zlib。建议你花十秒扫一眼,如果看到no,说明对应模块没编进去,这时候返回去补装依赖库再重新 configure,比装完再折腾省事得多。
3.2 编译与安装的完整命令序列
configure 没问题后,开始正式编译。这段命令我建议直接整段复制:
make -j$(nproc) make altinstall-j$(nproc)是让 make 用 CPU 的所有核心并行编译,能明显缩短编译时间。如果你不确定服务器有几个核,可以先执行nproc看下输出。如果编译过程中报错,先别急着重试,往下看“常见问题”部分。
make altinstall跟make install的区别我前面提过,这里再强调一次:install 会把 Python 可执行文件安装成python3,如果系统原本没有 python3 还好,但在 CentOS 7 上,某些系统脚本或第三方软件可能已经创建了python3软链,直接覆盖很容易弄崩依赖。而altinstall生成的是python3.10、pip3.10这种带完整版本号的命令,不会去改python3。
编译完成后,可以确认一下安装结果:
ls /usr/local/python3.10/bin/正常情况下能看到python3.10、pip3.10、pip3、python3.10-config等文件。这里注意,pip3也会生成,但因为它在独立的/usr/local/python3.10/bin/目录里,并不影响系统其它路径下的 pip。
3.3 软链接与 PATH 配置
altinstall装完,默认情况下你直接敲python3.10是找不到命令的,因为/usr/local/python3.10/bin不在 PATH 里。有两种处理办法,我更推荐做软链:
ln -s /usr/local/python3.10/bin/python3.10 /usr/local/bin/python3.10 ln -s /usr/local/python3.10/bin/pip3.10 /usr/local/bin/pip3.10这样所有用户都能直接用python3.10命令,不用改每个用户的 PATH。如果你希望设置成默认的python3,我建议你要想清楚,因为 CentOS 7 默认没有 python3,把它作为默认 python3 影响不大,但 CentOS 8/9 自带的 3.6/3.9 就不要覆盖了。
想长期使用的话,也可以把/usr/local/python3.10/bin加进 PATH 环境变量:
echo 'export PATH=/usr/local/python3.10/bin:$PATH' >> /etc/profile.d/python310.sh source /etc/profile.d/python310.sh这种做法的好处是不产生软链文件,目录本身就是独立的,管理更干净。两种方式任选其一,我实际更习惯软链,因为执行which python3.10时路径清晰,一眼能看出来源。
验证一下安装结果:
python3.10 -V pip3.10 -V输出Python 3.10.11和对应的 pip 版本,安装就成功了。
3.4 虚拟环境:项目隔离才是正经事
装完 Python 3.10 之后,我强烈建议所有项目都使用虚拟环境,而不是直接往全局环境里pip install。原因很简单:不同项目依赖的包版本可能互相冲突,比如 A 项目要 Django 3.2,B 项目要 Django 4.2,全装在一个环境里迟早出事。
创建虚拟环境用标准库的 venv 就行,不需要额外装 virtualenv:
cd /opt mkdir myapp && cd myapp /usr/local/python3.10/bin/python3.10 -m venv venv source venv/bin/activate激活后,命令行前面会出现(venv)前缀,这时候敲python和pip用的都是虚拟环境里的 3.10,跟系统环境完全隔离。后续项目部署时,可以直接在 systemd 服务里指定虚拟环境里的 Python 绝对路径,比source activate更可靠:
ExecStart=/opt/myapp/venv/bin/python /opt/myapp/app.py这一步在写 Dockerfile 或写启动脚本时特别有用,后面扩展方案里我再细说。
4. 常见问题与排查技巧实录
4.1 pip 安装时报 SSL 模块不可用,怎么破
这是 CentOS 7 上编译 Python 3.10 遇到频率最高的坑,没有之一。现象是:Python 编译安装一切正常,python3.10 -V也正常,但一执行pip3.10 install requests,直接报错Could not fetch URL ... There was a problem confirming the ssl certificate,或者更干脆地提示ModuleNotFoundError: No module named '_ssl'。
原因我也提到过,CentOS 7 自带的 OpenSSL 是 1.0.2k,而 Python 3.10 要求至少 1.1.1。你会发现 configure 的时候日志里 OpenSSL 那一行是no,但 configure 并不会因此中止,它只是默默地去掉了 ssl 模块,等你装完才发现 pip 废了。解决办法是重新编译一个高版本 OpenSSL,再回过头来重新编译 Python。
我在服务器上的操作步骤是:
cd /usr/local/src wget https://www.openssl.org/source/openssl-1.1.1w.tar.gz tar xzf openssl-1.1.1w.tar.gz cd openssl-1.1.1w ./config --prefix=/usr/local/openssl --openssldir=/usr/local/openssl shared zlib make -j$(nproc) make install等 OpenSSL 装好,重新回到 Python 源码目录,加上两个参数重新 configure,然后重新 make:
cd /usr/local/src/Python-3.10.11 make clean ./configure --prefix=/usr/local/python3.10 \ --enable-optimizations \ --with-ensurepip=install \ --with-openssl=/usr/local/openssl \ --with-openssl-rpath=auto make -j$(nproc) make altinstall--with-openssl指定我们新编译的 OpenSSL 路径,--with-openssl-rpath=auto让 Python 在运行时自动找到对应的动态库,否则编译过了运行也会因为找不到 libssl.so 报错。重新编译后再执行pip3.10 install就正常了。这个坑我踩过两次,现在不管装什么版本的 Python,凡是 CentOS 7,我都默认先把 OpenSSL 升到 1.1.1 再编译,一次成型。
4.2 编译到一半卡死或被 kill,多半是内存不够
加了--enable-optimizations之后,编译过程会额外执行一段 profiling 测试,这段时间内存占用会明显上涨。我在一台内存只有 1G 的小服务器上试过一次,make跑到一半直接被 OOM Killer 干掉,日志显示Killed或make: *** [Python] Error 137,没有任何明确报错,很迷惑。
排查方法很简单,编译前敲一下free -h看看剩余内存。如果机器内存小于 2G,我建议直接去掉--enable-optimizations,或者用make -j1单核编译,降低内存峰值。不要硬扛,你是在部署环境,不是在跑基准测试,优化那点性能收益远不如先把业务跑起来重要。等以后机器配置升了,再重新编译也不迟。
4.3 系统 Python 被误改,yum 直接崩溃,怎么救
还有一个不少新手会犯的错误:装完 Python 3.10 后,手一抖把/usr/bin/python软链接指向了 Python 3.10,或者干脆把/usr/bin/python2.7给删了。结果第二天执行yum install nginx,发现 yum 报错:No module named yum。
原因是 yum 本身是用 Python 2 写的,你把默认 python 换成 3.10,它自然找不到 yum 模块了。这种问题处理起来不复杂,但要冷静:
ls -l /usr/bin/python*看看软链是不是被改了。如果/usr/bin/python指向了别的路径,把它恢复回来:
ln -sf /usr/bin/python2.7 /usr/bin/python万一/usr/bin/python2.7已经被删了,就需要从系统安装盘或镜像仓库里把这个包恢复出来。CentOS 7 上对应的 RPM 包是python-2.7.5-90.el7.x86_64.rpm,下载后用rpm -ivh重新装回即可。安装时注意别和现有的系统文件冲突,必要时候加--force。这里的关键经验就是:这个错误能别踩就别踩,把系统自带的 Python 当“系统文件”而不是“编程工具”,任何新的 Python 版本都用独立目录装。
4.4 常见异常速查表
嫌上面内容太长不好记的,可以直接收藏这个表:
| 现象 | 可能原因 | 处理办法 |
|---|---|---|
No module named '_ssl' | OpenSSL 版本低于 1.1.1 或 openssl-devel 未装 | 编译安装 OpenSSL 1.1.1+,重新 configure 并指定--with-openssl |
make中途被 OOM Kill | 内存不足,PGO 测试占用过高 | 去掉--enable-optimizations,或降低并行度-j1 |
bash: python3.10: command not found | 未配置软链接或 PATH | 添加/usr/local/python3.10/bin到 PATH,或创建软链 |
yum报No module named yum | /usr/bin/python被错误覆盖 | 恢复/usr/bin/python软链指向 python2.7 |
ModuleNotFoundError: No module named 'sqlite3' | 缺 sqlite-devel | 安装 sqlite-devel 后重新编译 |
pip install下载速度极慢 | 默认访问官方 PyPI 源 | 配置国内 PyPI 镜像源 |
如果用国内源,pip 可以这样配置:
pip3.10 config set global.index-url https://mirrors.aliyun.com/pypi/simple/配置好之后,pip 的下载速度会有一个质的提升,尤其是安装 pandas、numpy 这种大包时,差别非常明显。
5. 替代方案与经验建议
5.1 pyenv:开发机多版本管理利器
如果你是在本地开发机上做测试,需要在 Python 3.9、3.10、3.11 之间来回切换,那我更推荐用 pyenv,而不是反复源码编译。pyenv 是一个用户级的 Python 版本管理工具,安装后可以一条命令装任意版本:
curl https://pyenv.run | bash pyenv install 3.10.11 pyenv local 3.10.11pyenv 在编译底层逻辑上跟我上面写的源码编译是一样的,所以依赖库同样不能少,重点还是 gcc、openssl-devel、libffi-devel 这些。它的优势是版本切换非常干净,pyenv local 3.10.11设置完,当前目录下python命令就自动变成 3.10.11,去别的目录又切回原来的版本,适合个人电脑。但生产服务器我一般不用 pyenv,因为多一层工具就会多一个故障点,而且 systemd 启动脚本指定解释器路径时,pyenv 版本下的路径不直观。
5.2 Docker 方案:从根上避开环境问题
如果你有 Docker 环境,最省心的方式其实是根本不装 Python 到宿主机,直接用官方镜像。这样 CentOS 宿主机只负责跑容器,Python 版本、依赖库都在镜像里固化,换台机器也能复现同样的环境。
一个最基础的三行 Dockerfile 就能解决:
FROM python:3.10-slim WORKDIR /app COPY requirements.txt . RUN pip install -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple/ COPY . . CMD ["python", "app.py"]构建:
docker build -t myapp:latest . docker run -d --name myapp -p 8000:8000 myapp:latest镜像方式我特别推荐给那些需要统一团队开发环境、或者运维要批量部署多个 Python 项目的场景。宿主机不用跑一堆编译工具链,也不用担心污染系统 Python,干净利落。当然,如果你的服务器没有 Docker,或者因为安全策略不让用容器,那就老老实实按前面的源码编译走。
5.3 我的几条实操心得
最后说几个我这么多年在 CentOS 上装 Python 总结出来的经验,可能比前面的命令更值钱:
第一,装 Python 之前先改 yum 源。不换国内源的话,光groupinstall "Development Tools"这一步就能让你等到怀疑人生。
第二,把编译命令写成一个 shell 脚本存到本地。比如install_python310.sh,下次在新机器上部署,直接改一下版本号执行,十几分钟搞定,不用现场回忆命令。脚本里记得把依赖安装、源码下载、configure、make、软链全部串起来。
第三,生产环境不要只留一个 Python 3.10。你以后很可能还要装 Python 3.11 甚至 3.12,目录规划时一定要带版本号,比如/usr/local/python3.10、/usr/local/python3.11,并行的放那里,互不影响。
第四,pip 安装包之前先做镜像源配置。这个建议放前面或后面都行,反正别忘,不然首次pip install就会让你见识到什么叫网络超时。
第五,每次编译完一定要做一次完整验证,不光是python3.10 -V,还要顺手python3.10 -c "import ssl, sqlite3, ctypes; print('ok')",确认关键模块都在。这一个小动作,能帮你避免下个月突然发现某个功能不可用的尴尬。
我在实际部署里最常用的一句话是:编译 Python 不难,难的是别让这次安装影响系统的其他部分。只要记住“独立目录、altinstall、虚拟环境”这三个关键词,你装的就不是一个孤零零的解释器,而是一套稳定、可维护的 Python 运行环境。