客座文章作者:万事达卡首席软件开发工程师 Allison Richardet
在万事达,内部云团队维护我们的 Kubernetes 平台。我们的工作包括维护 Kubernetes 集群,这是我们所依赖的核心部署,并为租户提供了日志、监控等服务,并为租户提供了良好的体验。
我们的租户之一,数据仓库团队,曾经在 YARN 和 HDFS 上使用过原生 Apache Spark。他们找了我们的团队,希望将他们的大数据工作转移到 Kubernetes;他们想要实现云原生化,而我们也有机会在 Kubernetes 上与 Apache Spark 合作。
所以,我们的旅程从 Spark Operator 开始。向 Kubernetes 和 Operators 的迁移将为我们的内部客户数据仓库团队打开云原生的可能性。我们有机会帮助他们利用可伸缩性和成本改进的优势,而切换到 S3 将进一步实现这些目标。
背景
操作器(operator)是什么,为什么我们,或者你,对此感兴趣?首先,操作器使用自定义资源扩展了 Kubernetes API。操作器还定义了一个自定义控制器来监视其资源类型。将自定义资源与自定义控制器结合在一起会产生一个声明性 API,在这个 API 中,操作器会协调集群声明状态与实际状态之间的差异。换句话说,操作器处理与其资源相关的自动化。
有了这些好处,我们的团队很高兴能够利用 Kubernetes 的 Spark 操作器来支持我们的租户。通常,原生 Apache Spark 使用 HDFS。然而,迁移到云端并在 Kuberentes 上运行 Spark 操作器,S3 是 HDFS 的一个很好的替代方案,因为它具有成本优势,并且能够根据需要进行扩展。有趣的是,S3 在默认情况下不能与 Spark 操作器一起使用。我们参考了 Spark 操作器以及 Hadoop-AWS 集成文档。此外,我们将分享以下 4 个步骤的详细信息:镜像更新、SparkApplication 配置、S3 凭据和 S3 样式。遵循我们的步骤,将 S3 与你的 Spark 作业和 Kubernetes 的 Spark 操作器进行集成。
工作流程
与我们部署到 Kubernetes 集群的大多数应用程序一样,我们使用 Helm chart。Kubernetes 的 Apache Spark 操作器的 Helm chart 可以在这里[1]找到。
Values & Helm 模板
我们更新 values.yaml,然后运行 helm template 生成我们将部署到 Kubernetes 集群的清单。我们发现,对将要创建的内容具有可见性和对部署的控制是值得额外步骤的;模板存储在 git 中,我们的 CD 工具负责部署。
默认的 chart values 将允许你快速启动和运行。根据你的需要,以下是你可能需要做的一些修改:
- 启用 webhook:默认情况下,不启用 Mutating Admission Webhook。启用允许自定义 SparkApplication 驱动程序和执行程序 pod,包括挂载卷、ConfigMaps、亲和性/非亲和性等等。
- 定义 ingressUrlFormat:Spark UI 可选的 ingress。
请参阅快速入门指南[2]和默认values.yaml[3]获取更多详细信息和选项。
需求
要运行使用 S3 的 SparkApplication,需要 SparkApplication 的附加配置,包括一个自定义 docker 镜像。Hadoop S3AConnector 是一种可以对 S3 进行读写的工具。
1. 镜像更新
SparkApplication 使用的 docker 镜像需要添加两个 jar(hadoop-aws 和 aws-java-sdk 或 aws-java-sdk-bundle),版本根据 Spark 版本和 Hadoop 配置文件。
在这一步中有几件事情要记住。
- 用户和权限
- 额外的 Jar
如果使用 spark 镜像作为起点,在添加 jar 时引用它们各自的 dockerfile 以正确对齐用户和位置。
让我们来看看 python Dockerfile[4]。在执行任何安装任务之前,用户被设置为 root,然后重置为${spark_uid}。
通过检查基本镜像[5],可以看到 jar 位于/opt/spark/jars 或$SPARK_HOME/jars 中。最后,更新 jar 的权限,以便能够使用它们。
上传到 S3[6]的文档提供了使用 jar 文件的信息;然而,我们需要一个包含 fs.s3a.path.style.access 配置的新 Hadoop 版本——我们将在后面一节中讨论这个问题。在编写本文时,我们使用 spark 操作器版本 v1beta2-1.2.0-3.0.0,其中包含基本 spark 版本 3.0.0。使用 gcr.io/spark-operator/spark-py:v3.0.0-hadoop3 镜像作为起点,我们添加了以下 jar:hadoop-aws-3.1.0.jar 和 aws-java-sdk-bundle-1.11.271.jar。它需要一些实验来确定最终能工作的正确镜像组合。
2. SparkApplication 配置
SparkApplication 需要额外的配置才能与 S3 通信。spec.sparkConf 中要求的最小配置如下:
代码语言:javascript复制sparkConf:
spark.hadoop.fs.s3a。端点:<端点>
spark.hadoop.fs.s3a。impl: org.apache.hadoop.fs.s3a.S3AFileSystem
还必须提供访问 S3 的凭据。有类似于上面的配置选项;但是,这是非常丧气的,因为它们是字符串值,因此与安全最佳实践相违背。
3. S3 凭证
我们不在 SparkApplication 的 sparkConf 中提供 s3 凭据,而是创建一个 Kubernetes 秘密,并为驱动程序和执行程序定义环境变量。Spark 操作器文档提供了几种使用 secret 的选项,以及用于挂载秘密[7]或指定环境变量[8]的完整示例。
接下来,因为我们使用环境变量来验证 S3,我们在 sparkConf 中设置以下选项:
代码语言:javascript复制sparkConf:
spark.hadoop.fs.s3a.aws.credentials.provider: com.amazonaws.auth.EnvironmentVariableCredentialsProvider
这是不需要的,如果没有提供,将尝试按照以下顺序来尝试凭据提供程序类:
- org.apache.hadoop.fs.s3a.SimpleAWSCredentialsProvider
- com.amazonaws.auth.EnvironmentVariableCredentialsProvider
- com.amazonaws.auth.InstanceProfileCredentialsProvider
4. S3 样式
在 SparkApplication 的 sparkConf 中有一些其他的选项需要记住,这些选项是基于你特定的 S3 的:
代码语言:javascript复制sparkConf:
extraJavaOptions: -Dcom.amazonaws.services.s3.enableV4=true
spark.hadoop.fs.s3a.path.style.access: “true”
spark.hadoop.fs.s3a.connection.ssl.enabled: “true”
路径样式访问——通过启用路径样式访问,将禁用虚拟主机(默认启用)。启用路径样式访问可以消除为默认虚拟主机设置 DNS 的需求。
启用 SSL——如果你正在使用 TLS/SSL,请确保在 SparkApplication 的 sparkConf 中启用这个选项。
额外的 Java 选项——根据你的需要而变化。
使用 S3
现在你已经完成了使用 S3 的所有设置,现在有两种选择:利用 S3 处理依赖项或上传到 S3。
S3 处理依赖项
mainApplicationFile 和 spark 作业使用的附加依赖项(包括文件或 jar)也可以从 S3 中存储和获取。它们可以在 spec.deps 字段中的 SparkApplication 中与其他依赖项一起定义。spark-submit 会分别使用 spec.deps.jar 和 spec.deps.files 中指定的 jar 或文件。s3 中访问依赖的格式为 s3a://bucket/path/to/file。
上传到 S3
上传到 S3 时,文件位置的格式为 s3a://bucket/path/to/destination。bucket 必须存在,否则上传失败。如果 destination 文件已经存在,上载将失败。
总结
我们介绍了启动并运行 Spark 操作器和 S3 所需的 4 个步骤:镜像更新、SparkApplication 的 sparkConf 中所需的选项、S3 凭据以及基于特定 S3 的其他选项。最后,我们给出了一些关于如何利用 S3 来实现依赖关系和上传到 S3 的建议。
最后,我们帮助我们的内部客户,数据仓库团队,将他们的大数据工作负载从原生 Apache Spark 转移到 Kubernetes。Kubernetes 上的 Spark 操作器在云计算方面有很大的优势,我们想与更大的社区分享我们的经验。我们希望这个关于 Spark 操作器和 S3 集成的演练将帮助你和/或你的团队启动并运行 Spark 操作器和 S3。
参考资料
[1]
这里: https://github.com/GoogleCloudPlatform/spark-on-k8s-operator/tree/master/charts/spark-operator-chart
[2]
快速入门指南: https://github.com/GoogleCloudPlatform/spark-on-k8s-operator/blob/master/docs/quick-start-guide.md
[3]
values.yaml: https://github.com/GoogleCloudPlatform/spark-on-k8s-operator/blob/master/charts/spark-operator-chart/values.yaml
[4]
Dockerfile: https://github.com/apache/spark/blob/master/resource-managers/kubernetes/docker/src/main/dockerfiles/spark/bindings/python/Dockerfile
[5]
基本镜像: https://github.com/apache/spark/blob/master/resource-managers/kubernetes/docker/src/main/dockerfiles/spark/Dockerfile
[6]
上传到 S3: https://github.com/GoogleCloudPlatform/spark-on-k8s-operator/blob/master/sparkctl/README.md#uploading-to-s3
[7]
挂载秘密: https://github.com/GoogleCloudPlatform/spark-on-k8s-operator/blob/master/docs/user-guide.md#mounting-secrets
[8]
指定环境变量: https://github.com/GoogleCloudPlatform/spark-on-k8s-operator/blob/master/docs/user-guide.md#specifying-environment-variables