亚马逊AWS官方博客

使用 Amazon EMR 6.0.0(测试版)在 Docker 上运行 Spark 应用程序

Original URL:https://aws.amazon.com/blogs/big-data/run-spark-applications-with-docker-using-amazon-emr-6-0-0-beta/

Amazon EMR 团队很高兴宣布支持  Spark 2.4.3Hadoop 3.1.0Amazon Linux 2 和  Amazon Corretto 8 EMR 6.0.0 的公开测试版已经推出。在这个测试版中,Spark 用户可以使用  Docker Hub 和  Amazon Elastic Container Registry (Amazon ECR) 中的  Docker 镜像来定义环境和库依赖项。使用 Docker,用户可以轻松管理依赖项并将其用于单个作业,而无需在集群的各个主机上安装依赖项。

这篇博文向您展示了如何在 EMR 6.0.0 测试版中使用 Docker。您将学习如何启动 EMR 6.0.0 测试版集群,并通过 Docker Hub 和 Amazon ECR 中的 Docker 镜像以容器方式运行 Spark 作业。

Hadoop 3 Docker 支持

EMR 6.0.0(测试版)采用 Hadoop 3.1.0,这允许 YARN NodeManager 直接在集群的主机上或 Docker 容器内部启动容器。Docker 容器提供了一个自定义执行环境,在该环境中,应用程序的代码通过与 YARN NodeManager 和其他应用程序的执行环境隔离的方式运行。

这些容器可以包括应用程序所需的特殊库,甚至可以提供不同版本的原生工具和库,例如 R、Python、Python 库。这使得您可以使用熟悉的 Docker 工具,轻松定义应用程序所需的库和运行时依赖项。

默认情况下,运行 EMR 6.0.0(测试版)的集群已配置为允许使用 Docker 容器运行 YARN 应用程序(例如 Spark)。要对此进行自定义,请使用 /etc/hadoop/conf 目录中的 yarn-site.xml 和 container-executor.cfg 文件内定义的 Docker 支持选项进行配置。有关各配置选项及其用法的详细信息,请参阅使用 Docker 容器启动应用程序

您可以在提交作业时选择使用 Docker。在提交作业时,以下变量用于指定使用的 Docker 运行时和 Docker 镜像:

    • YARN_CONTAINER_RUNTIME_TYPE=docker
    • YARN_CONTAINER_RUNTIME_DOCKER_IMAGE={DOCKER_IMAGE_NAME}

当您使用 Docker 容器执行 YARN 应用程序时,YARN 将下载您提交作业时指定的 Docker 镜像。为了使 YARN 能够解析此 Docker 镜像,必须配置 Docker 镜像仓库。配置 Docker 镜像仓库的选项因您选择的 EMR 部署方式(使用公有子网还是私有子网)而异。

Docker 镜像仓库

Docker 镜像仓库是 Docker 镜像的存储和分发系统。对于 EMR 6.0.0(测试版),可以配置以下 Docker 镜像仓库:

  • Docker Hub:一个公共的 Docker 镜像仓库,其中包含超过 100000 个流行的 Docker 镜像。
  • Amazon ECR:完全托管的 Docker 容器镜像仓库,可让您创建自己的自定义镜像并将其托管在高可用且可扩展的服务中。

部署注意事项

Docker 镜像仓库需要集群中每个主机都具有网络访问权限,因为当您的 YARN 应用程序在集群上运行时,每个主机都会从 Docker 镜像仓库中下载镜像。由于网络连接性要求,您选择的 EMR 集群部署方式(接入公有子网还是私有子网)可能会限制您选择的 Docker 镜像仓库。

公有子网

如果是 EMR 公有子网集群,运行 YARN NodeManager 的节点可以直接访问互联网上可用的任何镜像仓库,例如 Docker Hub,如下图所示。

私有子网

如果是 EMR 私有子网集群,运行 YARN NodeManager 的节点无法直接访问互联网。 Docker 镜像可以托管在 ECR 中,并可以通过 AWS PrivateLink 访问,如下图所示。

有关如何在私有子网场景中使用 AWS PrivateLink 允许访问 ECR 的详细信息,请参阅为 Amazon ECS 和 Amazon ECR 设置 AWS PrivateLink

配置 Docker 镜像仓库

必须将 Docker 配置为信任用于解析 Docker 镜像的特定镜像仓库。默认的信任注册表是 local(私有)和 centos(位于公共的 Docker Hub 上)。您可以在 /etc/hadoop/conf/container-executor.cfg 中覆盖 docker.trusted.registries 以使用其他公共存储库或 ECR。要覆盖此配置,请使用 EMR 分类 API 和 container-executor 分类。

