我有一个Python项目,其中包含几个模块、类和依赖文件(一个requirements.txt
文件(。我想把它打包成一个包含所有依赖项的文件,并将文件路径提供给AWS EMR serverless,后者将运行它
问题是,我不明白如何将Python项目与所有依赖项打包,EMR可以使用哪个文件,等等。我发现的所有示例都使用了一个Python文件。
简单地说,如果我的Python项目不是单个文件,而是更复杂的文件,我该怎么办?
使用EMR Serverless有几种方法可以做到这一点。无论选择哪种方式,都需要为EMR Serverless StartJobRun命令提供一个主入口点Python脚本。
假设您有这样的作业结构,其中main.py
是创建Spark会话并运行作业的入口点,job1
和job2
是本地模块。
├── jobs
│ └── job1.py
│ └── job2.py
├── main.py
├── requirements.txt
选项1。将--py-files
与压缩的本地模块一起使用,将--archives
与用于外部依赖项的打包虚拟环境一起使用
- 压缩你的工作文件
zip -r job_files.zip jobs
- 使用具有依赖项的
venv-pack
创建一个虚拟环境
注意:这必须使用与EMR Serverless类似的操作系统和Python版本来完成,所以我更喜欢使用具有自定义输出的多级Dockerfile。
FROM --platform=linux/amd64 amazonlinux:2 AS base
RUN yum install -y python3
ENV VIRTUAL_ENV=/opt/venv
RUN python3 -m venv $VIRTUAL_ENV
ENV PATH="$VIRTUAL_ENV/bin:$PATH"
COPY requirements.txt .
RUN python3 -m pip install --upgrade pip &&
python3 -m pip install venv-pack==0.2.0 &&
python3 -m pip install -r requirements.txt
RUN mkdir /output && venv-pack -o /output/pyspark_deps.tar.gz
FROM scratch AS export
COPY --from=base /output/pyspark_deps.tar.gz /
如果运行DOCKER_BUILDKIT=1 docker build --output . .
,那么现在本地系统上应该有一个pyspark_deps.tar.gz
文件。
将
main.py
、job_files.zip
和pyspark_deps.tar.gz
上载到S3上的某个位置。使用以下命令运行EMR无服务器作业(替换
APPLICATION_ID
、JOB_ROLE_ARN
和YOUR_BUCKET
(:
aws emr-serverless start-job-run
--application-id $APPLICATION_ID
--execution-role-arn $JOB_ROLE_ARN
--job-driver '{
"sparkSubmit": {
"entryPoint": "s3://<YOUR_BUCKET>/main.py",
"sparkSubmitParameters": "--py-files s3://<YOUR_BUCKET>/job_files.zip --conf spark.archives=s3://<YOUR_BUCKET>/pyspark_deps.tar.gz#environment --conf spark.emr-serverless.driverEnv.PYSPARK_DRIVER_PYTHON=./environment/bin/python --conf spark.emr-serverless.driverEnv.PYSPARK_PYTHON=./environment/bin/python --conf spark.executorEnv.PYSPARK_PYTHON=./environment/bin/python"
}
}'
选项2。将本地模块打包为Python库,并在打包的虚拟环境中使用--archives
这可能是最可靠的方法,但需要使用setuptools。您可以将一个简单的pyproject.toml
文件与现有的requirements.txt
一起使用
[project]
name = "mysparkjobs"
version = "0.0.1"
dynamic = ["dependencies"]
[tool.setuptools.dynamic]
dependencies = {file = ["requirements.txt"]}
然后,您可以使用多阶段Dockerfile和自定义构建输出将模块和依赖项打包到虚拟环境中。
注意:这需要启用Docker Buildkit
FROM --platform=linux/amd64 amazonlinux:2 AS base
RUN yum install -y python3
ENV VIRTUAL_ENV=/opt/venv
RUN python3 -m venv $VIRTUAL_ENV
ENV PATH="$VIRTUAL_ENV/bin:$PATH"
WORKDIR /app
COPY . .
RUN python3 -m pip install --upgrade pip &&
python3 -m pip install venv-pack==0.2.0 &&
python3 -m pip install .
RUN mkdir /output && venv-pack -o /output/pyspark_deps.tar.gz
FROM scratch AS export
COPY --from=base /output/pyspark_deps.tar.gz /
现在您可以运行DOCKER_BUILDKIT=1 docker build --output . .
,并且会生成一个包含所有依赖项的pyspark_deps.tar.gz
文件。将此文件和main.py
脚本上载到S3。
假设您将两个文件都上载到了s3://<YOUR_BUCKET>/code/pyspark/myjob/
,则运行EMR Serverless作业,如下所示(替换APPLICATION_ID
、JOB_ROLE_ARN
和YOUR_BUCKET
:
aws emr-serverless start-job-run
--application-id <APPLICATION_ID>
--execution-role-arn <JOB_ROLE_ARN>
--job-driver '{
"sparkSubmit": {
"entryPoint": "s3://<YOUR_BUCKET>/code/pyspark/myjob/main.py",
"sparkSubmitParameters": "--conf spark.archives=s3://<YOUR_BUCKET>/code/pyspark/myjob/pyspark_deps.tar.gz#environment --conf spark.emr-serverless.driverEnv.PYSPARK_DRIVER_PYTHON=./environment/bin/python --conf spark.emr-serverless.driverEnv.PYSPARK_PYTHON=./environment/bin/python --conf spark.executorEnv.PYSPARK_PYTHON=./environment/bin/python"
}
}'
请注意额外的sparkSubmitParameters
,它指定了您的依赖项,并为python
的正确路径配置了驱动程序和执行程序环境变量。