本文介绍PySpark Package依赖的多种打包方式。
功能简介
通常情况下,PySpark作业依赖两类Python资源:第三方库(如其他Python库、插件或项目)以及用户自定义模块。由于MaxCompute集群无法自由安装Python库,需在本地打包后通过spark-submit上传。
管理第三方库:对于特定依赖,打包环境需跟线上环境保持一致。提供了以下多种打包方式:
无需上传额外资源,但是只能使用默认提供的Python环境。
适用于需要的额外Python依赖数量较少、较为简单的情况。
基于Docker提供若干版本的Python环境,结合用户提供的requirements文件,利用脚本一键生成完整Python包。
任意选择Python版本,Docker容器只提供了Linux环境,最终需要把Python环境上传至MaxCompute资源中。
管理用户自定义模块:即引用用户自定义的python包。将包含所有自定义模块的文件夹(例如,一个包含
__init__.py的Python包)打包成一个.zip文件,避免逐个上传和引用的繁琐步骤。
方案一:不打包直接使用公共资源
在spark-defaults.conf或DataWorks配置中修改配置项,如下分别为不同版本Python默认提供的环境配置。
Python 2.7.13
默认提供的Python 2.7.13环境配置,点击查看第三方库列表。
spark.hadoop.odps.cupid.resources = public.python-2.7.13-ucs4.tar.gz
spark.pyspark.python = ./public.python-2.7.13-ucs4.tar.gz/python-2.7.13-ucs4/bin/pythonPython 3.6.12
默认提供的Python 3.6.12环境配置。
spark.hadoop.odps.cupid.resources = public.python-3.6.12.tar.gz
spark.pyspark.python = ./public.python-3.6.12.tar.gz/python-3.6.12/bin/python3Python 3.7.9
默认提供的Python 3.7.9环境配置,点击查看第三方库列表。
spark.hadoop.odps.cupid.resources = public.python-3.7.9-ucs4.tar.gz
spark.pyspark.python = ./public.python-3.7.9-ucs4.tar.gz/python-3.7.9-ucs4/bin/python3Python3.11
spark.hadoop.odps.spark.alinux3.enabled = true方案二:上传单个wheel包
如果依赖较为简单,则可以只上传单个wheel包,通常需要选用manylinux版本,点击下载wheel包。
将wheel包重命名为zip包,例如将下载下来的pymysql的wheel包重命名为
pymysql.zip。登录DataWorks控制台,在左上角选择地域。
选择工作空间,单击进入Data Studio。
在左侧导航栏单击
图标,然后单击
新建MaxCompute Archive资源。上传打包好的pymysql.zip。在DataWorks Spark节点应用。
在
spark-defaults.conf配置文件或DataWorks配置项中添加以下配置:spark.executorEnv.PYTHONPATH=pymysql spark.yarn.appMasterEnv.PYTHONPATH=pymysql代码中导入包
import pymysql。
方案三:利用pyodps-pack快捷打包
若需要打包大量Python第三方库且对Python版本的依赖度较小时,推荐使用 pyodps-pack 工具。该工具依赖Docker提供打包环境,并支持通过 requirements.txt 文件批量处理依赖。以下将以打包 pandas 库(使用Python 3.11环境)为例,演示其具体用法。详细打包方式,参考制作和使用三方包-PyODPS 0.12.4。
Python版本限制:pyodps-pack 目前支持的Python版本范围为 3.8 至 3.14。
使用
pyodps-pack打包# 在开发环境执行 pip install pyodps # 此处使用的python版本建议和spark作业的python版本保持一致,若系统上没有Docker,需先安装并运行Docker。 pyodps-pack pandas --python-version=3.11 -o pyodps-pandas.tar.gz # 也可以使用 requirements.txt pyodps-pack -r requirements.txt --python-version=3.11 -o pyodps-pandas.tar.gz在odpscmd上传打包文件
add archive PATH/pyodps-pandas.tar.gz -f;设置作业启动配置
修改
spark-defaults.conf配置文件。spark.hadoop.odps.cupid.resources = {your_project}.pyodps-pandas.tar.gz spark.executorEnv.PYTHONPATH = ./{your_project}.pyodps-pandas.tar.gz/packages spark.yarn.appMasterEnv.PYTHONPATH = ./{your_project}.pyodps-pandas.tar.gz/packages # 如果使用 notebook 的用户打包请忽略以下内容 # 设置spark版本为3.4或3.5 spark.hadoop.odps.spark.version = spark-3.4.2-odps0.48.0 或 spark.hadoop.odps.spark.version = spark-3.5.2-odps0.48.0 # 使用该参数切换到python 3.11版本(可选,需要和pyodps-pack打包指定的python版本一致) spark.hadoop.odps.spark.alinux3.enabled = true
方案四:利用脚本一键生成Python环境
对于需要打包大量第三方库的场景,为避免方案二逐一上传wheel包重复且繁琐的操作,该方案提供了一个自动化打包脚本,只需准备一个requirements文件(文件格式请参考链接)即可通过脚本一键构建一个包含所有指定依赖的完整Python环境,可直接在PySpark作业中使用。目前仅支持Python 2.7、3.5、3.6和3.7版本,若对Python版本不敏感,当前推荐使用Python 3.7。
具体操作步骤如下:
下载自动化打包脚本。
脚本适用于Mac/Linux环境,需要预先安装Docker,见官方文档。
在命令行修改文件权限并查看使用方法:
$ chmod +x generate_env_pyspark.sh $ generate_env_pyspark.sh -h Usage: generate_env_pyspark.sh [-p] [-r] [-t] [-c] [-h] Description: -p ARG, the version of python, currently supports python 2.7, 3.5, 3.6 and 3.7 versions. -r ARG, the local path of your python requirements. -t ARG, the output directory of the gz compressed package. -c, clean mode, we will only package python according to your requirements, without other pre-provided dependencies. -h, display help of this script.-c选项表示是否开启clean mode,clean mode无法使用预装依赖,但输出的Python包更小。当前MaxCompute对上传资源的大小有500MB的限制,因此如果大部分预装依赖用不到,强烈推荐使用-c选项打包。点击链接查看不同Python版本的预装依赖:2.7预装依赖、3.5预装依赖、3.6预装依赖、3.7预装依赖。打包示例代码
# 带有预装依赖的打包方式 $ generate_env_pyspark.sh -p 3.7 -r your_path_to_requirements -t your_output_directory # 不带预装依赖的打包方式(clean mode) generate_env_pyspark.sh -p 3.7 -r your_path_to_requirements -t your_output_directory -c在Spark中使用
generate_env_pyspark.sh脚本的输出为在指定目录下(-t选项)生成指定Python版本(-p选项)的gz包。以Python3.7为例,将生成py37.tar.gz。后续再将此包上传为archive资源,以odpscmd执行为例,也可用odps-sdk上传,上传资源的各种方式参考资源操作。# 在odpscmd中执行 add archive /your/path/to/py37.tar.gz -f;然后在
spark-defaults.conf配置文件或DataWorks配置项中添加以下配置:spark.hadoop.odps.cupid.resources = your_project.py37.tar.gz spark.pyspark.python = your_project.py37.tar.gz/bin/python 若上述两个参数不生效,例如用于zeppelin调试pyspark时notebook中的python环境,还需在spark作业中增加以下两项配置: spark.yarn.appMasterEnv.PYTHONPATH = ./your_project.py37.tar.gz/bin/python spark.executorEnv.PYTHONPATH = ./your_project.py37.tar.gz/bin/python
方案五:利用docker容器打包Python环境
在满足以下任一条件时,推荐采用本方案打包:
依赖包含非Python代码:待打包的库包含
.so等二进制文件,导致无法通过简单的pip install或上传zip压缩包的方式分发。需要自定义Python版本:项目要求使用特定版本的Python环境(例如Python 3.8),而非平台默认提供的版本(如2.7、3.5、3.6、3.7)。
为此,提供了基于Docker的打包方案。以下将以构建Python 3.8环境为例,演示其操作步骤。
准备Dockerfile。
在已安装Docker的本地开发机上,创建一个名为
Dockerfile的文件。根据目标环境,从以下两个模板中选择一个。Python3.8 + alinux2
FROM alibaba-cloud-linux-2-registry.cn-hangzhou.cr.aliyuncs.com/alinux2/alinux2:latest RUN curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo RUN curl -o /etc/yum.repos.d/epel.repo https://mirrors.aliyun.com/repo/epel-7.repo RUN set -ex \ # 预安装所需组件 && yum clean all \ && yum makecache \ && yum install -y wget tar libffi-devel zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gcc make initscripts zip\ && wget https://www.python.org/ftp/python/3.8.20/Python-3.8.20.tgz \ && tar -zxvf Python-3.8.20.tgz \ && cd Python-3.8.20 \ && ./configure prefix=/usr/local/python3 \ && make \ && make install \ && make clean \ && rm -rf /Python-3.8.20* \ && yum install -y epel-release \ && yum install -y python-pip # 设置默认为python3 RUN set -ex \ # 备份旧版本python && mv /usr/bin/python /usr/bin/python27 \ && mv /usr/bin/pip /usr/bin/pip-python27 \ # 配置默认为python3 && ln -s /usr/local/python3/bin/python3.8 /usr/bin/python \ && ln -s /usr/local/python3/bin/pip3 /usr/bin/pip # 修复因修改python版本导致yum失效问题 RUN set -ex \ && sed -i "s#/usr/bin/python#/usr/bin/python27#" /usr/bin/yum \ && sed -i "s#/usr/bin/python#/usr/bin/python27#" /usr/libexec/urlgrabber-ext-down \ && yum install -y deltarpm # 更新pip版本 RUN pip install --upgrade pipPython3.7 + alinux3
FROM alibaba-cloud-linux-3-registry.cn-hangzhou.cr.aliyuncs.com/alinux3/alinux3:latest RUN set -ex \ && yum clean all \ && yum makecache \ && yum install -y \ wget \ tar \ libffi-devel \ zlib-devel \ bzip2-devel \ openssl-devel \ ncurses-devel \ sqlite-devel \ readline-devel \ tk-devel \ xz-devel \ gcc \ make \ initscripts \ zip \ which RUN set -ex \ && wget https://www.python.org/ftp/python/3.7.17/Python-3.7.17.tgz \ && tar -zxvf Python-3.7.17.tgz \ && rm -f Python-3.7.17.tgz \ && cd Python-3.7.17 \ && ./configure --prefix=/usr/local/python3 \ --enable-optimizations \ && make -j$(nproc) \ && make install \ && make clean \ && cd / \ && rm -rf Python-3.7.17 \ && yum clean all RUN ln -sf /usr/local/python3/bin/python3.7 /usr/bin/python \ && ln -sf /usr/local/python3/bin/pip3 /usr/bin/pip # 升级pip RUN pip install --no-cache-dir --upgrade pip构建镜像并运行容器
在Dockerfile文件的目录下运行如下命令:
# 1. 构建Docker镜像 (以Python 3.8为例) # -t 给镜像命名,格式为 <image_name>:<tag> docker build --platform linux/amd64 -t python-centos:3.8 . # 2. 启动一个后台运行的容器 # --name 给容器命名,便于后续操作 docker run --platform linux/amd64 -itd --name python3.8 python-centos:3.8 bash进入容器安装所需的Python依赖库
docker attach python3.8 pip install [所需依赖库]打包Python环境
cd /usr/local/ zip -r python3.8.zip python3/拷贝容器中的Python环境到宿主机
ctrl+P+Q退出容器 docker cp python3.8:/usr/local/python3.8.zip .上传Python3.8.zip包到MaxCompute资源
可以通过本地客户端(odpscmd)上传,上传类型为archive,详细命令参考资源操作。
add archive /path/to/python3.8.zip -f;修改
spark-defaults.conf或DataWorks配置项提交Spark作业时在
spark-defaults.conf配置文件或DataWorks配置项中添加如下配置:spark.hadoop.odps.cupid.resources=[project名].python3.8.zip spark.pyspark.python=./[project名].python3.8.zip/python3/bin/python3.8
如果遇到so包找不到的情况,则需要手动将so包放到Python环境中,并在Spark配置中添加以下环境变量(一般so包都能在容器中找到):
spark.executorEnv.LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./[project名].python3.8.zip/python3/[创建的so包目录]
spark.yarn.appMasterEnv.LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./[project名].python3.8.zip/python3/[创建的so包目录]引用用户自定义的python包
生成压缩包
在目录下创建一个空白的
__init__.py,生成一个zip压缩包。cd /path/to/parent_dir touch __init__.py zip -r target_dir.zip target_dir/ 注意:使用相对路径压缩,不要将父目录打入zip包,target_dir.zip解压后不包含parent_dir路径上传zip压缩包
方式一:使用DataWorks上传为archive类型资源
方式二:使用odpscmd上传为archive类型资源
add archive /path/to/python3.8.zip -f;
任务引用zip包
方式一:在DataWorks任务节点archive资源中引入zip压缩包
方式二:修改
spark-defaults.conf配置文件。通过spark.hadoop.odps.cupid.resources参数引用zip包,并重命名。参数示例: spark.hadoop.odps.cupid.resources=[替换project].target_dir.zip:target_dr 多个资源用逗号隔开。
任务配置参数
修改
spark-defaults.conf配置文件任务配置参数并引入 Python 包,如果对文件位置有疑惑请参考数据互通配置,务必清楚上传的包内部目录结构。以下的
./就表示当前工作目录/workdir/,填写合理的PYTHONPATH环境变量和对应的import路径。## 1. 第一种情况:假设当前 target_dir.zip 的子目录结构为 target_dir.zip/sub/target_module spark.executorEnv.PYTHONPATH=./target_dir spark.yarn.appMasterEnv.PYTHONPATH=./target_dir # 引入 Python 包 from sub import target_module.xxx ## 2. 第二种情况:假设当前 target_dir.zip 的子目录结构为 target_dir.zip/target_module spark.executorEnv.PYTHONPATH=./ spark.yarn.appMasterEnv.PYTHONPATH=./ # 引入 Python 包 from target_module import xxx ## 其余情况类似,不再赘述...