<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                # 運行支持kubernetes原生調度的Spark程序 TL;DR 這個主題比較大,該開源項目也還在不斷進行中,我單獨做了一個 web 用來記錄 spark on kubernetes 的研究和最新進展見: https://jimmysong.io/spark-on-k8s **注意**:本文中的鏡像倉庫地址 `harbor-001.jimmysong.io` 為的鏡像倉庫地址為偽裝地址,非本文中真正使用的鏡像倉庫,且該地址也不存在,請替換為您自己的鏡像倉庫。 我們之前就在 kubernetes 中運行過 standalone 方式的 spark 集群,見 [Spark standalone on kubernetes](spark-standalone-on-kubernetes.md)。 目前運行支持 kubernetes 原生調度的 spark 程序由 Google 主導,fork 自 spark 的官方代碼庫,見https://github.com/apache-spark-on-k8s/spark/ ,屬于Big Data SIG。 參與到該項目的公司有: - Bloomberg - Google - Haiwen - Hyperpilot - Intel - Palantir - Pepperdata - Red Hat ## 為何使用 spark on kubernetes 使用kubernetes原生調度的spark on kubernetes是對現有的spark on yarn/mesos的資源使用方式的革命性的改進,主要表現在以下幾點: 1. Kubernetes原生調度:不再需要二層調度,直接使用kubernetes的資源調度功能,跟其他應用共用整個kubernetes管理的資源池; 2. 資源隔離,粒度更細:原先yarn中的queue在spark on kubernetes中已不存在,取而代之的是kubernetes中原生的namespace,可以為每個用戶分別指定一個namespace,限制用戶的資源quota; 3. 細粒度的資源分配:可以給每個spark任務指定資源限制,實際指定多少資源就使用多少資源,因為沒有了像yarn那樣的二層調度(圈地式的),所以可以更高效和細粒度的使用資源; 4. 監控的變革:因為做到了細粒度的資源分配,所以可以對用戶提交的每一個任務做到資源使用的監控,從而判斷用戶的資源使用情況,所有的metric都記錄在數據庫中,甚至可以為每個用戶的每次任務提交計量; 5. 日志的變革:用戶不再通過yarn的web頁面來查看任務狀態,而是通過pod的log來查看,可將所有的kuberentes中的應用的日志等同看待收集起來,然后可以根據標簽查看對應應用的日志; 所有這些變革都可以讓我們更高效的獲取資源、更有效率的獲取資源! ## Spark 概念說明 [Apache Spark](http://spark.apache.org) 是一個圍繞速度、易用性和復雜分析構建的大數據處理框架。最初在2009年由加州大學伯克利分校的AMPLab開發,并于2010年成為Apache的開源項目之一。 在 Spark 中包括如下組件或概念: - **Application**:Spark Application 的概念和 Hadoop 中的 MapReduce 類似,指的是用戶編寫的 Spark 應用程序,包含了一個 Driver 功能的代碼和分布在集群中多個節點上運行的 Executor 代碼; - **Driver**:Spark 中的 Driver 即運行上述 Application 的 main() 函數并且創建 SparkContext,其中創建 SparkContext 的目的是為了準備Spark應用程序的運行環境。在 Spark 中由 SparkContext 負責和 ClusterManager 通信,進行資源的申請、任務的分配和監控等;當 Executor 部分運行完畢后,Driver負責將SparkContext 關閉。通常用 SparkContext 代表 Driver; - **Executor**:Application運行在Worker 節點上的一個進程,該進程負責運行Task,并且負責將數據存在內存或者磁盤上,每個Application都有各自獨立的一批Executor。在Spark on Yarn模式下,其進程名稱為`CoarseGrainedExecutorBackend`,類似于 Hadoop MapReduce 中的 YarnChild。一個 `CoarseGrainedExecutorBackend` 進程有且僅有一個 executor 對象,它負責將 Task 包裝成 taskRunner,并從線程池中抽取出一個空閑線程運行 Task。每個 `CoarseGrainedExecutorBackend` 能并行運行 Task 的數量就取決于分配給它的 CPU 的個數了; - **Cluster Manager**:指的是在集群上獲取資源的外部服務,目前有: - Standalone:Spark原生的資源管理,由Master負責資源的分配; - Hadoop Yarn:由YARN中的ResourceManager負責資源的分配; - **Worker**:集群中任何可以運行Application代碼的節點,類似于YARN中的NodeManager節點。在Standalone模式中指的就是通過Slave文件配置的Worker節點,在Spark on Yarn模式中指的就是NodeManager節點; - **作業(Job)**:包含多個Task組成的并行計算,往往由Spark Action催生,一個JOB包含多個RDD及作用于相應RDD上的各種Operation; - **階段(Stage)**:每個Job會被拆分很多組 Task,每組任務被稱為Stage,也可稱TaskSet,一個作業分為多個階段,每一個stage的分割點是action。比如一個job是:(transformation1 -> transformation1 -> action1 -> transformation3 -> action2),這個job就會被分為兩個stage,分割點是action1和action2。 - **任務(Task)**: 被送到某個Executor上的工作任務; - **Context**:啟動spark application的時候創建,作為Spark 運行時環境。 - **Dynamic Allocation(動態資源分配)**:一個配置選項,可以將其打開。從Spark1.2之后,對于On Yarn模式,已經支持動態資源分配(Dynamic Resource Allocation),這樣,就可以根據Application的負載(Task情況),動態的增加和減少executors,這種策略非常適合在YARN上使用spark-sql做數據開發和分析,以及將spark-sql作為長服務來使用的場景。Executor 的動態分配需要在 cluster mode 下啟用 "external shuffle service"。 - **動態資源分配策略**:開啟動態分配策略后,application會在task因沒有足夠資源被掛起的時候去動態申請資源,這意味著該application現有的executor無法滿足所有task并行運行。spark一輪一輪的申請資源,當有task掛起或等待 `spark.dynamicAllocation.schedulerBacklogTimeout` (默認1s)時間的時候,會開始動態資源分配;之后會每隔 `spark.dynamicAllocation.sustainedSchedulerBacklogTimeout` (默認1s)時間申請一次,直到申請到足夠的資源。每次申請的資源量是指數增長的,即1,2,4,8等。之所以采用指數增長,出于兩方面考慮:其一,開始申請的少是考慮到可能application會馬上得到滿足;其次要成倍增加,是為了防止application需要很多資源,而該方式可以在很少次數的申請之后得到滿足。 ## 架構設計 關于 spark standalone 的局限性與 kubernetes native spark 架構之間的區別請參考 Anirudh Ramanathan 在 2016年10月8日提交的 issue [Support Spark natively in Kubernetes #34377](https://github.com/kubernetes/kubernetes/issues/34377)。 簡而言之,spark standalone on kubernetes 有如下幾個缺點: - 無法對于多租戶做隔離,每個用戶都想給 pod 申請 node 節點可用的最大的資源。 - Spark 的 master/worker 本來不是設計成使用 kubernetes 的資源調度,這樣會存在兩層的資源調度問題,不利于與 kuberentes 集成。 而 kubernetes native spark 集群中,spark 可以調用 kubernetes API 獲取集群資源和調度。要實現 kubernetes native spark 需要為 spark 提供一個集群外部的 manager 可以用來跟 kubernetes API 交互。 ### 調度器后臺 使用 kubernetes 原生調度的 spark 的基本設計思路是將 spark 的 driver 和 executor 都放在 kubernetes 的 pod 中運行,另外還有兩個附加的組件:`ResourceStagingServer` 和 `KubernetesExternalShuffleService`。 Spark driver 其實可以運行在 kubernetes 集群內部(cluster mode)可以運行在外部(client mode),executor 只能運行在集群內部,當有 spark 作業提交到 kubernetes 集群上時,調度器后臺將會為 executor pod 設置如下屬性: - 使用我們預先編譯好的包含 kubernetes 支持的 spark 鏡像,然后調用 `CoarseGrainedExecutorBackend` main class 啟動 JVM。 - 調度器后臺為 executor pod 的運行時注入環境變量,例如各種 JVM 參數,包括用戶在 `spark-submit` 時指定的那些參數。 - Executor 的 CPU、內存限制根據這些注入的環境變量保存到應用程序的 `SparkConf` 中。 - 可以在配置中指定 spark 運行在指定的 namespace 中。 參考:[Scheduler backend 文檔](https://github.com/apache-spark-on-k8s/spark/blob/branch-2.2-kubernetes/resource-managers/kubernetes/architecture-docs/scheduler-backend.md) ## 安裝指南 我們可以直接使用官方已編譯好的 docker 鏡像來部署,下面是官方發布的鏡像: | 組件 | 鏡像 | | -------------------------- | ---------------------------------------- | | Spark Driver Image | `kubespark/spark-driver:v2.1.0-kubernetes-0.3.1` | | Spark Executor Image | `kubespark/spark-executor:v2.1.0-kubernetes-0.3.1` | | Spark Initialization Image | `kubespark/spark-init:v2.1.0-kubernetes-0.3.1` | | Spark Staging Server Image | `kubespark/spark-resource-staging-server:v2.1.0-kubernetes-0.3.1` | | PySpark Driver Image | `kubespark/driver-py:v2.1.0-kubernetes-0.3.1` | | PySpark Executor Image | `kubespark/executor-py:v2.1.0-kubernetes-0.3.1` | 我將這些鏡像放到了我的私有鏡像倉庫中了。 還需要安裝支持 kubernetes 的 spark 客戶端,在這里下載:https://github.com/apache-spark-on-k8s/spark/releases 根據使用的鏡像版本,我下載的是 [v2.1.0-kubernetes-0.3.1](https://github.com/apache-spark-on-k8s/spark/releases/tag/v2.1.0-kubernetes-0.3.1) **運行 SparkPi 測試** 我們將任務運行在 `spark-cluster` 的 namespace 中,啟動 5 個 executor 實例。 ```bash ./bin/spark-submit \ --deploy-mode cluster \ --class org.apache.spark.examples.SparkPi \ --master k8s://https://172.20.0.113:6443 \ --kubernetes-namespace spark-cluster \ --conf spark.executor.instances=5 \ --conf spark.app.name=spark-pi \ --conf spark.kubernetes.driver.docker.image=harbor-001.jimmysong.io/library/kubespark-spark-driver:v2.1.0-kubernetes-0.3.1 \ --conf spark.kubernetes.executor.docker.image=harbor-001.jimmysong.io/library/kubespark-spark-executor:v2.1.0-kubernetes-0.3.1 \ --conf spark.kubernetes.initcontainer.docker.image=harbor-001.jimmysong.io/library/kubespark-spark-init:v2.1.0-kubernetes-0.3.1 \ local:///opt/spark/examples/jars/spark-examples_2.11-2.1.0-k8s-0.3.1-SNAPSHOT.jar ``` 關于該命令參數的介紹請參考:https://apache-spark-on-k8s.github.io/userdocs/running-on-kubernetes.html **注意:** 該 jar 包實際上是 `spark.kubernetes.executor.docker.image` 鏡像中的。 這時候提交任務運行還是失敗,報錯信息中可以看到兩個問題: - Executor 無法找到 driver pod - 用戶 `system:serviceaccount:spark-cluster:defaul` 沒有權限獲取 `spark-cluster` 中的 pod 信息。 提了個 issue [Failed to run the sample spark-pi test using spark-submit on the doc #478](https://github.com/apache-spark-on-k8s/spark/issues/478) 需要為 spark 集群創建一個 `serviceaccount` 和 `clusterrolebinding`: ```bash kubectl create serviceaccount spark --namespace spark-cluster kubectl create rolebinding spark-edit --clusterrole=edit --serviceaccount=spark-cluster:spark --namespace=spark-cluster ``` 該 Bug 將在新版本中修復。 ## 用戶指南 ### 編譯 Fork 并克隆項目到本地: ```bash git clone https://github.com/rootsongjc/spark.git ``` 編譯前請確保你的環境中已經安裝 Java8 和 Maven3。 ```bash ## 第一次編譯前需要安裝依賴 build/mvn install -Pkubernetes -pl resource-managers/kubernetes/core -am -DskipTests ## 編譯 spark on kubernetes build/mvn compile -Pkubernetes -pl resource-managers/kubernetes/core -am -DskipTests ## 發布 dev/make-distribution.sh --tgz -Phadoop-2.7 -Pkubernetes ``` 第一次編譯和發布的過程耗時可能會比較長,請耐心等待,如果有依賴下載不下來,請自備梯子。 詳細的開發指南請見:https://github.com/apache-spark-on-k8s/spark/blob/branch-2.2-kubernetes/resource-managers/kubernetes/README.md ### 構建鏡像 使用該腳本來自動構建容器鏡像:https://github.com/apache-spark-on-k8s/spark/pull/488 將該腳本放在 `dist` 目錄下,執行: ```bash ./build-push-docker-images.sh -r harbor-001.jimmysong.io/library -t v2.1.0-kubernetes-0.3.1-1 build ./build-push-docker-images.sh -r harbor-001.jimmysong.io/library -t v2.1.0-kubernetes-0.3.1-1 push ``` **注意:**如果你使用的 MacOS,bash 的版本可能太低,執行改腳本將出錯,請檢查你的 bash 版本: ```bash bash --version GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin16) Copyright (C) 2007 Free Software Foundation, Inc. ``` 上面我在升級 bash 之前獲取的版本信息,使用下面的命令升級 bash: ```bash brew install bash ``` 升級后的 bash 版本為 `4.4.12(1)-release (x86_64-apple-darwin16.3.0)`。 編譯并上傳鏡像到我的私有鏡像倉庫,將會構建出如下幾個鏡像: ```bash harbor-001.jimmysong.io/library/spark-driver:v2.1.0-kubernetes-0.3.1-1 harbor-001.jimmysong.io/library/spark-resource-staging-server:v2.1.0-kubernetes-0.3.1-1 harbor-001.jimmysong.io/library/spark-init:v2.1.0-kubernetes-0.3.1-1 harbor-001.jimmysong.io/library/spark-shuffle:v2.1.0-kubernetes-0.3.1-1 harbor-001.jimmysong.io/library/spark-executor:v2.1.0-kubernetes-0.3.1-1 harbor-001.jimmysong.io/library/spark-executor-py:v2.1.0-kubernetes-0.3.1-1 harbor-001.jimmysong.io/library/spark-driver-py:v2.1.0-kubernetes-0.3.1-1 ``` ## 運行測試 在 `dist/bin` 目錄下執行 spark-pi 測試: ```bash ./spark-submit \ --deploy-mode cluster \ --class org.apache.spark.examples.SparkPi \ --master k8s://https://172.20.0.113:6443 \ --kubernetes-namespace spark-cluster \ --conf spark.kubernetes.authenticate.driver.serviceAccountName=spark \ --conf spark.executor.instances=5 \ --conf spark.app.name=spark-pi \ --conf spark.kubernetes.driver.docker.image=harbor-001.jimmysong.io/library/spark-driver:v2.1.0-kubernetes-0.3.1-1 \ --conf spark.kubernetes.executor.docker.image=harbor-001.jimmysong.io/library/spark-executor:v2.1.0-kubernetes-0.3.1-1 \ --conf spark.kubernetes.initcontainer.docker.image=harbor-001.jimmysong.io/library/spark-init:v2.1.0-kubernetes-0.3.1-1 \ local:///opt/spark/examples/jars/spark-examples_2.11-2.2.0-k8s-0.4.0-SNAPSHOT.jar ``` 詳細的參數說明見:https://apache-spark-on-k8s.github.io/userdocs/running-on-kubernetes.html **注意:**`local:///opt/spark/examples/jars/spark-examples_2.11-2.2.0-k8s-0.4.0-SNAPSHOT.jar` 文件是在 `spark-driver` 和 `spark-executor` 鏡像里的,在上一步構建鏡像時已經構建并上傳到了鏡像倉庫中。 執行日志顯示: ```bash 2017-09-14 14:59:01 INFO Client:54 - Waiting for application spark-pi to finish... 2017-09-14 14:59:01 INFO LoggingPodStatusWatcherImpl:54 - State changed, new state: pod name: spark-pi-1505372339796-driver namespace: spark-cluster labels: spark-app-selector -> spark-f4d3a5d3ad964a05a51feb6191d50357, spark-role -> driver pod uid: 304cf440-991a-11e7-970c-f4e9d49f8ed0 creation time: 2017-09-14T06:59:01Z service account name: spark volumes: spark-token-zr8wv node name: N/A start time: N/A container images: N/A phase: Pending status: [] 2017-09-14 14:59:01 INFO LoggingPodStatusWatcherImpl:54 - State changed, new state: pod name: spark-pi-1505372339796-driver namespace: spark-cluster labels: spark-app-selector -> spark-f4d3a5d3ad964a05a51feb6191d50357, spark-role -> driver pod uid: 304cf440-991a-11e7-970c-f4e9d49f8ed0 creation time: 2017-09-14T06:59:01Z service account name: spark volumes: spark-token-zr8wv node name: 172.20.0.114 start time: N/A container images: N/A phase: Pending status: [] 2017-09-14 14:59:01 INFO LoggingPodStatusWatcherImpl:54 - State changed, new state: pod name: spark-pi-1505372339796-driver namespace: spark-cluster labels: spark-app-selector -> spark-f4d3a5d3ad964a05a51feb6191d50357, spark-role -> driver pod uid: 304cf440-991a-11e7-970c-f4e9d49f8ed0 creation time: 2017-09-14T06:59:01Z service account name: spark volumes: spark-token-zr8wv node name: 172.20.0.114 start time: 2017-09-14T06:59:01Z container images: harbor-001.jimmysong.io/library/spark-driver:v2.1.0-kubernetes-0.3.1-1 phase: Pending status: [ContainerStatus(containerID=null, image=harbor-001.jimmysong.io/library/spark-driver:v2.1.0-kubernetes-0.3.1-1, imageID=, lastState=ContainerState(running=null, terminated=null, waiting=null, additionalProperties={}), name=spark-kubernetes-driver, ready=false, restartCount=0, state=ContainerState(running=null, terminated=null, waiting=ContainerStateWaiting(message=null, reason=ContainerCreating, additionalProperties={}), additionalProperties={}), additionalProperties={})] 2017-09-14 14:59:03 INFO LoggingPodStatusWatcherImpl:54 - State changed, new state: pod name: spark-pi-1505372339796-driver namespace: spark-cluster labels: spark-app-selector -> spark-f4d3a5d3ad964a05a51feb6191d50357, spark-role -> driver pod uid: 304cf440-991a-11e7-970c-f4e9d49f8ed0 creation time: 2017-09-14T06:59:01Z service account name: spark volumes: spark-token-zr8wv node name: 172.20.0.114 start time: 2017-09-14T06:59:01Z container images: harbor-001.jimmysong.io/library/spark-driver:v2.1.0-kubernetes-0.3.1-1 phase: Running status: [ContainerStatus(containerID=docker://5c5c821c482a1e35552adccb567020532b79244392374f25754f0050e6cd4c62, image=harbor-001.jimmysong.io/library/spark-driver:v2.1.0-kubernetes-0.3.1-1, imageID=docker-pullable://harbor-001.jimmysong.io/library/spark-driver@sha256:beb92a3e3f178e286d9e5baebdead88b5ba76d651f347ad2864bb6f8eda26f94, lastState=ContainerState(running=null, terminated=null, waiting=null, additionalProperties={}), name=spark-kubernetes-driver, ready=true, restartCount=0, state=ContainerState(running=ContainerStateRunning(startedAt=2017-09-14T06:59:02Z, additionalProperties={}), terminated=null, waiting=null, additionalProperties={}), additionalProperties={})] 2017-09-14 14:59:12 INFO LoggingPodStatusWatcherImpl:54 - State changed, new state: pod name: spark-pi-1505372339796-driver namespace: spark-cluster labels: spark-app-selector -> spark-f4d3a5d3ad964a05a51feb6191d50357, spark-role -> driver pod uid: 304cf440-991a-11e7-970c-f4e9d49f8ed0 creation time: 2017-09-14T06:59:01Z service account name: spark volumes: spark-token-zr8wv node name: 172.20.0.114 start time: 2017-09-14T06:59:01Z container images: harbor-001.jimmysong.io/library/spark-driver:v2.1.0-kubernetes-0.3.1-1 phase: Succeeded status: [ContainerStatus(containerID=docker://5c5c821c482a1e35552adccb567020532b79244392374f25754f0050e6cd4c62, image=harbor-001.jimmysong.io/library/spark-driver:v2.1.0-kubernetes-0.3.1-1, imageID=docker-pullable://harbor-001.jimmysong.io/library/spark-driver@sha256:beb92a3e3f178e286d9e5baebdead88b5ba76d651f347ad2864bb6f8eda26f94, lastState=ContainerState(running=null, terminated=null, waiting=null, additionalProperties={}), name=spark-kubernetes-driver, ready=false, restartCount=0, state=ContainerState(running=null, terminated=ContainerStateTerminated(containerID=docker://5c5c821c482a1e35552adccb567020532b79244392374f25754f0050e6cd4c62, exitCode=0, finishedAt=2017-09-14T06:59:11Z, message=null, reason=Completed, signal=null, startedAt=null, additionalProperties={}), waiting=null, additionalProperties={}), additionalProperties={})] 2017-09-14 14:59:12 INFO LoggingPodStatusWatcherImpl:54 - Container final statuses: Container name: spark-kubernetes-driver Container image: harbor-001.jimmysong.io/library/spark-driver:v2.1.0-kubernetes-0.3.1-1 Container state: Terminated Exit code: 0 2017-09-14 14:59:12 INFO Client:54 - Application spark-pi finished. ``` 從日志中可以看到任務運行的狀態信息。 使用下面的命令可以看到 kubernetes 啟動的 Pod 信息: ```bash kubectl --namespace spark-cluster get pods -w ``` 將會看到 `spark-driver` 和 `spark-exec` 的 Pod 信息。 ## 依賴管理 上文中我們在運行測試程序時,命令行中指定的 jar 文件已包含在 docker 鏡像中,是不是說我們每次提交任務都需要重新創建一個鏡像呢?非也!如果真是這樣也太麻煩了。 #### 創建 resource staging server 為了方便用戶提交任務,不需要每次提交任務的時候都創建一個鏡像,我們使用了 **resource staging server** 。 ``` kubectl create -f conf/kubernetes-resource-staging-server.yaml ``` 我們同樣將其部署在 `spark-cluster` namespace 下,該 yaml 文件見 [kubernetes-handbook](https://github.com/rootsongjc/kubernetes-handbook) 的 `manifests/spark-with-kubernetes-native-scheduler` 目錄。 #### 優化 其中有一點需要優化,在使用下面的命令提交任務時,使用 `--conf spark.kubernetes.resourceStagingServer.uri` 參數指定 *resource staging server* 地址,用戶不應該關注 *resource staging server* 究竟運行在哪臺宿主機上,可以使用下面兩種方式實現: - 使用 `nodeSelector` 將 *resource staging server* 固定調度到某一臺機器上,該地址依然使用宿主機的 IP 地址 - 改變 `spark-resource-staging-service` service 的 type 為 **ClusterIP**, 然后使用 **Ingress** 將其暴露到集群外部,然后加入的內網 DNS 里,用戶使用 DNS 名稱指定 *resource staging server* 的地址。 然后可以執行下面的命令來提交本地的 jar 到 kubernetes 上運行。 ```bash ./spark-submit \ --deploy-mode cluster \ --class org.apache.spark.examples.SparkPi \ --master k8s://https://172.20.0.113:6443 \ --kubernetes-namespace spark-cluster \ --conf spark.kubernetes.authenticate.driver.serviceAccountName=spark \ --conf spark.executor.instances=5 \ --conf spark.app.name=spark-pi \ --conf spark.kubernetes.driver.docker.image=harbor-001.jimmysong.io/library/spark-driver:v2.1.0-kubernetes-0.3.1-1 \ --conf spark.kubernetes.executor.docker.image=harbor-001.jimmysong.io/library/spark-executor:v2.1.0-kubernetes-0.3.1-1 \ --conf spark.kubernetes.initcontainer.docker.image=harbor-001.jimmysong.io/library/spark-init:v2.1.0-kubernetes-0.3.1-1 \ --conf spark.kubernetes.resourceStagingServer.uri=http://172.20.0.114:31000 \ ../examples/jars/spark-examples_2.11-2.2.0-k8s-0.4.0-SNAPSHOT.jar ``` 該命令將提交本地的 `../examples/jars/spark-examples_2.11-2.2.0-k8s-0.4.0-SNAPSHOT.jar` 文件到 *resource staging server*,executor 將從該 server 上獲取 jar 包并運行,這樣用戶就不需要每次提交任務都編譯一個鏡像了。 詳見:https://apache-spark-on-k8s.github.io/userdocs/running-on-kubernetes.html#dependency-management #### 設置 HDFS 用戶 如果 Hadoop 集群沒有設置 kerbros 安全認證的話,在指定 `spark-submit` 的時候可以通過指定如下四個環境變量, 設置 Spark 與 HDFS 通信使用的用戶: ```bash --conf spark.kubernetes.driverEnv.SPARK_USER=hadoop --conf spark.kubernetes.driverEnv.HADOOP_USER_NAME=hadoop --conf spark.executorEnv.HADOOP_USER_NAME=hadoop --conf spark.executorEnv.SPARK_USER=hadoop ``` 使用 hadoop 用戶提交本地 jar 包的命令示例: ```bash ./spark-submit \ --deploy-mode cluster \ --class com.talkingdata.alluxio.hadooptest \ --master k8s://https://172.20.0.113:6443 \ --kubernetes-namespace spark-cluster \ --conf spark.kubernetes.driverEnv.SPARK_USER=hadoop \ --conf spark.kubernetes.driverEnv.HADOOP_USER_NAME=hadoop \ --conf spark.executorEnv.HADOOP_USER_NAME=hadoop \ --conf spark.executorEnv.SPARK_USER=hadoop \ --conf spark.kubernetes.authenticate.driver.serviceAccountName=spark \ --conf spark.executor.instances=5 \ --conf spark.app.name=spark-pi \ --conf spark.kubernetes.driver.docker.image=harbor-001.jimmysong.io/library/spark-driver:v2.1.0-kubernetes-0.3.1-1 \ --conf spark.kubernetes.executor.docker.image=harbor-001.jimmysong.io/library/spark-executor:v2.1.0-kubernetes-0.3.1-1 \ --conf spark.kubernetes.initcontainer.docker.image=harbor-001.jimmysong.io/library/spark-init:v2.1.0-kubernetes-0.3.1-1 \ --conf spark.kubernetes.resourceStagingServer.uri=http://172.20.0.114:31000 \ ~/Downloads/tendcloud_2.10-1.0.jar ``` 詳見:https://github.com/apache-spark-on-k8s/spark/issues/408 #### 限制 Driver 和 Executor 的資源使用 在執行 `spark-submit` 時使用如下參數設置內存和 CPU 資源限制: ```bash --conf spark.driver.memory=3G --conf spark.executor.memory=3G --conf spark.driver.cores=2 --conf spark.executor.cores=10 ``` 這幾個參數中值如何傳遞到 Pod 的資源設置中的呢? 比如我們設置在執行 `spark-submit` 的時候傳遞了這樣的兩個參數:`--conf spark.driver.cores=2` 和 `--conf spark.driver.memory=100G` 那么查看 driver pod 的 yaml 輸出結果將會看到這樣的資源設置: ```yaml resources: limits: memory: 110Gi requests: cpu: "2" memory: 100Gi ``` 以上參數是對 `request` 值的設置,那么 `limit` 的資源設置的值又是從何而來? 可以使用 `spark.kubernetes.driver.limit.cores` 和 `spark.kubernetes.executor.limit.cores` 來設置 CPU的 hard limit。 memory limit 的值是根據 memory request 的值加上 `spark.kubernetes.executor.memoryOverhead` 的值計算而來的,該配置項用于設置分配給每個 executor 的超過 heap 內存的值(可以使用k、m、g單位)。該值用于虛擬機的開銷、其他本地服務開銷。根據 executor 的大小設置(通常是 6%到10%)。 我們可以這樣來提交一個任務,同時設置 driver 和 executor 的 CPU、內存的資源 request 和 limit 值(driver 的內存 limit 值為 request 值的 110%)。 ```bash ./spark-submit \ --deploy-mode cluster \ --class org.apache.spark.examples.SparkPi \ --master k8s://https://172.20.0.113:6443 \ --kubernetes-namespace spark-cluster \ --conf spark.kubernetes.authenticate.driver.serviceAccountName=spark \ --conf spark.driver.memory=100G \ --conf spark.executor.memory=10G \ --conf spark.driver.cores=30 \ --conf spark.executor.cores=2 \ --conf spark.driver.maxResultSize=10240m \ --conf spark.kubernetes.driver.limit.cores=32 \ --conf spark.kubernetes.executor.limit.cores=3 \ --conf spark.kubernetes.executor.memoryOverhead=2g \ --conf spark.executor.instances=5 \ --conf spark.app.name=spark-pi \ --conf spark.kubernetes.driver.docker.image=harbor-001.jimmysong.io/library/spark-driver:v2.1.0-kubernetes-0.3.1-1 \ --conf spark.kubernetes.executor.docker.image=harbor-001.jimmysong.io/library/spark-executor:v2.1.0-kubernetes-0.3.1-1 \ --conf spark.kubernetes.initcontainer.docker.image=harbor-001.jimmysong.io/library/spark-init:v2.1.0-kubernetes-0.3.1-1 \ local:///opt/spark/examples/jars/spark-examples_2.11-2.2.0-k8s-0.4.0-SNAPSHOT.jar 10000000 ``` 這將啟動一個包含一千萬個 task 的計算 pi 的 spark 任務,任務運行過程中,drvier 的 CPU 實際消耗大約為 3 核,內存 40G,每個 executor 的 CPU 實際消耗大約不到 1 核,內存不到 4G,我們可以根據實際資源消耗不斷優化資源的 request 值。 `SPARK_DRIVER_MEMORY` 和 `SPARK_EXECUTOR_MEMORY` 和分別作為 Driver 容器和 Executor 容器啟動的環境變量,比如下面這個 Driver 啟動的 CMD 中: ```bash CMD SPARK_CLASSPATH="${SPARK_HOME}/jars/*" && \ env | grep SPARK_JAVA_OPT_ | sed 's/[^=]*=\(.*\)/\1/g' > /tmp/java_opts.txt && \ readarray -t SPARK_DRIVER_JAVA_OPTS < /tmp/java_opts.txt && \ if ! [ -z ${SPARK_MOUNTED_CLASSPATH+x} ]; then SPARK_CLASSPATH="$SPARK_MOUNTED_CLASSPATH:$SPARK_CLASSPATH"; fi && \ if ! [ -z ${SPARK_SUBMIT_EXTRA_CLASSPATH+x} ]; then SPARK_CLASSPATH="$SPARK_SUBMIT_EXTRA_CLASSPATH:$SPARK_CLASSPATH"; fi && \ if ! [ -z ${SPARK_EXTRA_CLASSPATH+x} ]; then SPARK_CLASSPATH="$SPARK_EXTRA_CLASSPATH:$SPARK_CLASSPATH"; fi && \ if ! [ -z ${SPARK_MOUNTED_FILES_DIR+x} ]; then cp -R "$SPARK_MOUNTED_FILES_DIR/." .; fi && \ if ! [ -z ${SPARK_MOUNTED_FILES_FROM_SECRET_DIR} ]; then cp -R "$SPARK_MOUNTED_FILES_FROM_SECRET_DIR/." .; fi && \ ${JAVA_HOME}/bin/java "${SPARK_DRIVER_JAVA_OPTS[@]}" -cp $SPARK_CLASSPATH -Xms$SPARK_DRIVER_MEMORY -Xmx$SPARK_DRIVER_MEMORY $SPARK_DRIVER_CLASS $SPARK_DRIVER_ARGS ``` 我們可以看到對 `SPARK_DRIVER_MEMORY` 環境變量的引用。Executor 的設置與 driver 類似。 而我們可以使用這樣的參數來傳遞環境變量的值 `spark.executorEnv.[EnvironmentVariableName]`,只要將 `EnvironmentVariableName` 替換為環境變量名稱即可。 ## 參考 - [Spark動態資源分配-Dynamic Resource Allocation](http://lxw1234.com/archives/2015/12/593.htm) - [Running Spark on Kubernetes](https://apache-spark-on-k8s.github.io/userdocs/running-on-kubernetes.html) - [Apache Spark Jira Issue - 18278 - SPIP: Support native submission of spark jobs to a kubernetes cluster](https://issues.apache.org/jira/browse/SPARK-18278) - [Kubernetes Github Issue - 34377 Support Spark natively in Kubernetes](https://github.com/kubernetes/kubernetes/issues/34377) - https://github.com/rootsongjc/spark-on-kubernetes - [Scheduler backend](https://github.com/apache-spark-on-k8s/spark/blob/branch-2.2-kubernetes/resource-managers/kubernetes/architecture-docs/scheduler-backend.md) - [Introduction to Spark on Kubernetes - banzaicloud.com](https://banzaicloud.github.io/blog/spark-k8s/) - [Scaling Spark made simple on Kubernetes - banzaicloud.com](https://banzaicloud.com/blog/scaling-spark-k8s/) - [The anatomy of Spark applications on Kubernetes - banzaicloud.com](https://banzaicloud.com/blog/spark-k8s-internals/) - [Monitoring Apache Spark with Prometheus - banzaicloud.com](https://banzaicloud.com/blog/spark-monitoring/) - [Running Zeppelin Spark notebooks on Kubernetes - banzaicloud.com](https://banzaicloud.com/blog/zeppelin-spark-k8/) - [Apache Spark CI/CD workflow howto - banzaicloud.com](https://banzaicloud.com/blog/pipeline-howto/)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看