以下示例展示了如何配置集群以信任公共存储库 (your-public-repo) 和 ECR 镜像仓库 (123456789123.dkr.ecr.us-east-1.amazonaws.com)。使用 ECR 时,请将该终端节点替换为您的特定 ECR 终端节点。使用 Docker Hub 时,请将此存储库的名称替换为您的实际存储库名称。

[

{

“Classification”: “container-executor”,

“Configurations”: [

{

“Classification”: “docker”,

“Properties”: {

“docker.trusted.registries”: “local,centos, your-public-repo,123456789123.dkr.ecr.us-east-1.amazonaws.com”,

“docker.privileged-containers.registries”: “local,centos, your-public-repo,123456789123.dkr.ecr.us-east-1.amazonaws.com”

}

}

]

}

]

要使用 AWS 命令行界面 (AWS CLI) 以此配置启动 EMR 6.0.0(测试版)集群,请创建一个名为 container-executor.json 的文件,其中包含上述 JSON 配置的内容。 然后,使用以下命令启动集群:

$ export KEYPAIR=<Name of your Amazon EC2 key-pair>

$ export SUBNET_ID=<ID of the subnet to which to deploy the cluster>

$ export INSTANCE_TYPE=<Name of the instance type to use>

$ export REGION=<Region to which to deploy the cluster deployed>

 

$ aws emr create-cluster \

–name “EMR-6-Beta Cluster” \

–region $REGION \

–release-label emr-6.0.0-beta \

–applications Name=Hadoop Name=Spark \

–service-role EMR_DefaultRole \

–ec2-attributes KeyName=$KEYPAIR,InstanceProfile=EMR_EC2_DefaultRole,SubnetId=$SUBNET_ID \

–instance-groups InstanceGroupType=MASTER,InstanceCount=1,InstanceType=$INSTANCE_TYPE InstanceGroupType=CORE,InstanceCount=2,InstanceType=$INSTANCE_TYPE \

–configuration file://container-executor.json

使用 ECR

如果您之前不熟悉 ECR,请按照 Amazon ECR 入门中的说明进行操作,并验证从EMR 集群中的每个实例都可以访问 ECR。

要使用 docker 命令访问 ECR,必须首先生成凭证。为了确保 YARN 可以访问 ECR 中的镜像,请使用容器环境变量 YARN_CONTAINER_RUNTIME_DOCKER_CLIENT_CONFIG 传递对生成凭证的引用。

在其中一个核心节点上运行以下命令,以获取您的 ECR 账户的登录命令。

$ aws ecr get-login –region us-east-1 –no-include-email

get-login 命令会生成创建凭证的 Docker CLI 命令。复制并运行 get-login 的输出结果。

$ sudo docker login -u AWS -p <password> https://<account-id>.dkr.ecr.us-east-1.amazonaws.com

此命令在 /root/.docker 文件夹中生成一个 config.json 文件。 将此文件复制到 HDFS,以便提交给集群的作业可以使用它向 ECR 进行身份验证。

执行以下命令,将 config.json 文件复制到您的家目录。

$ mkdir -p ~/.docker
$ sudo cp /root/.docker/config.json ~/.docker/config.json
$ sudo chmod 644 ~/.docker/config.json

执行以下命令以将 config.json 放入 HDFS,让集群上运行的作业可以使用它。

$ hadoop fs -put ~/.docker/config.json /user/hadoop/

此时,YARN 可以将 ECR 作为 Docker 镜像仓库访问,并在作业执行期间拉取容器。

通过 Docker 运行 Spark

借助 EMR 6.0.0(测试版),Spark 应用程序可以使用 Docker 容器定义其库依赖项,而无需要求将依赖项安装在集群中的各个 Amazon EC2 实例上。这种集成要求配置 Docker 镜像仓库,并在提交 Spark 应用程序时定义其他参数。

提交应用程序后,YARN 会调用 Docker 来拉取指定的 Docker 镜像,并在 Docker 容器内运行 Spark 应用程序。这让您可以轻松定义和隔离依赖关系,还能减少在 EMR 集群中为了执行作业所需的库进行引导操作或实例准备所耗费的时间。

