Kubernetes助力Spark大數據分析
- 2019 年 12 月 11 日
- 筆記
Kubernetes 作為一個廣受歡迎的開源容器協調系統,是Google於2014年醞釀的項目。從Google趨勢上看到,Kubernetes自2014年以來熱度一路飆升,短短几年時間就已超越了大數據分析領域的長老Hadoop。本公眾號之前的文章(Kubernetes核心組件解析)也對Kubernetes的幾個組件做了一些詳細的剖析,本文就帶領大家一起看看Kubernetes和Spark碰到一起會擦出什麼樣的火花。

Spark2.3.0之前的版本只原生支援Standalone、YARN和Mesos三種部署模式,也就是說要遷移Spark2.3.0之前的Spark到Kuberbetes上,還得準備一層Standalone、YARN或者Mesos環境,不過Spark2.3.0已經引入了對Kubernetes的原生支援。

Spark2.3.0可以將編寫好的數據處理程式直接通過spark-submit提交到Kubernetes集群,通過創建一個Drive Pod和一系列Executor Pods,然後共同協調完成計算任務,整體過程的官方示意圖如下。

當我們通過spark-submit將Spark作業提交到Kubernetes集群時,會執行以下流程:
1. Spark在Kubernetes Pod中創建Spark Driver
2. Driver調用Kubernetes API創建ExecutorPods,Executor Pods執行作業程式碼
3. 計算作業結束,Executor Pods回收並清理
4. Driver Pod處於completed狀態,保留日誌,直到Kubernetes GC或者手動清理
Spark原生支援Kubernetes最大的好處是,不用在Kubernetes集群上再建立一層資源調度系統,只要建立一個新Spark容器鏡像,並指派合適的RBAC許可權角色,給所要執行的Spark應用程式,就可以在Kubernetes集群上運行Spark程式了。
接下來就介紹如何在一個Kubernetes上運行Spark程式。
1前提條件
(1) 我們測試的是Spark 2.3.0,由於Spark on Kubernetes任務提交後,實際上在集群中是以custom resources和custom controller的形式運行,所以我們需要一個1.7+版本的k8s集群,同時需要啟動Kubernetes DNS和RBAC。
(2) Spark2.3.0版本的二進位包,下載鏈接https://archive.apache.org/dist/spark/spark-2.3.0/spark-2.3.0-bin-hadoop2.6.tgz
2打包製作Spark鏡像
(1) 解壓並進入到解壓後的Spark安裝文件路徑
$ tar -zxvf spark-2.3.0-bin-hadoop2.6
$ cd spark-2.3.0-bin-hadoop2.6
(2) 製作Spark基礎鏡像
- 使用Spark提供的docker-image-tool.sh腳本製作
$ ./bin/docker-image-tool.sh -r <repo> -t my-tag build
$ ./bin/docker-image-tool.sh -r <repo> -t my-tag push
- 使用docker build命令製作
$ docker build -t registry/spark:2.3.0 -f kubernetes/dockerfiles/spark/Dockerfile .
(3) 查看鏡像
$ docker images | grep registry/spark
3運行Spark官方例子
(1) 獲取集群資訊,確認Kubernetes master地址
$ kubectl cluster-info

(2) 為Spark創建一個RBAC的role
$ kubectl create serviceaccount spark
$ kubectl create clusterrolebinding spark-role –clusterrole=edit –serviceaccount=default:spark –namespace=default
(3) 運行如下命令,向Kubernetes集群提交計算π值的例子
$/spark-2.3.0-bin-hadoop2.6/bin/spark-submit
–master k8s://k8s-master
–deploy-mode cluster
–name spark-pi
–class org.apache.spark.examples.SparkPi
–conf spark.kubernetes.authenticate.driver.serviceAccountName=spark
–conf spark.executor.instances=2
–conf spark.kubernetes.container.image=registry/spark:2.3.0
local:///opt/spark/examples/jars/spark-examples_2.11-2.3.0.jar

(4) 查看運行狀態,計算π值的例子運行很快,可以看到它已經運行結束了
$ kubectl get po

(5) 查看運行日誌,可以看到π值已經計算出來了
$ kubectl logs -f spark-pi-63abb54cf382394d95413f43744c65ed-Drive

至此,使用官方的例子體驗Spark on Kubernetes就完成了。那麼,如何提交自己編寫的Spark程式到Kubernetes集群呢?
其實只需把自己寫好的Spark程式編譯成jar文件,然後打包到Spark基礎鏡像中,就可以提交到Kubernetes集群中運行了。
4運行自己編寫的Spark程式
(1)準備源程式碼。以一個wordcount程式為例。程式會從一個小說網站下載《了不起的蓋茨比》的英文版小說,然後對其做詞頻統計,源程式碼如下:
import org.apache.commons.io.IOUtils import org.apache.spark.sql.functions._ import java.net.URL import org.apache.spark.sql.SparkSession class WordCount { def main(args: Array[String]) { val spark = SparkSession .builder .appName("CopyData") .getOrCreate() import spark.implicits._ val bankText = spark.sparkContext.parallelize( IOUtils.toString( new URL("http://novel.tingroom.com/novel_down.php?aid=319&dopost=txt") ).split("n")) bankText.flatMap(p=>{ val pattern = "[^a-zA-Z0-9-']".r val line = pattern.replaceAllIn(p," ") line.split(" ") }).map((_,1)).reduceByKey(_+_).sortBy(p=>p._2,false).toDF("word","count"). where(length('word)>4).show } }
(2) 源程式碼編譯為wordcount.jar文件,並編寫Dockerfile文件,內容如下:
FROM registry/spark:2.3.0
RUN mkdir -p /opt/spark/jars
COPY wordcount.jar /opt/spark/jars
(3)wordcount.jar和DockerFlie文件放在同一路徑下,並在該路徑下運行docker bulid命令打包鏡像:
$docker build -t registry/spark_wordcount:latest -f Dockerfile .
(4)使用如下命令將wordcount程式提交到Kubernetes集群:
/home/nsfocus/dengxincheng/spark-2.3.1-bin-hadoop2.6/bin/spark-submit
–master k8s://192.168.19.13:6443
–deploy-mode cluster
–name wordcount
–class example.wordcount.WordCount
–conf spark.kubernetes.authenticate.driver.serviceAccountName=spark
–conf spark.executor.instances=2
–conf spark.kubernetes.container.image=registry/spark_wordcount:latest
local:///opt/spark/jars/wordcount.jar
(5)當任務運行完了之後,使用kubectl logs查看wordcount程式運行所對應drive pod內的日誌,可以得詞頻最高的前20個詞,如下圖。

5總結
新版的Spark加入對Kubernetes的原生支援,統一了Spark程式在Kubernetes上所有工作負載的控制層,這樣可以簡化群集管理並提高資源利用率。總的來說,使用Kubernetes原生調度的Spark主要有以下優點:
原生資源調度:不再需要二級調度,直接使用Kubernetes原生的調度模組,實現與其他應用的混布;
資源隔離:任務可以提交到指定的namespace,這樣可以復用Kubernetes原生的qouta限制,實現任務資源的限制;
用戶自定義:用戶可以在Spark基礎鏡像中打上自己的Application, 更加靈活和方便;
內容編輯:安全大數據分析實驗室 鄧新程 責任編輯:肖晴