Spark On Kubernetes 的 Web UI 访问实践
本文作者为中国移动云能力中心软件开发工程师洪冬冬,文章详细介绍了不同场景下使用不同的方式实现对 Spark on K8s 的 Web UI 访问实践,供大家参考。
背景
在将 Spark 从 YARN 集群迁移到 Kubernetes 集群的过程中,遇到一个问题,以 Cluster 模式提交任务后,我们该如何访问 Spark Web UI。
在 Kubernetes 中提供了名为 Service 的资源,它是将运行在一组 Pods 上的应用程序公开为网络服务的抽象方法。Service 大致可以分为以下几类:
ClusterIP:默认值,通过集群的内部 IP 暴露服务,选择该值时服务只能够在集群内部访问。
NodePort:将 Service 通过指定的 Node 上的端口暴露给外部,通过此方法,就可以在集群外部访问服务。
LoadBalancer:使用云提供商的负载均衡器向外部暴露服务。外部负载均衡器可以将流量路由到自动创建的 NodePort 服务和 ClusterIP 服务上。
ExternalName:把集群外部的服务引入集群内部,直接使用
在 Kubernetes 中,当 Spark 的 driver pod 启动后,默认会帮我们创建一个 ClusterIP 类型的 service,且当前开源版本中我们无法修改 service 类型。我们可以借助这个 Service,根据使用场景,通过不同的方式来实现对 Web UI 的访问。
实践
1、端口转发
在 Spark 官网示例中(https://spark.apache.org/docs/latest/running-on-kubernetes.html#accessing-driver-ui),使用 Kubernetes 自带的端口转发命令 kubectl port-forward 实现对 Web UI 的访问,具体命令如下:
该命令使用执行命令的宿主机的 4040 端口转发 driver pod 的 4040 端口,我们可以在本地访问宿主机的 4040 端口来实现 Web UI 的访问(需要本地可以连通宿主机)。
2、创建新的 service
由于 Spark 默认创建的是 ClusterIP 类型 service,无法直接在外部访问,我们可以直接为 driver pod 创建一个新的 NodePort/LoadBalancer 类型的 service,以 NodePort 为例,命令如下:
创建完 NodePort 后,可以通过 get service 命令获取对应的端口映射关系。
其中 31231 为映射的外部访问地址,可以通过 Kubernetes 集群中任意宿主机 IP:31231 来访问 Web UI。
3、Ingress
Ingress 是 Kubernetes 中对集群中服务的外部访问进行管理的 API 对象,支持和维护 AWS、 GCE 和 Nginx Ingress 控制器。可以看作是 service 上的 service,工作原理如下:
Ingress 是目前在生产中比较推荐的方案,部分集成 Spark 的开源组件也是通过 ingress 来暴露 Web UI。一个简单的 ingress 模版如下:
成功创建 Ingress 后,我们可以通过 IP:Port/的方式来访问 Spark Web UI。
4、Gateway 配合 spark 反向代理
Spark 在 2.1.0 以后引入了反向代理功能,详见(https://issues.apache.org/jira/browse/SPARK-20044),基于反向代理,我们可以实现对 Spark Web UI 的动态代理。其工作原理如下:
需要在 Spark 中开启 reverseProxy,参数如下:
其中 host:port 为网关服务的入口地址,path 为对应 spark driver 的转发路径,我们可以在应用中对应关系持久化到 mysql/zookeeper 中,便于 gateway 服务动态加载。这种方案依赖外部服务,同时需要对应用改造。通过翻阅文档和源码,spark 支持定义各种资源的前缀字符串,可以设置参数
此时,可以直接推断出 Spark 创建的 ClusterIP 为 prefix-a-driver-svc。通过添加配置,既不会增加外部依赖,也不需要改造应用,可以很方便的实现 gateway 对 spark Web UI 的动态代理。
总结
根据不同的使用场景,我们可以选择不同的方式实现对 Web UI 的访问,在 gateway 配合 Spark 反向代理方案的使用过程中,我们也遇到了性能和转发方面的问题。后续,将进一步探索 Nginx ingress 的方案,实现基于原生组件的动态代理功能。
评论