将 Spark 与 Docker 结合使用时,请务必考虑以下因素:

  • docker 程序包和 CLI 仅需安装在核心节点和任务节点上。
  • spark-submit 命令应始终从 EMR 集群的主实例上运行。
  • 在启动集群时用于解析 Docker 镜像的 Docker 镜像仓库必须使用带有 container-executor 分类的分类 API 来定义参数:
    • docker.trusted.registries
    • docker.privileged-containers.registries
  • 要在 Docker 容器中执行 Spark 应用程序,需要使用以下配置选项:
    • YARN_CONTAINER_RUNTIME_TYPE=docker
    • YARN_CONTAINER_RUNTIME_DOCKER_IMAGE={DOCKER_IMAGE_NAME}
  • 使用 ECR 获取Docker 镜像时,必须将集群配置为可以自行执行身份验证。为此,务必使用以下配置选项:
    • YARN_CONTAINER_RUNTIME_DOCKER_CLIENT_CONFIG={DOCKER_CLIENT_CONFIG_PATH_ON_HDFS}
  • 将 /etc/passwd 文件挂载到容器中,以便可以在 Docker 容器中标识正在运行作业的用户。
    • YARN_CONTAINER_RUNTIME_DOCKER_MOUNTS=/etc/passwd:/etc/passwd:ro
  • 与 Spark 配合使用的任何 Docker 镜像都必须在镜像中安装 Java。

创建一个 Docker 镜像

Docker 镜像是使用 Dockerfile 创建的,该文件定义了要包含在镜像中的程序包和配置。以下两个示例 Dockerfile 分别使用了 PySpark 和 SparkR。

PySpark Dockerfile

通过该 Dockerfile 创建的 Docker 镜像包括 R 和 randomForest CRAN 程序包。该 Dockerfile 包括 Amazon Linux 2 和 Amazon Corretto JDK 8。

FROM amazoncorretto:8

RUN yum -y update
RUN yum -y install yum-utils
RUN yum -y groupinstall development

RUN yum list python3*
RUN yum -y install python3 python3-dev python3-pip python3-virtualenv

RUN python -V
RUN python3 -V

ENV PYSPARK_DRIVER_PYTHON python3
ENV PYSPARK_PYTHON python3

RUN pip3 install --upgrade pip
RUN pip3 install numpy panda

RUN python3 -c "import numpy as np"

SparkR Dockerfile

通过该 Dockerfile 创建的 Docker 镜像包括 R 和 randomForest CRAN 程序包。该 Dockerfile 包括 Amazon Linux 2 和 Amazon Corretto JDK 8。

FROM amazoncorretto:8

RUN java -version

RUN yum -y update
RUN amazon-linux-extras enable R3.4

RUN yum -y install R R-devel openssl-devel
RUN yum -y install curl

#setup R configs
RUN echo "r <- getOption('repos'); r['CRAN'] <- 'http://cran.us.r-project.org'; options(repos = r);" > ~/.Rprofile

RUN Rscript -e "install.packages('randomForest')"

有关 Dockerfile 语法的更多信息,请参阅 Dockerfile 参考文档。

使用 ECR 中的 Docker 镜像

Amazon Elastic Container Registry (ECR) 是一种完全托管式的 Docker 容器镜像仓库,让开发人员可以轻松存储、管理和部署 Docker 容器镜像。使用 ECR 时,必须将集群配置为信任您的 ECR 实例,并且必须配置身份验证以使集群使用来自 ECR 的 Docker 镜像。

在此示例中,我们必须使用以下额外配置创建集群,以确保 ECR 镜像仓库受信任。请用您的 ECR 终端节点替换 123456789123.dkr.ecr.us-east-1.amazonaws.com 终端节点。

[
  {
    "Classification": "container-executor",
    "Configurations": [
        {
            "Classification": "docker",
            "Properties": {
                "docker.trusted.registries": "local,centos,123456789123.dkr.ecr.us-east-1.amazonaws.com",
                "docker.privileged-containers.registries": "local,centos, 123456789123.dkr.ecr.us-east-1.amazonaws.com"
            }
        }
    ]
  }
]

将 PySpark 与 ECR 结合使用

本示例使用 PySpark Dockerfile。 这个文件将被标记并上传到 ECR。上传后,您将运行 PySpark 作业,并引用 ECR 中的 Docker 镜像。

启动集群后,使用 SSH 连接到核心节点,然后运行以下命令从 PySpark Dockerfile 示例构建本地 Docker 镜像。

首先,为我们的示例创建一个目录和一个 Dockerfile。

$ mkdir pyspark

$ vi pyspark/Dockerfile

粘贴 PySpark Dockerfile 的内容,然后运行以下命令来构建 Docker 镜像。

$ sudo docker build -t local/pyspark-example pyspark/

为我们的示例创建 emr-docker-examples ECR 存储库。

$ aws ecr create-repository --repository-name emr-docker-examples

标记在本地构建的镜像并将其上传到 ECR,将 123456789123.dkr.ecr.us-east-1.amazonaws.com 替换为您的 ECR 终端节点。

