本文介绍Spark On K8s的环境准备工作,并通过一个示例来演示如何提交Spark程序到K8s运行。

一、环境准备

首先,本门课程使用的Spark版本为v3.2.3版本,Spark 3.x是当前主流在用的版本,它相比Spark 2.x增加了很多新功能新特性,性能也有大幅的提升。
其次,在实际应用中,为了规范Spark程序在K8s上的运行部署,通常将Spark的程序调度到指定的Namespace中,并使用特定的ServiceAccount运行。
在K8s运行一个Spark程序,通常会伴随创建Pod、Deployment、Service等各种K8s资源,为了确保Spark的ServiceAccount有权限创建这些资源,还需要创建相应的Role和RoleBinding、以及ClusterRole和ClusterRoleBinding,有关这些概念涉及K8s的RBAC授权认证规则,在这里就不做过多的说明,大家可以到K8s的官网进行详细查阅。

1、获取Spark安装包文件

(1)使用wget命令下载Spark v3.2.3安装包文件。
wget https://archive.apache.org/dist/spark/spark-3.2.3/spark-3.2.3-bin-hadoop3.2.tgz
(2)解压并重命名
tar -zxvf spark-3.2.3-bin-hadoop3.2.tgz -C /opt/module
mv spark-3.2.3-bin-hadoop3.2 spark-3.2.3

2、初始化K8s环境

在实践本文的实验之前,需要提前准备好K8s集群环境。关于如何搭建K8s集群,可以到 bigdataonk8s.com 观看相关视频,此外,该网站也提供了高可用K8s集群虚拟机镜像文件,可以直接下载导入使用,省去重头安装的工作。
(1)创建Spark Namespace
编写spark-namespace.yaml
vi spark-namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: apache-spark
  labels:
    app.kubernetes.io/name: apache-spark
    app.kubernetes.io/instance: apache-spark
提交yaml创建namespace
kubectl apply -f spark-namespace.yaml
查看namespace
kubectl get ns
(2)创建ServiceAccount
编写spark-service-account.yaml
vi spark-service-account.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  namespace: apache-spark
  name: spark-service-account
  labels:
    app.kubernetes.io/name: apache-spark
    app.kubernetes.io/instance: apache-spark
    app.kubernetes.io/version: v3.2.3
提交yaml创建ServiceAccount
kubectl apply -f spark-service-account.yaml
查看ServiceAccount
kubectl get sa -n apache-spark
(3)创建Role和RoleBinding
编写spark-role.yaml
vi spark-role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  labels:
    app.kubernetes.io/name: apache-spark
    app.kubernetes.io/instance: apache-spark
    app.kubernetes.io/version: v3.2.3
  namespace: apache-spark
  name: spark-role
