# !/usr/bin/env bash
# helper script to fulfil Spark's python packaging requirements.
# Installs everything in a designated virtualenv, then zips up the virtualenv for using as an the value of
# supplied to --py-files argument of `pyspark` or `spark-submit`
# First argument should be the top-level virtualenv
# Second argument is the zipfile which will be created, and
# which you can subsequently supply as the --py-files argument to
# spark-submit
# Subsequent arguments are all the private packages you wish to install
# If these are set up with setuptools, their dependencies will be installed
VENV=$1; shift
ZIPFILE=$1; shift
PACKAGES=$*
. $VENV/bin/activate
for pkg in $PACKAGES; do
pip install --upgrade $pkg
done
TMPZIP="$TMPDIR/$RANDOM.zip" # abs path. Use random number to avoid clashes with other processes
( cd "$VENV/lib/python2.7/site-packages" && zip -q -r $TMPZIP . )
mv $TMPZIP $ZIPFILE
1条答案
按热度按时间exdqitrt1#
实际上,我已经试过了,我认为我作为评论发布的链接并不能完全满足您对依赖项的要求。您所要求的是一种让spark在安装依赖项时很好地使用setuptools和pip的方法。在spark中没有更好的支持这一点让我大吃一惊。第三方依赖性问题在通用python中得到了很大程度的解决,但是在spark中,似乎假设您将回到手动依赖性管理之类的方式。
我一直在使用一个不完善但功能强大的基于virtualenv的管道。基本思想是
为你的spark节点创建一个virtualenv
每次你运行一个Spark作业,运行一个新的
pip install
所有的内部python库。如果你已经用setuptools
,这将安装它们的依赖项压缩virtualenv的站点包目录。这将包括工作节点需要的库及其依赖项,但不包括它们已经拥有的标准python库
传单曲
.zip
文件,包含库及其依赖项作为--py-files
当然,您需要编写一些助手脚本来管理这个过程。下面是一个助手脚本,它改编自我一直在使用的脚本,无疑可以改进很多:我有一个其他简单的 Package 器脚本的集合,我运行这些脚本来提交我的spark作业。我只是在该过程中首先调用这个脚本,并确保在运行时将第二个参数(zip文件的名称)作为--py files参数传递
spark-submit
(如评论中所述)。我总是运行这些脚本,所以我从不意外地运行旧代码。与spark开销相比,对于我的小规模项目来说,打包开销是最小的。我们可以做很多改进,例如,在何时创建一个新的zip文件方面非常聪明,将它分成两个zip文件,一个包含经常更改的私有包,另一个包含很少更改的依赖项,这些依赖项不需要经常重建。在重建zip之前,您可以更聪明地检查文件更改。同时检查论点的有效性也是一个好主意。不过,就我的目的而言,这已经足够了。
我提出的解决方案并不是专门为大规模依赖项(比如numpy)设计的(尽管它可能对它们有用)。另外,如果您正在构建基于c的扩展,并且您的驱动程序节点与集群节点具有不同的体系结构,那么它将不起作用。
我在其他地方看到过一些建议,建议在所有节点上运行像anaconda这样的python发行版,因为它已经包含了numpy(和许多其他包),这可能是让numpy以及其他基于c的扩展运行起来的更好方法。无论如何,我们不能总是期望anaconda拥有我们想要的pypi包的正确版本,此外,您可能无法控制spark环境以将anaconda放在其上,因此我认为这种基于virtualenv的方法仍然是有用的。