$ sudo docker tag local/pyspark-example 123456789123.dkr.ecr.us-east-1.amazonaws.com/emr-docker-examples:pyspark-example
$ sudo docker push 123456789123.dkr.ecr.us-east-1.amazonaws.com/emr-docker-examples:pyspark-example

使用 SSH 连接到主节点,并准备一个文件名为 main.py 的 Python 脚本。将以下内容粘贴到 main.py 文件中并保存。

from pyspark.sql import SparkSession
spark = SparkSession.builder.appName("docker-numpy").getOrCreate()
sc = spark.sparkContext

import numpy as np
a = np.arange(15).reshape(3, 5)
print(a)

要提交作业,请指定 Docker 镜像的名称。定义其他配置参数以确保作业执行使用 Docker 作为运行时。使用 ECR 时,YARN_CONTAINER_RUNTIME_DOCKER_CLIENT_CONFIG 必须引用 config.json 文件,该文件包含用于对 ECR 进行身份验证的凭证。

$ DOCKER_IMAGE_NAME=123456789123.dkr.ecr.us-east-1.amazonaws.com/emr-docker-examples:pyspark-example
$ DOCKER_CLIENT_CONFIG=hdfs:///user/hadoop/config.json
$ spark-submit --master yarn \
--deploy-mode cluster \
--conf spark.executorEnv.YARN_CONTAINER_RUNTIME_TYPE=docker \
--conf spark.executorEnv.YARN_CONTAINER_RUNTIME_DOCKER_IMAGE=$DOCKER_IMAGE_NAME \
--conf spark.executorEnv.YARN_CONTAINER_RUNTIME_DOCKER_CLIENT_CONFIG=$DOCKER_CLIENT_CONFIG \
--conf spark.executorEnv.YARN_CONTAINER_RUNTIME_DOCKER_MOUNTS=/etc/passwd:/etc/passwd:ro \
--conf spark.yarn.appMasterEnv.YARN_CONTAINER_RUNTIME_TYPE=docker \
--conf spark.yarn.appMasterEnv.YARN_CONTAINER_RUNTIME_DOCKER_IMAGE=$DOCKER_IMAGE_NAME \
--conf spark.yarn.appMasterEnv.YARN_CONTAINER_RUNTIME_DOCKER_CLIENT_CONFIG=$DOCKER_CLIENT_CONFIG \
--conf spark.yarn.appMasterEnv.YARN_CONTAINER_RUNTIME_DOCKER_MOUNTS=/etc/passwd:/etc/passwd:ro \
--num-executors 2 \
main.py -v

作业完成后,记下 YARN 应用程序 ID,并使用以下命令获取 PySpark 作业的输出。

$ yarn logs --applicationId application_id | grep -C2 '\[\['
LogLength:55
LogContents:
[[ 0  1  2  3  4]
 [ 5  6  7  8  9]
 [10 11 12 13 14]]

将 SparkR 与 ECR 结合使用

本示例使用 SparkR Dockerfile。这个文件将被标记并上传到 ECR。上传后,您将运行 SparkR 作业并引用 ECR 中的 Docker 镜像。

启动集群后,使用 SSH 连接到核心节点,然后运行以下命令从 SparkR Dockerfile 示例构建本地 Docker 镜像。

首先,为该示例创建目录和 Dockerfile。

$ mkdir sparkr

$ vi sparkr/Dockerfile

粘贴 SparkR Dockerfile 的内容,然后运行以下命令来构建 Docker 镜像。

$ sudo docker build -t local/sparkr-example sparkr/

标记在本地构建的镜像并将其上传到 ECR,将 123456789123.dkr.ecr.us-east-1.amazonaws.com 替换为您的 ECR 终端节点。

$ sudo docker tag local/sparkr-example 123456789123.dkr.ecr.us-east-1.amazonaws.com/emr-docker-examples:sparkr-example
$ sudo docker push 123456789123.dkr.ecr.us-east-1.amazonaws.com/emr-docker-examples:sparkr-example

使用 SSH 连接到主节点,并准备一个名称为 sparkR.R 的 R 脚本。将以下内容粘贴到 sparkR.R 文件中。

library(SparkR)
sparkR.session(appName = "R with Spark example", sparkConfig = list(spark.some.config.option = "some-value"))

sqlContext <- sparkRSQL.init(spark.sparkContext)
library(randomForest)
# check release notes of randomForest
rfNews()

sparkR.session.stop()

