亚马逊AWS官方博客

EMR on EKS 与 Apache Kyuubi 的数据驱动之旅

背景

Data on Kubernetes

在现代化数据策略的推动下,我们看到越来越多的客户将大数据工作负载从传统的虚拟机迁移到容器化环境。客户被 Kubernetes 所带来的动态扩展、快速构建和资源编排能力所吸引。同时,流行的大数据流/批处理引擎如 Apache Spark、Apache Flink 等也开始支持 Kubernetes 作为资源管理器。

Amazon EMR on EKS

Amazon EMR on EKS 为 Amazon EMR 提供了部署选项,可让您在 Amazon Elastic Kubernetes Service(Amazon EKS)上运行开源大数据框架。借助此部署选项,您可以专注于运行分析工作负载,同时 Amazon EMR on EKS 为开源应用程序构建、配置和管理容器。截止至 2024 年 4 月,Amazon EMR on EKS 已经支持 Apache Spark 和 Apache Flink 引擎,并且计划支持 Trino。

Apache Kyuubi

Apache Kyuubi 的目标是提供一个高度并发、可扩展且支持多租户的 SQL 引擎,以满足大数据分析的需求。它由 Apache Spark、Apache Flink 和 Trino 等流行计算框架提供支持,提供高效的查询功能。用户可以通过 JDBC/ODBC 访问 Kyuubi,从而能够直接或通过 BI 工具运行 SQL 查询。 Kyuubi 促进资源共享并提供快速响应。它与各种来源无缝集成,包括 Apache Hive/HDFS 等传统数据仓库和 Apache Iceberg、Apache Hudi 和 Delta Lake 等现代 Lakehouse 标准。

Kyuubi 与不同的资源管理器(包括 K8s 和 YARN)集成开箱即用,因此这使我们能够轻松地与 EKS 上的 EMR 和 EC2 上的 EMR 集成。在此之前,我们通过“使用 EMR Hue 整合 Apache Kyuubi 提升 Spark SQL 开发效率”一文来介绍 Apache Kyuubi 和 EMR on EC2 的集成,在此文中,我们会继续探索 Apache Kyuubi 和 EMR on EKS 集成的方式和体验。

方案架构总览

方案搭建步骤

预置 EMR on EKS 环境

git clone https://github.com/aws-samples/aws-emr-utilities.git
cd aws-emr-utilities/utilities/emr-on-eks-kyuubi

使用脚本进行工具预置。

使用脚本进行 EMR on EKS 环境预置:

该脚本在 emr 命名空间中设置了一个 EMR on EKS virtual cluster,Kyuubi 组件安装在名为 kyuubi 的单独命名空间中。为了允许 Kyuubi 跨不同命名空间 emr 创建 Spark 集群,该脚本在 emr 命名空间中构建了一个服务帐户 emr-kyuubi,该帐户映射到预构建的 EMR on EKS role emr-containers-role-spark-driver。

使用 kubectl get role -n emr 查看,若环境中没有 emr-containers-role-spark-driver 存在若没有,请将此文件下载, 并运行 kubectl apply -f emr-containers-driver-role.yaml -n emr

构建包含 Apache Kyuubi的EMR on EKS 自定义镜像

注意:下述以 us-east-1 区域为例,其他区域要注意更改到对应 Amazon ECR 镜像仓库的账号,列表如下: https://docs.thinkwithwp.com/emr/latest/EMR-on-EKS-DevelopmentGuide/docker-custom-images-tag.html

ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
AWS_REGION=us-east-1
ECR_URL=$ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com

aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin 755674844232.dkr.ecr.us-east-1.amazonaws.com
aws ecr get-login-password --region $AWS_REGION | docker login --username AWS --password-stdin $ECR_URL

# create a new repository in your ECR, **ONE-OFF task**
aws ecr create-repository --repository-name kyuubi-emr-eks --image-scanning-configuration scanOnPush=true

