Amazon EMR 无服务器¶
Amazon EMR Serverless 可用于通过Apache Spark管理和执行分布式计算工作负载。其无服务器架构无需预置或管理集群即可执行Spark作业。相反,EMR Serverless 会为每个作业独立分配所需资源,并在完成后释放它们。
EMR Serverless通常用于完全或部分依赖PySpark的管道流程。对于管道的其他部分,例如建模环节,若采用非分布式计算方法更为合适,则可能无需使用EMR Serverless。
上下文¶
在Amazon Elastic MapReduce (EMR)上运行的Python应用程序传统上使用bootstrap actions来管理依赖项。由于脚本复杂性、较长的引导时间以及集群实例间可能存在的不一致性,这有时会导致问题。
某些应用可能需要采用不同的方法,例如:
自定义Python版本: 默认情况下,最新的EMR版本(6.10.0、6.11.0)运行Python 3.7,但某些应用可能需要Python 3.9或更高版本。
Python依赖项: 某些应用程序需要使用一系列第三方依赖项,这些依赖项需要同时安装在驱动节点和工作节点上。
尽管AWS官方文档提供了配置自定义Python版本和使用自定义依赖项的方法,但仍存在一些限制。这些方法容易出错,难以调试,且不能确保完全兼容性(更多详情请参阅下方FAQ部分)。
EMR Serverless 从 Amazon EMR 6.9.0 开始提供解决上述限制的方案,该版本支持自定义镜像。通过自定义 Docker 镜像,您可以将特定 Python 版本与所有必需的依赖项打包到一个不可变的容器中。这确保了整个设置中运行时环境的一致性,并实现了对运行时环境的控制。
这种方法有助于避免因配置错误或与系统级软件包潜在冲突导致的作业失败,并确保软件包的可移植性,以便在本地进行调试和测试(查看更多验证详情)。采用该方法可以提供可重复、可靠的环境,并提高操作灵活性。
在建立这个上下文后,本页的其余部分将介绍如何将Kedro项目部署到EMR Serverless。
方法概述¶
该方法为EMR Serverless创建了一个自定义Docker镜像,用于打包依赖项并管理运行时环境,步骤如下:
将Kedro项目打包以便在所有EMR Serverless工作节点上安装。可以使用
kedro package命令:生成的.whl文件用于安装,而conf.tar.gz包含项目配置文件。使用自定义的Python版本而非EMR Serverless上默认安装的Python。示例中使用了pyenv来安装自定义Python版本。
在EMR Serverless上运行一个指定Spark属性的作业。这是为了使用自定义Python并提供接受命令行参数以运行Kedro的入口点脚本。
以下是一个可使用的Dockerfile示例:
FROM public.ecr.aws/emr-serverless/spark/emr-6.10.0:latest AS base
USER root
# Install Python build dependencies for pyenv
RUN yum install -y gcc make patch zlib-devel bzip2 bzip2-devel readline-devel \
sqlite sqlite-devel openssl11-devel tk-devel libffi-devel xz-devel tar
# Install git for pyenv installation
RUN yum install -y git
# Add pyenv to PATH and set up environment variables
ENV PYENV_ROOT /usr/.pyenv
ENV PATH $PYENV_ROOT/shims:$PYENV_ROOT/bin:$PATH
ENV PYTHON_VERSION=3.9.16
# Install pyenv, initialize it, install desired Python version and set as global
RUN curl https://pyenv.run | bash
RUN eval "$(pyenv init -)"
RUN pyenv install ${PYTHON_VERSION} && pyenv global ${PYTHON_VERSION}
# Copy and install packaged Kedro project
ENV KEDRO_PACKAGE <PACKAGE_WHEEL_NAME>
COPY dist/$KEDRO_PACKAGE /tmp/dist/$KEDRO_PACKAGE
RUN pip install --upgrade pip && pip install /tmp/dist/$KEDRO_PACKAGE \
&& rm -f /tmp/dist/$KEDRO_PACKAGE
# Copy and extract conf folder
ADD dist/conf.tar.gz /home/hadoop/
# EMRS will run the image as hadoop
USER hadoop:hadoop
请确保将替换为您自己的.whl文件名。
以下是入口脚本entrypoint.py:
import sys
from <PACKAGE_NAME>.__main__ import main
main(sys.argv[1:])
将 替换为你的包名。
资源¶
更多详情,请参阅以下资源:
设置¶
先决条件¶
您必须创建一个S3存储桶来存储EMR Serverless的数据。
基础设施¶
在ECR中创建一个私有仓库。具体操作步骤请参阅AWS文档。您可以使用默认设置。该仓库将用于上传EMR Serverless自定义镜像。
创建一个EMR Studio.
前往AWS控制台 > EMR > EMR Serverless。
确保您位于想要创建资源的正确区域。
然后,点击"开始使用" > "创建并启动EMR Studio"。
创建一个应用.
类型: Spark
发布版本:
emr-6.10.0架构:
x86_64应用设置选项 > "选择自定义设置"
自定义镜像设置 > "将此自定义镜像用于此应用"
为简化操作,Spark驱动器和执行器使用相同的自定义镜像
提供ECR镜像URI;它必须与EMR Studio位于同一区域
您可以根据需要自定义其他设置,甚至可以更改发布版本和架构选项(同时需在自定义镜像中进行相应更改)。
警告
文档中记录的方法仅针对上述选项进行了测试。
有关创建应用程序的更多详情,请参阅AWS EMR Serverless文档。
IAM¶
创建作业运行时角色。按照“创建作业运行时角色”下的说明操作。该角色将在向EMR Serverless提交作业时使用。策略中定义的权限还授予对S3存储桶的访问权限(请指定您已创建的S3存储桶)。
授予对ECR存储库的访问权限。
前往AWS控制台中的ECR服务。
点击进入您之前创建的代码仓库,然后在左侧导航栏中选择"代码仓库 > 权限"。
点击“编辑策略JSON”,并在“允许EMR Serverless访问自定义镜像仓库”下粘贴此策略。
确保在
aws:SourceArn值中输入您的EMR Serverless应用程序的ARN。
(可选) 验证自定义镜像¶
EMR Serverless 提供了一个实用工具,用于在本地验证您的自定义镜像,确保您的修改仍然与 EMR Serverless 兼容,并防止作业失败。详情请参阅Amazon EMR Serverless Image CLI 文档。
运行任务¶
注意
在对自定义镜像进行更改、重新构建并推送到ECR后,如果您的应用程序已经启动,请务必在提交作业前重启EMR Serverless应用程序。否则,新的更改可能不会反映在作业运行中。
这可能是因为当应用程序启动时,EMR Serverless会保留一组预热资源(也称为 预初始化容量) 准备运行作业,而这些节点可能已经使用了先前版本的ECR镜像。
查看如何在EMR Serverless上运行Spark作业的详细信息。
需要提供以下参数:
“entryPoint” - 指向S3中上传的
entrypoint.py入口脚本的路径。“entryPointArguments” - 用于运行Kedro的参数列表
“sparkSubmitParameters” - 设置属性以使用自定义Python版本
注意
需要使用"入口点脚本"是因为EMR Serverless会忽略Dockerfile中的[CMD]或[ENTRYPOINT]指令。我们建议通过"入口点脚本"以编程方式运行Kedro,这样可以避免使用例如子进程来调用kedro run。更多详情请参阅FAQ。
使用AWS CLI的示例:
aws emr-serverless start-job-run \
--application-id <application-id> \
--execution-role-arn <execution-role-arn> \
--job-driver '{
"sparkSubmit": {
"entryPoint": "<s3-path-to-entrypoint-script>",
"entryPointArguments": ["--env", "<emr-conf>", "--runner", "ThreadRunner", "--pipeline", "<kedro-pipeline-name>"],
"sparkSubmitParameters": "--conf spark.emr-serverless.driverEnv.PYSPARK_DRIVER_PYTHON=/usr/.pyenv/versions/3.9.16/bin/python --conf spark.emr-serverless.driverEnv.PYSPARK_PYTHON=/usr/.pyenv/versions/3.9.16/bin/python --conf spark.executorEnv.PYSPARK_PYTHON=/usr/.pyenv/versions/3.9.16/bin/python"
}
}'
在上方的占位符中输入相应的值。例如,使用之前为作业运行时角色创建的ARN替换。
常见问题¶
这里定义的方法与Kedro博客上“在Amazon EMR上部署Kedro管道的七个步骤”中的方法有何不同?¶
两种方法在步骤上有相似之处。关键区别在于,本页介绍如何通过自定义镜像提供自定义Python版本。而博客文章则介绍了为EMR在虚拟环境中提供Python依赖项的方法。
提供自定义镜像的方法适用于EMR Serverless。在EMR上,值得考虑使用自定义AMI作为替代bootstrap actions的方案。目前尚未对此进行探索或测试。
EMR Serverless 已经预装了 Python,为什么我们还需要自定义 Python 版本?¶
某些应用可能需要与默认安装的Python版本不同的版本。例如,您的代码库可能需要Python 3.9,而最新EMR版本(6.10.0, 6.11.0)上默认安装的Python是基于Python 3.7的。
为什么我们需要创建一个自定义镜像来提供自定义的Python版本?¶
在使用pyenv修改虚拟环境方案时,您可能会遇到困难。在使用venv-pack过程中,我们发现一个会返回错误Too many levels of symbolic links的限制条件,具体记录如下:
Python 并未随环境打包,而是在环境中创建符号链接。这在部署场景中非常有用,因为机器上可能已安装Python,但所需的库依赖项可能尚未安装。
自定义镜像方法一次性完成了Kedro项目的安装并提供了自定义Python版本。否则,您需要单独提供文件,并在每次提交作业时将它们指定为额外的Spark配置。
为什么我们需要打包Kedro项目并使用入口点脚本来调用?为什么不能在自定义镜像中直接使用[CMD]或[ENTRYPOINT]运行kedro run?¶
如AWS文档所述,EMR Serverless会忽略Dockerfile中的[CMD]或[ENTRYPOINT]指令。
我们建议使用entrypoint.py入口点脚本的方式以编程方式运行Kedro,而不是通过subprocess调用kedro run。
是否考虑使用Lifecycle management with KedroSession中描述的方法以编程方式运行Kedro?¶
这是一种以编程方式运行Kedro的有效替代方案,无需打包Kedro项目,但这些参数并不直接对应Kedro命令行参数:
使用了不同的名称。例如,使用"pipeline_name"和"node_names"代替"pipeline"和"nodes"。
使用了不同类型。例如,要指定"runner",您需要传递一个
AbstractRunner对象,而不是像"ThreadRunner"这样的字符串值。
参数需要分别传递:"env"直接传递给KedroSession.create(),而其他参数如"pipeline_name"和"node_names"需要传递给session.run()。
它最适合于调用kedro run的场景,或者当你没有向Kedro提供许多命令行参数时。