本文介紹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 ## 其餘情況類似,不再贅述...