docker buildx build --platform linux/amd64,linux/arm64 \
-t $ECR_URL/kyuubi-emr-eks:emr6.15_kyuubi1.8 \
-f dockers/kyuubi/Dockerfile \
--build-arg SPARK_BASE_IMAGE=755674844232.dkr.ecr.us-east-1.amazonaws.com/spark/emr-6.15.0 \
--build-arg KYUUBI_VERSION=1.8.0 \
--build-arg SPARK_VERSION=3.4.1 \
--build-arg RANGER_VERSION=2.4.0 \
--push .

从 Docker Engine 23.0 和 Docker Desktop 4.19 开始,Buildx 是默认的构建客户端。但是,如果您使用的是旧版本,请参阅此链接以获取完整的设置说明:

docker buildx 完整命令可以参考此链接

Dockerfile 内容请见链接

安装 Apache Kyuubi

git clone https://github.com/aws-samples/aws-emr-utilities.git
cd aws-emr-utilities/utilities/emr-on-eks-kyuubi
helm install kyuubi charts/kyuubi -n kyuubi --create-namespace -f charts/my-kyuubi-values.yaml --debug
# check the installation progress
kubectl get all -n kyuubi

my-kyuubi-values.yaml 文件模板可以从此链接下载。

注意配置 cross namespace service account,如上述链接 17 行开始的示例:

serviceAccount:
create: false
name: cross-ns-kyuubi

my-kyuubi-values.yaml 文件需要修改的配置项

repository 的内容改成推送到自己 ECR 仓库的 kyuubi-emr-eks 镜像地址:

replicaCount: 2
image:
  repository: 02173xxx.dkr.ecr.us-west-2.amazonaws.com/kyuubi-emr-eks
  tag: "6.15"

spark.kubernetes.container.image 参数修改成和上述一样的 kyuubi-emr-eks 镜像地址

spark.kubernetes.container.image=02173xxx.dkr.ecr.us-west-2.amazonaws.com/kyuubi-emr-eks:6.15

修改 spark.kubernetes.file.upload.path 参数到您的 S3 桶下。

查看 kyuubi namespaces 下的资源

kubectl get all -n kyuubi
NAME           READY   STATUS    RESTARTS   AGE
pod/kyuubi-0   1/1     Running   0          15d
pod/kyuubi-1   1/1     Running   0          134m

NAME                           TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)                                  AGE
service/kyuubi-headless        ClusterIP   None             <none>        3309/TCP,10099/TCP,10009/TCP,10010/TCP   16d
service/kyuubi-rest            ClusterIP   10.100.88.166    <none>        10099/TCP                                16d
service/kyuubi-thrift-binary   ClusterIP   10.100.239.139   <none>        10009/TCP                                16d

NAME                      READY   AGE
statefulset.apps/kyuubi   2/2     16d


kubectl describe rolebinding kyuubi-emr -n emr
Name:         kyuubi-emr
............
Role:
  Kind:  Role
  Name:  kyuubi-emr
Subjects:
  Kind            Name             Namespace
  ----            ----             ---------
  ServiceAccount  cross-ns-kyuubi  kyuubi

功能验证

1. 登录 Kyuubi Server

kubectl exec -it pod/kyuubi-0 -n kyuubi -- bash

1.1 从 Kyuubi Server 提交任务到 EMR on EKS namespace

/usr/lib/spark/bin/spark-submit \
--master k8s://https://kubernetes.default.svc:443 \
--deploy-mode cluster \
--class org.apache.spark.examples.SparkPi \
--conf spark.executor.instances=5 \
 local:///usr/lib/spark/examples/jars/spark-examples.jar 100

查看 SparkPi 的资源运行情况

kubectl get pod -namespace emr -w
NAME                                                        READY   STATUS    RESTARTS   AGE
org-apache-spark-examples-sparkpi-1dc1958e8b4c5001-driver   1/1     Running   0          8s
spark-pi-0672778e8b4c63ed-exec-1                            1/1     Running   0          3s
spark-pi-0672778e8b4c63ed-exec-2                            1/1     Running   0          3s
spark-pi-0672778e8b4c63ed-exec-3                            1/1     Running   0          3s
spark-pi-0672778e8b4c63ed-exec-4                            1/1     Running   0          3s
spark-pi-0672778e8b4c63ed-exec-5                            1/1     Running   0          3s