rules:
  - apiGroups: [""]
    resources: ["pods"]
    verbs: ["get", "watch", "list", "create", "delete"]
  - apiGroups: ["extensions", "apps"]
    resources: ["deployments"]
    verbs: ["get", "watch", "list", "create", "delete"]
  - apiGroups: [""]
    resources: ["configmaps"]
    verbs: ["get", "create", "update", "delete"]
  - apiGroups: [""]
    resources: ["secrets"]
    verbs: ["get"]
  - apiGroups: [""]
    resources: ["services"]
    verbs: ["get", "list", "create", "delete"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  labels:
    app.kubernetes.io/name: apache-spark
    app.kubernetes.io/instance: apache-spark
    app.kubernetes.io/version: v3.2.3
  name: spark-role-binding
  namespace: apache-spark
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: spark-role
subjects:
  - kind: ServiceAccount
    name: spark-service-account
    namespace: apache-spark
提交yaml创建Role和RoleBinding
kubectl apply -f spark-role.yaml
查看Role和RoleBinding
kubectl get role -n apache-spark
kubectl get rolebinding -n apache-spark
(4)创建ClusterRole和ClusterRoleBinding
编写cluster-role.yaml
vi cluster-role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  labels:
    app.kubernetes.io/name: apache-spark
    app.kubernetes.io/instance: apache-spark
    app.kubernetes.io/version: v3.2.3
  name: apache-spark-clusterrole
rules:
  - apiGroups:
      - ''
    resources:
      - configmaps
      - endpoints
      - nodes
      - pods
      - secrets
      - namespaces
    verbs:
      - list
      - watch
      - get
  - apiGroups:
      - ''
    resources:
      - services
    verbs:
      - get
      - list
      - watch
  - apiGroups:
      - ''
    resources:
      - events
    verbs:
      - create
      - patch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  labels:
    app.kubernetes.io/name: apache-spark
    app.kubernetes.io/instance: apache-spark
    app.kubernetes.io/version: v3.2.3
  name: apache-spark-clusterrole-binding
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: apache-spark-clusterrole
subjects:
  - kind: ServiceAccount
    name: spark-service-account
    namespace: apache-spark
提交yaml创建ClusterRole和ClusterRoleBinding
kubectl apply -f cluster-role.yaml
查看ClusterRole和ClusterRoleBinding
kubectl get ClusterRole | grep spark
kubectl get ClusterRoleBinding | grep spark 

二、Spark On K8s基本测试

本次测试,使用Spark自带的示例程序SparkPi,以Cluster模式运行。
1、到Docker Hub查找apache spark的镜像,并拉取到本地
docker pull apache/spark:v3.2.3
如果因为网络原因无法下载镜像,则使用以下镜像
docker pull registry.cn-hangzhou.aliyuncs.com/cm_ns01/apache-spark:v3.2.3
2、查看k8s master的url,获取Kubernetes control plane URL
kubectl cluster-info

3、提交Spark程序到K8s上运行 

/opt/module/spark-3.2.3/bin/spark-submit \
 --name SparkPi \
 --verbose \
 --master k8s://https://master.k8s.io:16443 \
 --deploy-mode cluster \
 --conf spark.network.timeout=300 \
 --conf spark.executor.instances=3 \
 --conf spark.driver.cores=1 \
 --conf spark.executor.cores=1 \
 --conf spark.driver.memory=1024m \
 --conf spark.executor.memory=1024m \
 --conf spark.kubernetes.namespace=apache-spark \
 --conf spark.kubernetes.container.image.pullPolicy=IfNotPresent \
 --conf spark.kubernetes.container.image=registry.cn-hangzhou.aliyuncs.com/cm_ns01/apache-spark:v3.2.3 \
 --conf spark.kubernetes.authenticate.driver.serviceAccountName=spark-service-account \
 --conf spark.kubernetes.authenticate.executor.serviceAccountName=spark-service-account \
 --conf spark.driver.extraJavaOptions="-Dio.netty.tryReflectionSetAccessible=true" \
 --conf spark.executor.extraJavaOptions="-Dio.netty.tryReflectionSetAccessible=true" \
 --class org.apache.spark.examples.SparkPi \
 local:///opt/spark/examples/jars/spark-examples_2.12-3.2.3.jar \
 3000
--master为Kubernetes control plane URL
--deploy-mode为cluster,则driver和executor都运行在K8s里
--conf spark.kubernetes.namespace为前面创建的命名空间apache-spark
--conf spark.kubernetes.container.image为Spark的镜像地址
--conf spark.kubernetes.authenticate.executor.serviceAccountName前面创建的spark-service-account
--class为Spark程序的启动类
local:///opt/spark/examples/jars/spark-examples_2.12-3.2.3.jar为Spark程序所在的Jar文件,spark-examples_2.12-3.2.3.jar是Spark镜像自带的,所以使用local schema
3000是传入Spark程序的启动类的参数
4、观察driver pod和executor pod
watch -n 1 kubectl get all -owide -n apache-spark

可以看到,以cluster模式运行,启动了Driver Pod和3个Executor Pod 。

Spark程序运行结束后,Executor Pod被释放,Driver Pod的状态变为Completed状态,此时的Driver Pod不消耗K8s的计算资源,它的存在只是为了便于查看日志输出。
5、查看日志输出
kubectl logs sparkpi-b9de1a887b1163f1-driver -n apache-spark

6、清理Driver Pod
kubectl delete pod sparkpi-b9de1a887b1163f1-driver -n apache-spark

三、结语

本文只是对Spark On K8s进行简单介绍和演示,希望能起到抛砖引玉的作用。要将Spark On K8s真正应用到生产环境,还需要掌握其他更多的知识,例如Spark日志的持久化、Spark程序的监控,Spark程序的高可靠运行、Spark SQL On K8s以及与Hadoop、S3、JuiceFS和CDH集成等内容,这些内容在 bigdataonk8s.com 里有详细的讲解和说明,大家可以前往观看学习。

 

 

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