要提交作业,请指定 Docker 镜像的名称。定义其他配置参数以确保作业执行使用 Docker 作为运行时。使用 ECR 时,YARN_CONTAINER_RUNTIME_DOCKER_CLIENT_CONFIG 必须引用 config.json 文件,该文件包含用于对 ECR 进行身份验证的凭证。

$ DOCKER_IMAGE_NAME=123456789123.dkr.ecr.us-east-1.amazonaws.com/emr-docker-examples:sparkr-example
$ DOCKER_CLIENT_CONFIG=hdfs:///user/hadoop/config.json
$ spark-submit --master yarn \
--deploy-mode cluster \
--conf spark.executorEnv.YARN_CONTAINER_RUNTIME_TYPE=docker \
--conf spark.executorEnv.YARN_CONTAINER_RUNTIME_DOCKER_IMAGE=$DOCKER_IMAGE_NAME \
--conf spark.executorEnv.YARN_CONTAINER_RUNTIME_DOCKER_CLIENT_CONFIG=$DOCKER_CLIENT_CONFIG \
--conf spark.executorEnv.YARN_CONTAINER_RUNTIME_DOCKER_MOUNTS=/etc/passwd:/etc/passwd:ro \
--conf spark.yarn.appMasterEnv.YARN_CONTAINER_RUNTIME_TYPE=docker \
--conf spark.yarn.appMasterEnv.YARN_CONTAINER_RUNTIME_DOCKER_IMAGE=$DOCKER_IMAGE_NAME \
--conf spark.yarn.appMasterEnv.YARN_CONTAINER_RUNTIME_DOCKER_CLIENT_CONFIG=$DOCKER_CLIENT_CONFIG \
--conf spark.yarn.appMasterEnv.YARN_CONTAINER_RUNTIME_DOCKER_MOUNTS=/etc/passwd:/etc/passwd:ro \
sparkR.R

作业完成后,记下 YARN 应用程序 ID,并使用以下命令获取 SparkR 作业的输出。此示例为测试,主要是检查 randomForest 库、已安装的版本和发行说明。

$ yarn logs --applicationId application_id | grep -B4 -A10 "Type rfNews"
randomForest 4.6-14
Type rfNews() to see new features/changes/bug fixes.
Wishlist (formerly TODO):

* Implement the new scheme of handling classwt in classification.

* Use more compact storage of proximity matrix.

* Allow case weights by using the weights in sampling?

========================================================================
Changes in 4.6-14:

使用 Docker Hub 中的 Docker 镜像

要使用 Docker Hub,必须将集群部署到公有子网,并配置 Docker Hub 为受信任的镜像仓库。在此示例中,集群需要以下额外配置,以确保 Docker Hub 上的 your-public-repo 存储库受到信任。使用 Docker Hub 时,请将此存储库名称替换为您的实际存储库的名称。

[
  {
    "Classification": "container-executor",
    "Configurations": [
        {
            "Classification": "docker",
            "Properties": {
                "docker.trusted.registries": "local,centos,your-public-repo ",
                "docker.privileged-containers.registries": "local,centos,your-public-repo"
            }
        }
    ]
  }
]

测试版限制

EMR 6.0.0(测试版)致力于帮助您将 Docker 与 Spark 结合使用以简化依赖项管理,从而为您提供价值。您也可以使用 EMR 6.0.0(测试版)来熟悉 Amazon Linux 2 和 Amazon Corretto JDK 8。

EMR 6.0.0(测试版)支持以下应用程序:

  • Spark 2.4.3
  • Livy 0.6.0
  • ZooKeeper 3.4.14
  • Hadoop 3.1.0

以下区域支持该测试版本:

  • 美国东部(弗吉尼亚北部)
  • 美国西部(俄勒冈)

此测试版当前不提供以下 EMR 功能:

  • 与 AWS Lake Formation 的集成
  • 附加到 EMR 集群的 Amazon EBS 卷的原生加密

小结

本文介绍了如何使用 EMR 6.0.0(测试版)集群在 Docker 容器中运行 Spark 作业,并与 Docker Hub 和 ECR 集成。接着,本文又展示了 PySpark Dockerfile 和 SparkR Dockerfile 的示例。

EMR 团队期待了解您如何在项目中使用此集成来简化依赖项管理。如果您有任何问题或建议,欢迎留言。


关于作者

Paul Codding 是 Amazon Web Services 负责 EMR 的高级产品经理

 

 

 

 

Ajay Jadhav 是 Amazon Web Services 负责 EMR 的软件开发工程师

 

 

 

 

Rentao Wu 是 Amazon Web Services 负责 EMR 的软件开发工程师

 

 

 

 

Stephen Wu 是 Amazon Web Services 负责 EMR 的软件开发工程师