Amazon Linux 2023 源码编译 Python 3.12 与全局环境变量配置 刚拿到一台Amazon Linux 2023实例时最容易被卡住的需求就是装新版Python 3.12。我手头有个内部的数据清洗任务代码用了tomllib和Self类型这类只在 3.11 里稳定的特性系统默认的 Python 3.9 跑不动当时我下意识执行dnf install python3.12结果直接No match for argument。这一篇就把我在 Amazon Linux 2023 上编译安装 Python 3.12并且把环境变量一次性配到位的完整过程拆开讲包括每一步背后的逻辑、那些官方文档没写的坑以及多版本共存时怎么保证安全和稳定。不管你是临时想跑个新脚本还是要正经交付服务器环境按我这套流程走下来都能落地。1. 先搞清楚现状AL2023 自带 Python 的版本与仓库限制1.1 系统默认自带的情况Amazon Linux 2023 默认的 Python 版本是 3.9这个版本满足绝大多数系统工具的依赖比如dnf、cloud-init、ec2-net-utils这些系统组件都在用它。你可以执行cat /etc/os-release python3 --version看到类似Python 3.9.16的输出是正常的。这里有个很重要的认知系统自带的 Python 3.9 不能动因为很多系统级的 Python 脚本尤其/usr/libexec和/usr/bin下的工具都依赖它。如果你把它替换成 3.12轻则dnf直接报错重则整台实例的包管理器都无法工作。1.2 默认软件源里搜不到 Python 3.12在 AL2023 上执行下面这条命令dnf search python3.12大概率得到的结果是No matches found或者只有零散的子包但没有完整的运行时。这是因为 AL2023 的软件仓库策略相对保守它主要维护 LTS 版本Python 主版本的更新节奏远慢于社区。仓库里目前比较确定的是python3.11和相关模块你可以试一下dnf info python3.11如果对 3.11 可以接受直接sudo dnf install -y python3.11 python3.11-pip这种安装方式最简单但既然这里的需求明确是Python 3.12而 3.12 在多数云厂商默认仓库里都没有那就必须换路线。1.3 搜索不到不等于装不了我见过很多人在dnf search找不到包之后就放弃或者直接换系统。实际上这只是说明默认仓库没有预编译好的 RPM并不代表 Python 3.12 用不了。常见的替代路径有三条EPEL 扩展仓库、源码编译、自建 RPM 包。EPEL 对 AL2023 的支持目前还处于逐步完善阶段Python 3.12 的包并不齐全有时候装出来还会依赖一堆用不上的模块反而拖慢机器。在云服务器上最稳妥、也最可控的思路就是走一次源码编译。2. 方案选型为什么我选择源码编译而不是走 RPM 或者工具链2.1 三种可行路线的对比方案优点缺点适用场景dnf直接装 3.11快、省心、系统原生管理当前仓库没有 3.12版本可能滞后不挑版本只想尽快跑通EPEL 装 3.12比源码安装省事AL2023 下包不齐可能拉入多余依赖恰好遇到仓库里有完整包的时候源码编译 3.12版本完全可控、可指定 prefix、优化选项丰富编译耗时几分钟到十几分钟、需要装开发依赖生产环境、多版本共存、有定制需求我自己在 AL2023 上测试源码编译 3.12 整个过程大概 8~12 分钟取决于实例规格这点时间成本换来的是一个完全符合预期的独立 Python很划算。2.2 源码编译为什么可控用源码编译可以自主决定:安装目录--prefix把它隔离在/usr/local/python3.12不动系统路径启用哪些编译优化比如--enable-optimizations做 PGO是否顺带装 pip--with-ensurepipinstall编译时链接系统 OpenSSL 的方式。这种隔离思路在多个 Python 版本共存时尤其重要。你不需要删除系统 Python也不用改/usr/bin下的任何文件就能拥有一个完全独立的 3.12 环境后续维护也不影响系统稳定性。2.3 编译安装的底层逻辑configure 到底在干嘛很多新手对./configure这步不太理解可以把它类比成装修前先量房。它不会真正构建 Python而是做一堆检查当前系统有没有 C 编译器OpenSSL 头文件在哪libffi版本够不够然后把这些答案写进Makefile。如果系统缺少某个库configure阶段就会报错告诉你缺了什么这时候及时补依赖比等make到一半再中断要好处理得多。所以记住这个链条依赖检测 → configure 生成 Makefile → make 编译 → make install 安装。后续踩坑大部分都发生在第一步和第三步之间的衔接位置。3. 完整实操从零编译安装 Python 3.12 的手把手步骤3.1 安装编译依赖少装一个包后面都是泪回到实例上先升级索引并安装编译工具链和 Python 运行时依赖sudo dnf update -y sudo dnf groupinstall -y Development Tools sudo dnf install -y openssl-devel bzip2-devel libffi-devel zlib-devel readline-devel sqlite-devel xz-devel wget tarDevelopment Tools这个组包覆盖了 gcc、gcc-c、make 等核心工具不用单独一个个装。重点说几个容易漏的包openssl-devel如果不装编译出来的 Python 大概率没有_ssl模块pip 在 HTTPS 场景下直接废掉libffi-devel缺少它会导致_ctypes构建失败而ctypes又是很多底层库比如cryptography依赖的东西zlib-devel缺少它会在make install阶段因为 zipimport 失败而中断安装readline-devel和sqlite-devel分别是交互式命令行和sqlite3模块的基础。这几项几乎是 Python 源码编译的标准前置条件在 AL2023 上尤其要一次装齐否则后续排查会非常痛苦。3.2 下载源码并解压到指定目录我习惯把源码放在/usr/src下避免放在家目录里不小心被清理掉cd /usr/src sudo wget https://www.python.org/ftp/python/3.12.4/Python-3.12.4.tgz sudo tar -xzf Python-3.12.4.tgz cd Python-3.12.4需要注意版本号。3.12.x 是一个持续迭代的系列你去的时候可能已经有更新的补丁版本比如 3.12.5、3.12.6。优先用 python.org 的 FTP 目录 里最新的 3.12.x因为 patch 版本往往包含安全和兼容性修复。3.3 configure 参数里藏着哪些门道这是整个编译过程里最需要认真对待的一步。我使用的参数如下sudo ./configure --prefix/usr/local/python3.12 --enable-optimizations --with-ensurepipinstall逐个拆开解释--prefix/usr/local/python3.12指定安装目录。把 Python 隔离到独立目录这样卸载时直接删掉这个目录就干净了也不会污染/usr/local/bin。--enable-optimizations开启性能优化效果相当于用当前机器上已有的编译器做一次 Profile Guided Optimization。代价是编译时间变长但对 Python 这种解释型语言运行时性能提升是实打实的。--with-ensurepipinstall安装结束后自动拉取并安装 pip。装完少一步手动引导 pip 的操作。另外还有一个参数值得留意如果你有特殊需求可以加但默认场景没必要--enable-shared共享库模式会让 Python 以.so动态库形式存在方便像 mod_wsgi 这类扩展调用但代价是多了LD_LIBRARY_PATH设置环境变量配置复杂度更高。本地跑脚本、普通服务部署用静态模式就够了不要为了灵活给自己找麻烦。3.4 make 和 install用 altinstall 保护系统 python3编译sudo make -j$(nproc)-j$(nproc)表示用机器的所有 CPU 核心并行编译。在 2C4G 的实例上大约 5~8 分钟在 4C8G 上能压到 3 分钟左右。编译过程中如果看到个别 warning 不用慌只要没中断都算正常。安装时有一个关键动作sudo make altinstall这里切记不要用make install要用altinstall。install会把二进制安装成python3直接覆盖掉/usr/bin/python3这个软链而/usr/bin/python3是系统包管理工具和很多服务的命根子。altinstall只会生成python3.12和python3.12-config不会碰python3从源头杜绝了把系统环境搞坏的可能性。进一步确认安装结果sudo ls /usr/local/python3.12/bin/正常应该能看到python3.12和pip3.12。执行/usr/local/python3.12/bin/python3.12 --version能输出Python 3.12.4就是好的开始。3.5 顺手把 pip 升级到最新装完自带一个匹配的 pip建议立刻升级/usr/local/python3.12/bin/python3.12 -m pip install --upgrade pip这一步看起来多余但自带的ensurepip通常内置了一个略旧的 pip升级能避免后续安装包时因为旧版 pip 导致依赖解析异常。4. 环境变量配置让 python3.12 在任意目录下都认你4.1 为什么编译完还是要配环境变量你可能会疑惑/usr/local/python3.12/bin都已经有二进制文件了直接输全路径也能调用何必再配 PATH原因有两个第一日常使用不可能每次都敲全路径。把所有标志性目录加进 PATH 后在任意工作目录直接输python3.12和pip3.12就能调用这是命令行体验的基础。第二不少自动化工具比如 cron 定时任务、systemd 服务脚本、IDE 的远程解释器在非交互 shell 环境下加载的是系统级环境变量而不是你手动敲source ~/.bashrc后的那些。如果不把这套配置写到全局生效的文件里定时任务里就会出现找不到 python3.12的诡异现象。4.2 全局配置 vs 用户配置写在 /etc/profile.d 更省心环境变量配置有两种常见位置用户级写在~/.bashrc或~/.bash_profile只对当前用户生效系统级写在/etc/profile.d/xxx.sh所有用户、所有登录会话都生效。我强烈推荐写在/etc/profile.d/下因为服务器上通常需要这个 Python 环境的不止一个服务账号。如果你把它写进root的~/.bashrc后面切换到普通用户或者用sudo -u跑任务又得排查一遍。创建配置文件sudo tee /etc/profile.d/python312.sh EOF export PYTHON_HOME/usr/local/python3.12 export PATH$PYTHON_HOME/bin:$PATH EOF然后让当前会话立即生效source /etc/profile.d/python312.sh验证which python3.12 echo $PATHwhich python3.12应该返回/usr/local/python3.12/bin/python3.12。4.3 用软链做一个急救入口如果不想让 PATH 里塞太多目录也可以选择在/usr/local/bin下建软链因为/usr/local/bin默认就在 PATH 里sudo ln -s /usr/local/python3.12/bin/python3.12 /usr/local/bin/python3.12 sudo ln -s /usr/local/python3.12/bin/pip3.12 /usr/local/bin/pip3.12这样一来不配置环境变量也能直接输python3.12。但软链方式不适合管理多个 Python 版本切换版本时需要把软链指来指去容易混乱。所以我的建议是主要版本用 PATH 方式临时备用的版本才用软链入口。4.4 用 alternatives 管理多版本 Python 的优雅姿势如果你的机器上同时存在 3.9、3.11、3.12 多个版本想快速切换默认版本可以使用系统自带的update-alternatives机制它比手动改软链规范得多。注册 Python 3.12 到 alternativessudo update-alternatives --install /usr/local/bin/python3.12 python3.12 /usr/local/python3.12/bin/python3.12 100如果后续装了 3.12.5、3.12.6 等多个补丁版本可以通过sudo update-alternatives --config python3.12交互式切换优先级或者修改/etc/alternatives/python3.12软链的指向。但要提醒一点绝对不要通过 alternatives 把新的 python3.12 注册成系统的 python3更不要注册成 /usr/bin/python3。你真正能安全管理的目标是/usr/local/bin/python3.12这类非系统路径的入口系统的/usr/bin/python3永远不要动。4.5 环境变量生效的验证方法配置完之后要分两种 shell 验证别只在当前窗口验证一次第一重新登录一个新的 SSH 会话执行python3.12 --version command -v python3.12第二用一个非交互式环境验证env -i /bin/bash -c source /etc/profile.d/python312.sh; python3.12 --version这里之所以要单独验证非交互场景是因为 cron 和 systemd 的环境和普通登录 shell 不一样很多我明明配了环境变量但定时任务还是找不到命令的故障根源就在这里。5. 实测中一定会遇到的坑和解决办法5.1 configure 阶段提示无法找到 OpenSSL如果你在./configure时看到类似这样的报错checking for libssl... no Could not find the OpenSSL library, please install its dev package.基本原因就是没有装openssl-devel。在 AL2023 上安装sudo dnf install -y openssl-devel装完之后重新从./configure开始跑先删掉之前生成的Makefile和缓存sudo make distclean sudo ./configure ...这里特别提醒一次如果补齐依赖后直接make可能会出现一些难以解释的链接错误因为旧配置已经写了找不到 OpenSSL的结论。每次补完依赖必须make distclean后再 configure。这个习惯能省下大量排查时间。5.2 编译成功了但 pip 报No module named _ssl这是我见过最多的情况。明明编译过程没报错结果执行python3.12 -c import ssl提示ModuleNotFoundError: No module named _ssl或者 pip 在访问 HTTPS 源时卡住。原因很简单系统缺少 OpenSSL 开发头文件而 Python 在编译_ssl扩展模块时会实时检测。如果检测不到头文件它不会让整个编译失败而是静默跳过这个模块导致装出来的 Python 缺失 SSL 能力。要规避这个问题最稳的办法是在configure阶段就显式指定 OpenSSLsudo ./configure --prefix/usr/local/python3.12 --enable-optimizations --with-ensurepipinstall --with-openssl/usr--with-openssl/usr是明确告诉编译器去 /usr 下找 openssl 的头文件和库。AL2023 里 OpenSSL 的安装路径通常位于/usr/include/openssl和/usr/lib64配好之后也要等到安装完成再验证python3.12 -c import ssl; print(ssl.OPENSSL_VERSION)能输出 OpenSSL 版本号说明 SSL 模块是真的可用的。5.3 把系统 python3 强行替换的严重后果网上有些教程会教你sudo ln -sf /usr/local/python3.12/bin/python3.12 /usr/bin/python3这种操作在Amazon Linux 2023 上极其危险。系统里的dnf、cloud-init、rpm脚本、甚至aws命令行工具都依赖/usr/bin/python3。一旦把它换成 3.12轻则出现ModuleNotFoundError重则所有与包管理相关的命令全部瘫痪最后只能从快照回滚。正确思路是上面反复强调的altinstall加 PATH 环境变量让新版本和旧版本井水不犯河水。如果确实需要系统级python3命令指向 3.12必须经过充分测试且做好应急回滚方案在核心生产环境里不要拍脑袋做。5.4 虚拟环境用的不一定是你刚装的 Python如果后面你用python3.12 -m venv创建虚拟环境它默认会关联当前的解释器python3.12 -m venv myenv source myenv/bin/activate python --version这个没问题。但有一种情况容易踩坑系统其他脚本创建的 venv 很可能使用的是旧的系统 Python比如某个项目文件里写死了#!/usr/bin/env python3因为它寻找的是 PATH 里的python3而你没有修改/usr/bin/python3时它找到的仍然是 3.9。遇到这种情况要么在项目虚拟环境里明确指定解释器路径要么在 venv 之外用别名alias python/usr/local/python3.12/bin/python3.12或者更干净的做法直接编辑项目的虚拟环境配置文件myenv/pyvenv.cfg把home /usr/local/python3.12/bin指到新环境目录。改完重启 shell 就生效。5.5 权限设计普通用户如何调用新装的 Python源码编译需要sudo但安装完成之后没必要让每个应用用户都拥有写/usr/local/python3.12的权限。我习惯这样分配sudo chown -R root:root /usr/local/python3.12这样普通用户只拥有读和执行权限能运行 Python 但不能往系统目录里随意装包。需要装包时要么用sudo要么使用虚拟环境。这能防止团队成员误操作污染全局 Python 环境尤其是多人共用的开发服务器。最后分享一点我的实际体会这套流程我在多台 AL2023 实例上跑过从第一次踩了_ssl的坑到现在整条链路闭着眼都能装完最大的经验就三个一是编译依赖一次装齐不要挤牙膏式地缺啥补啥二是永远用altinstall保护系统 Python三是环境变量放到/etc/profile.d/全局配置并且要用非交互 shell 验证。把这个思路迁移到 Ubuntu、Rocky Linux 上也完全成立只是包管理器的命令从dnf换成了apt或yum。希望这篇能帮你少绕几圈在 Amazon Linux 2023 上顺利用上 Python 3.12。