- 消息队列
- 流处理
- 后端
- 微服务
- 消息路由
【免费下载链接】pulsar
Apache Pulsar - distributed pub-sub messaging system
PIP-56(Python3 Migration)是 Apache Pulsar 社区提出的将默认 Python 运行时从 2.7 迁移到 3.7 的改进提案。本文以该提案为核心,结合当前仓库中 docker/pulsar/Dockerfile、docker/pulsar/Dockerfile.wolfi 以及 Pulsar Functions Python 运行时源码,讲解迁移的背景、影响面、落地改动与验证方法,帮助你理解 Pulsar 镜像中 Python 运行时的演进逻辑,并掌握自定义 Python 版本镜像的构建思路。
PIP-56 提案背景:Python 2.7 的 End of Life
Python 2.7 于 2020 年 1 月 1 日正式停止官方维护(End of Life)。而在此之前的较长一段时间里,Apache Pulsar 存在两个与 Python 2 深度绑定的现实:
- PyPI 上发布的 Python 客户端制品仍是 Python 2.x 兼容的构件,社区持续在 pypi 上分发 python 2 的 wheel 包;
- Pulsar 官方镜像中 Python 2.7 是默认运行时,这直接影响两类用户:
- 依赖 Python 客户端的安装场景;
- 使用 Python 编写 Pulsar Functions、并直接运行在官方镜像上的函数用户。
PIP-56 正是针对这一现状提出的系统性迁移提案,其核心主张包含三点:
- 将 Pulsar 镜像中的默认 Python 版本从 python27 升级到 python37;
- 将集成测试(integration test)迁移到 python37 运行时上执行;
- 公告 Python 3.7 的弃用节奏,同时承诺在 2020 年底前继续支持 python27 制品。
影响分析:谁会被这次默认运行时变更波及
提案明确指出,变更默认 Python 安装会给两类群体带来直接冲击:
- 使用 Python 客户端的安装场景:如果默认 Python 解释器从 2 变为 3,依赖旧解释器行为或旧版本依赖树的部署会受到破坏,且不存在简单的自动迁移路径;
- 运行 Python Functions 的用户:官方镜像内预置的 Python 运行时一旦切换,函数运行环境随之变化,需要用户重新验证函数代码的 Python 3 兼容性。
与此同时,迁移带来的一个必然结果是:python27 的测试覆盖会逐步缩减,因为默认集成测试将显式针对 python37 运行。提案给出的缓解策略是:
- 通过**明确的发布说明(release notes)**通知受影响用户;
- 提供构建自定义镜像、以 python27 为默认解释器的操作指引;
- 在当年年底之前继续发布 python27 制品,为存量用户留出过渡窗口。
需要落地的改动清单
PIP-56 将改动范围圈定在少量 docker 与 pom 文件中,具体包括:
- 移除 Python 2 的安装步骤:删除 Pulsar 镜像 Dockerfile 中 python2 的安装行,以及 dashboard 镜像 Dockerfile 中的对应安装逻辑;
- 添加符号链接:建立
python3 -> python、pip3 -> pip的 symlink,使既有脚本和用户在无感知的情况下使用 Python 3; - 移除 Python 27 wheel 的安装:不再在镜像中安装面向 python27 的客户端 wheel。
需要说明:提案引用的 Dockerfile 行号对应的是提案撰写时的历史版本。当前仓库中的镜像定义已经历多轮演进(Alpine 基础镜像、Wolfi 基础镜像、JDK 25/21、mimalloc 预加载等),但"Python 3 为唯一默认运行时"这一结论已在 docker/pulsar/Dockerfile 与 docker/pulsar/Dockerfile.wolfi 中得到充分落实。
迁移后的镜像现状:源码级验证
Alpine 版镜像:python3 + py3-pip
当前 docker/pulsar/Dockerfile 的基础镜像阶段(FROM alpine:$ALPINE_VERSION)通过apk add安装的 Python 相关包已经完全 Python 3 化:
RUN apk add --no-cache \ bash \ python3 \ py3-pip \ py3-yaml \ gcompat \ libgcc \ libstdc++ \ libuuid \ ca-certificates \ procps \ curl \ bind-tools \ openssl \ coreutils其中python3、py3-pip、py3-yaml分别是 Python 3 解释器、pip 与 PyYAML 的 Alpine 包。py3-yaml对 Pulsar Functions 尤其重要——Functions 运行时通过 YAML 解析函数配置(对应 conf/functions_worker.yml 等配置文件的使用场景)。
随后,镜像内通过pip3安装一组与 Pulsar Functions Python 运行时严格绑定版本的依赖(docker/pulsar/Dockerfile):
ARG PULSAR_CLIENT_PYTHON_VERSION RUN pip3 install --break-system-packages --no-cache-dir \ --only-binary \ grpcio==1.78.0 \ protobuf==6.33.6 \ pulsar-client[all]==${PULSAR_CLIENT_PYTHON_VERSION} \ kazoogrpcio与protobuf的版本被显式固定,且与仓库内_pb2.py生成的 stubs 保持兼容(详见下文"stubs 生成"小节);pulsar-client[all]==${PULSAR_CLIENT_PYTHON_VERSION}是 Python 客户端全量依赖安装,版本由构建参数注入,构建时可通过--build-arg PULSAR_CLIENT_PYTHON_VERSION=...覆盖;kazoo用于 ZooKeeper 交互,支撑 Functions 运行时的协调逻辑。
Wolfi 版镜像:可参数化的 Python 版本
docker/pulsar/Dockerfile.wolfi 以 Chainguard Wolfi 为基础镜像,Python 版本通过构建参数显式声明(默认 3.12),迁移思路一脉相承:
ARG PYTHON_VERSION=3.12 RUN apk add --no-cache \ bash \ python-${PYTHON_VERSION} \ py${PYTHON_VERSION}-pip \ ...依赖安装同样使用pip3,并额外补充了pyyaml(docker/pulsar/Dockerfile.wolfi)。可以看到,PIP-56 提出的"python3 为默认、pip3 为默认包管理器"在两条镜像链路上都已固化为事实标准。
构建自定义镜像:如何让 python27 成为默认
对于仍需 Python 2 的存量用户,PIP-56 给出的方向是"构建自定义镜像"。基于当前 Dockerfile 的结构,可采取以下做法(仅作操作说明,仓库本身不提供 python2 支持):
- fork 或复制docker/pulsar/Dockerfile 到自己仓库;
- 将
apk add中的python3替换为python2(Alpine 老版本仓库)或改用 Ubuntu/Debian 基础镜像中的python2.7; - 将
py3-pip、py3-yaml替换为对应的 Python 2 版本,并把pip3 install改为pip install; - 移除或替换
grpcio==1.78.0、protobuf==6.33.6等仅支持 Python 3 的新版本依赖,回退到兼容 Python 2 的历史版本(如 grpcio 1.24.x、protobuf 3.x 早期版本)。
需要注意:当前仓库的 Functions Python 运行时源码(见下文)对 Python 2 仅保留了有限兼容逻辑,且 grpcio/protobuf 已推进到 Python 3-only 的版本线,因此自定义 python2 镜像需要同步回退这些依赖才能实际运行。
运行时源码中的 Python 3 迁移痕迹
PIP-56 的迁移不仅体现在 Dockerfile,Pulsar Functions 的 Python 运行时源码同样记录了从 2 到 3 的兼容与演进过程,集中在 pulsar-functions/instance/src/main/python 目录:
入口脚本显式声明 python3
pulsar-functions/instance/src/main/python/python_instance_main.py 的 shebang 为:
#!/usr/bin/env python3这是运行时"强制 Python 3"最直接的证据——无论 PATH 中的python指向哪个版本,函数实例进程都会用python3解释器启动。
运行时内的 Py2/Py3 兼容分支
pulsar-functions/instance/src/main/python/python_instance.py 定义了版本判定常量,并在多处使用条件分支:
PY3 = sys.version_info[0] >= 3例如base64ify()中根据PY3决定字符串是否需要先encode('utf8')再 base64(python_instance.py);模块导入处也保留了try: import Queue as queue / except: import queue的双版本兼容写法(python_instance.py)。
类似的兼容代码还出现在:
- function_stats.py:
int(...) if sys.version_info.major >= 3 else long(...),处理 Python 2 独有的long类型; - python_instance.py:指标与状态上报时的
int/long转换分支; - python_instance.py:自定义 Schema 反射时
inspect.signature与inspect.getargspec的双版本回退(# for compatibility with python 2注释)。
从源码结构看,这些分支是迁移过渡期留下的"兼容层":功能上以 Python 3 为主路径,Python 2 仅保留最低限度的可用性——与 PIP-56"python27 测试覆盖缩减、年底停止制品发布"的路线完全一致。
依赖锁定与 stubs 再生成机制
Python 运行时依赖的 Protobuf/gRPC stubs 由仓库内的脚本生成,与镜像中固定的grpcio/protobuf版本严格对应。相关说明见 pulsar-functions/instance/src/main/python/README.md:
- 若升级镜像中的
grpcio/protobuf,必须同步更新 src/update_python_protobuf_stubs.sh 中的PYTHON_GRPCIO_VERSION(当前默认1.78.0,见该脚本第 23 行),并重新生成 stubs; - 在项目根目录执行
src/update_python_protobuf_stubs.sh(或容器化的src/update_python_protobuf_stubs_with_docker.sh)即可重新生成Function_pb2.py、InstanceCommunication_pb2.py、InstanceCommunication_pb2_grpc.py等文件; - 脚本会创建临时 venv 以避免污染全局环境,并使用
grpc_tools.protoc从 pulsar-functions/proto/src/main/proto 下的.proto文件生成代码,同时删除生成文件中的严格版本校验代码,以允许跨版本运行。
迁移的验证路径:集成测试与运行时测试
PIP-56 的第二项主张是"集成测试迁移到 python37"。当前仓库中与 Python Functions 相关的测试可从两个层面验证 Python 3 运行时:
- 运行时单元测试:
pulsar-function-go与 Python 运行时各有独立测试(如 pulsar-functions/instance 下的 Python 脚本,以及pf/目录中*_test.go对应的 Go 运行时测试),它们共同覆盖函数实例的启动、消息处理与指标上报; - 集成测试链路:
tests/integration目录下的 Java 集成测试(如 tests/integration/src 中的 Pulsar Functions 相关用例)负责在真实集群中验证函数端到端行为,默认即运行在带 Python 3 的官方镜像之上。
对于希望本地复现"镜像内 Python 3 可用性"的读者,可执行:
# 构建镜像(在仓库根目录,需先完成完整构建以产出 tarball) ./gradlew -Pdocker -PskipTests -DdockerPull=true docker:docker # 或直接进入镜像验证运行时 docker run --rm -it apachepulsar/pulsar:latest python3 --version docker run --rm -it apachepulsar/pulsar:latest pip3 --version提示:
PULSAR_CLIENT_PYTHON_VERSION与PYTHON_VERSION(仅 Wolfi 镜像)均为可覆盖的构建参数,自定义镜像时可利用--build-arg调整客户端版本。
小结:PIP-56 的落地与演进
PIP-56 以"Python 2.7 停止维护"为背景,提出了默认运行时从 python27 到 python37 的三步迁移方案。回看当前仓库,该提案的目标已全面达成并继续演进:
- 官方镜像(Alpine 与 Wolfi 两条链路)只安装 Python 3,
python3/pip3成为默认命令; - Functions Python 运行时入口使用
python3shebang,源码中的 Py2 兼容分支仅作为历史兼容层保留; - grpcio/protobuf 与生成的 stubs 通过
PYTHON_GRPCIO_VERSION脚本化联动,保证运行时依赖与生成代码的版本一致性; - Python 版本进一步演进(Wolfi 镜像默认 3.12),客户端版本持续跟随社区发布节奏。
对于依旧依赖 Python 2 的存量部署,唯一的合规路径是参考 docker/pulsar/Dockerfile 自行构建自定义镜像并回退依赖版本,同时关注发布说明中的兼容性公告——这正是 PIP-56 当年为社区规划好的过渡方式。
- 消息队列
- 流处理
- 后端
- 微服务
- 消息路由
【免费下载链接】pulsar
Apache Pulsar - distributed pub-sub messaging system
相关推荐
PIP-324 深度解析:Apache Pulsar Docker 镜像迁移至 Alpine Linux 基础镜像
PIP 324 深度解析:Apache Pulsar Docker 镜像迁移至 Alpine Linux 基础镜像 Apache Pulsar 官方 Docke
消息队列后端终极指南:Apache Pulsar集群零停机升级与数据迁移实战
终极指南:Apache Pulsar集群零停机升级与数据迁移实战 Apache Pulsar作为云原生消息队列和流处理平台,其集群的平滑升级与数据迁移是保障业务
消息队列流处理后端微服务消息路由Salt 3007.x onedir 运行时升级:Python 3.10 迁移至 3.11 的完整运维指南
Salt 3007.x onedir 运行时升级:Python 3.10 迁移至 3.11 的完整运维指南 导读 本文基于 Salt 仓库 changelog
运维配置管理后端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考