1.2 通过 Thrift(HiveServer2 Compatible)连接到 Kyuubi

./bin/beeline -u 'jdbc:hive2://kyuubi-0.kyuubi-headless.kyuubi.svc.cluster.local:10009?spark.app.name=testdelta' -n hadoop

成功连接后,可以进行简单的 SQL 验证。

查看库:

0: jdbc:hive2://kyuubi-thrift-binary.kyuubi:10009> show databases;

查看表:

0: jdbc:hive2://kyuubi-0.kyuubi- headless.kyuu>SHOW TABLES IN ods;

查询数据:

select * from customer limit 10;

配置 Hue 访问 Kyuubi

本文使用 EMR(on EC2)的 Hue 访问 EKS 部署的 Kyuubi(也可进行额外搭建Hue)。首先给 Kyuubi 配置一个负载均衡器,用来建立公网访问方式。

cat <<EOF > kyuubi-loadbalance.yaml
apiVersion: v1
kind: Service
metadata:
  name: kyuubi-loadbalance
  namespace: kyuubi
spec:
  ports:
  - name: thrift-binary
    port: 10009
    protocol: TCP
    targetPort: 10009
  selector:
    app.kubernetes.io/instance: kyuubi
    app.kubernetes.io/name: kyuubi
  type: LoadBalancer
EOF

kubectl apply -f kyuubi-loadbalance.yaml -n kyuubi
kubectl get svc -n kyuubi

SSH 到 EMR on EC2 的 master node 更新 Hue 的 Spark 访问配置(/etc/hue/conf/hue.ini),将 sql_server_host 的地址配置为负载均衡器的地址,将 sql_server_port 配置为 10009。

重启 Hue 服务

sudo systemctl restart hue

访问 Hue 的 SparkSql 时会出现异常

此时 Spark driver 的 pod 状态如下图所示

进一步查看 spark driver pod 的 log 会发现如下错误信息

针对上述问题,kyuubi 官方提供了 kyuubi.kubernetes.spark.forciblyRewriteDriverPodName.enabled 和 kyuubi.kubernetes.spark.forciblyRewriteExecutorPodNamePrefix.enabled 两个参数来解决,具体描述请参考配置介绍。这两个参数是在 Kyuubi 1.8.1 版本开始支持。

更新为

kyuubi.kubernetes.spark.forciblyRewriteDriverPodName.enabled true
kyuubi.kubernetes.spark.forciblyRewriteExecutorPodNamePrefix.enabled true

完成后,再次访问 Hue 的 SparkSql 页面,可以正常加载 database 信息:

查询数据:

select * from customer limit 10;

总结

本文探讨了如何将 Apache Kyuubi 和 EMR on EKS 结合,发掘其在数据处理和分析领域的潜力。通过将它们结合起来,我们可以利用 Kyuubi 作为统一的多租户 JDBC 接口,同时充分发挥 EMR on EKS 在大规模数据处理和分析方面的优势。这种结合不仅仅能够提供更强大、更灵活的数据分析平台,同时也为企业提供了更高效的解决方案。

本篇作者

张尹

亚马逊云科技技术客户经理,负责企业级客户的架构和成本优化、技术支持等工作。有多年的大数据架构设计,数仓建模等实战经验。在加入 AWS 之前,长期负责头部电商大数据平台架构设计、数仓建模、运维等相关工作。

Sunny Fang

亚马逊云科技资深数据分析产品经理,负责亚马逊云科技战略客户的云上数据分析体验,并专注在大数据容器化技术方向的产品定位,推广和项目落地。在加入亚马逊云科技之前,曾就职于 Citrix 和微软等科技公司,拥有 10 年以上虚拟化与公有云领域的大数据,机器学习和容器等技术方向的架构优化和技术支持经验。

施俊

亚马逊云科技解决方案架构师,主要负责数字金融客户和企业级客户在亚马逊云科技上的架构设计与实施。10+年金融软件研发和机器学习经验。