馬踏飛燕——奔跑在Docker上的Spark

目錄

  1. 爲何要在Docker上搭建Spark集羣
  2. 網絡拓撲
  3. Docker安裝及配置
  4. ssh安裝及配置
  5. 基礎環境安裝
  6. Zookeeper安裝及配置
  7. Hadoop安裝及配置
  8. Spark安裝及配置
  9. 集羣部署
  10. 總結
  11. 參考資料

 1 爲何要在Docker上搭建Spark集羣

他:爲何要在Docker上搭建Spark集羣啊?node

我:由於……我行啊!linux

  MR和Spark都提供了local模式,即在單機上模擬多計算節點來執行任務。可是,像我這等手賤的新手,怎麼會知足於「模擬」?很容易想到在單機上運行多個虛擬機做爲計算節點,但是考慮到PC的資源有限,即便能將集羣運行起來,再作其餘的工做已是超負荷了。Docker是一種相比虛擬機更加輕量級的虛擬化解決方案,因此在Docker上搭建Spark集羣具備可行性。web


 2 網絡拓撲

  搭建一個有意義的小規模集羣,我選擇了3臺服務器做爲Spark計算節點(Worker)。集羣中光有計算節點還不夠,這3臺服務器同時也做爲分佈式文件系統(HDFS)的數據節點(DataNode)。指定了哪些服務器用來計算,哪些用來存儲以後,咱們還須要指定來管理計算和存儲的主節點。一個簡單方案:咱們可讓cloud1做爲管理計算節點的主節點(Master),同時它也做爲管理數據節點的主節點(NameNode)。docker

  很容易看到簡單方案不夠完美:首先,要是cloud1做爲NameNode宕機,整個分佈式文件系統則沒法工做。此時,咱們應當採用基於HA的HDFS方案:由多個NameNode共同管理DataNode,可是隻有一個NameNode處於活動(Active)狀態,當活動的NameNode沒法工做時,則須要其餘NameNode候補。這裏至少涉及2個關鍵技術:shell

  • 如何共享NameNode的信息(EditLog)?NameNode存儲的信息包括但不限於:數據在各DataNode上如何存儲,哪些DataNode是可用的。因此,當活動的NameNode沒法工做時,應當將這些信息傳遞給下一個被選中的NameNode。與其傳遞,不如全部的NameNode共享這些信息。這些信息將被分佈式地存儲在JournalNode上。在本集羣中,咱們使用全部3臺服務器都做爲JournalNode。cloud1和cloud2做爲NameNode。
  • 如何確保只有一個NameNode是活動的?當活動的NameNode沒法工做時,如何肯定下一個活動的Namenode?Zookeeper能夠解決這兩個問題,在本集羣中,3臺服務器都做爲Zkserver節點。

  再者,選用cloud1做爲Master來管理計算(standalone)的方式對資源的利用率不比Yarn方式。因此,在本集羣中選用cloud1作爲ResourceManager,3臺服務器都做爲NodeManager)。apache

  改進後的集羣描述以下:ubuntu

節點 Zkserver NameNode JournalNode ResourceManager NodeManager

Mastercentos

Worker
cloud1  √  √  √  √  √  √  √
cloud2  √  √  √  ×  √  ×  √
cloud3  √  ×  √  ×  √  ×  √

 3 Docker安裝及配置

  Docker有Windows/Mac/Linux版本。起初我處於對Docker的誤解選擇了Windows版本,Docker的核心程序必須運行在Linux上,故Windows版本的Docker其實是利用VirtualBox運行着一個精簡的Linux,而後在此Linux上運行Docker,最後在Docker上運行安裝好應用的鏡像。好傢伙,盜夢空間!最終,我選擇在CentOS上安裝Linux版本的Docker。關於Docker,咱們須要理解一個重要的概念:容器(Container)。容器是鏡像運行的場所,能夠在多個容器中運行同一個鏡像。瀏覽器

  Docker安裝好以後,咱們啓動Docker服務:bash

1 systemctl start docker.service

  咱們能夠拉一個Ubuntu鏡像,基於該鏡像咱們搭建Spark集羣:

1 docker pull ubuntu

  下載好鏡像到本地後,咱們能夠查看鏡像:

1 docker images

  使用run命令,建立一個容器來運行鏡像:

1 docker run -it ubuntu

  使用ps命令查看容器:

1 docker ps -a

  使用commit命令來將容器提交爲一個鏡像:

1 docker commit <container id|name>

  使用tag命令來爲一個鏡像打標籤:

1 docker tag <mirror id> <tag>

  使用start命令來啓動一個容器:

1 docker start -a <container id|name>

  在掌握了以上操做後,在Docker上搭建Spark集羣的技術路線以下:


4 ssh安裝及配置 

   試想一下如何啓動集羣?手動去每一個節點啓動相應的服務?這顯然是不合理的。HDFS,Yarn,Spark都支持單命令啓動所有節點。在某個節點上執行的命令是如何發送至其餘節點的呢?ssh服務幫助實現這一功能。關於ssh咱們須要知道其分爲服務端和客戶端,服務端默認監聽22號端口,客戶端可與服務端創建鏈接,從而實現命令的傳輸。

  docker服務啓動後,能夠看到宿主機上多了一塊虛擬網卡(docker0),在個人機器中爲172.17.0.1。啓動容器後,容器的IP從172.17.0.2開始分配。咱們不妨爲集羣分配IP地址以下:

域名 IP
cloud1 172.17.0.2
cloud2 172.17.0.3
cloud3 172.17.0.4

  關閉全部容器後,新建一個容器,命名爲cloud1:

1 #新建容器時須要指定這個容器的域名以及hosts文件
2 #參數:
3 #name:容器名稱
4 #h:域名
5 #add-host:/etc/hosts文件中的域名與IP的映射
6 docker --name cloud1 -h cloud1 --add-host cloud1:172.17.0.2 --add-host cloud2:172.17.0.3 --add-host cloud3:172.17.0.4 -it ubuntu

  在容器cloud1中經過apt工具來安裝ssh:

1 apt-get install ssh

  往~/.bashrc中加入ssh服務啓動命令:

1 /usr/sbin/sshd

  客戶端不能任意地與服務端創建鏈接,或經過密碼,或經過密鑰認證。在這裏咱們使用密鑰認證,生成客戶端的私鑰和公鑰:

1 #私鑰(~/.ssh/id_rsa)由客戶端持有
2 #公鑰(~/.ssh/id_rsa.pub)交給服務端
3 #已認證的公鑰(~/.ssh/authorized_keys)由服務端持有,只有已認證公鑰的客戶端才能鏈接至服務端
4 #參數:
5 #t:加密方式
6 #P:密碼    
7 ssh-keygen -t rsa -P ""

  根據技術路線,由cloud1容器提交的鏡像將生成cloud2容器和cloud3容器。要實現cloud1對cloud2和cloud3的ssh密鑰認證鏈接,其實只要實現cloud1對自己的鏈接就能夠了:

1 cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys

  測試是否能鏈接成功:

1 ssh root@cloud1

5 基礎環境安裝

  Java與Scala版本須要與其餘軟件的版本相匹配:

軟件 版本
Java 1.8.0_77
Scala 2.10.6
Zookeeper 3.4.8
Hadoop 2.6.4
Spark 1.6.1

  Java與Scala安裝包下載後,均解壓在/usr目錄下。在~/.bashrc中添加環境變量:

1 export JAVA_HOME=/usr/jdk1.8.0_77
2 export PATH=$PATH:$JAVA_HOME/bin
3 export SCALA_HOME=/usr/scala-2.10.6
4 export PATH=$PATH:$SCALA_HOME/bin

 6 Zookeeper安裝及配置

   Zookeeper安裝包下載後,解壓在/usr目錄下。在~/.bashrc中添加環境變量:

1 export ZOOKEEPER_HOME=/usr/zookeeper-3.4.8
2 export PATH=$PATH:$ZOOKEEPER_HOME/bin

  生成Zookeeper配置文件:

1 cp /usr/zookeeper-3.4.8/conf/zoo_sample.cfg /usr/zookeeper-3.4.8/conf/zoo.cfg 

  修改Zookeeper配置文件:

1 #數據存儲目錄修改成:
2 dataDir=/root/zookeeper/tmp
3 #在最後添加Zkserver配置信息:
4 server.1=cloud1:2888:3888
5 server.2=cloud2:2888:3888
6 server.3=cloud3:2888:3888

  設置當前Zkserver信息:

1 #~/zookeeper/tmp/myid文件中保存的數字表明本機的Zkserver編號
2 #在此設置cloud1爲編號爲1的Zkserver,以後生成cloud2和cloud3以後還須要分別修改此文件
3 echo 1 > ~/zookeeper/tmp/myid

7 Hadoop安裝及配置

  Hadoop安裝包下載後,解壓在/usr目錄下。在~/.bashrc中添加環境變量:

1 export HADOOP_HOME=/usr/hadoop-2.6.4
2 export PATH=$PATH:$HADOOP_HOME/bin:$HADOOP_HOME/sbin

  修改Hadoop啓動配置文件(/usr/hadoop-2.6.4/etc/hadoop/hadoop-env.sh):

1 #修改JAVA_HOME
2 export JAVA_HOME=/usr/jdk1.8.0_77

  修改核心配置文件(/usr/hadoop-2.6.4/etc/hadoop/core-site.xml):

參數 說明
fs.defaultFS 默認的文件系統
hadoop.tmp.dir 臨時文件目錄
ha.zookeeper.quorum Zkserver信息

 

 1 <property>
 2     <name>fs.defaultFS</name>
 3     <value>hdfs://ns1</value>
 4 </property>
 5 <property>
 6     <name>hadoop.tmp.dir</name>
 7     <value>/root/hadoop/tmp</value>
 8 </property>
 9 <property>
10     <name>ha.zookeeper.quorum</name> 
11     <value>cloud1:2181,cloud2:2181,cloud3:2181</value>
12 </property>

  修改HDFS配置文件(/usr/hadoop-2.6.4/etc/hadoop/hdfs-site.xml):

參數 說明
dfs.nameservices 名稱服務,在基於HA的HDFS中,用名稱服務來表示當前活動的NameNode
dfs.ha.namenodes.<nameservie> 配置名稱服務下有哪些NameNode
dfs.namenode.rpc-address.<nameservice>.<namenode> 配置NameNode遠程調用地址
dfs.namenode.http-address.<nameservice>.<namenode> 配置NameNode瀏覽器訪問地址
dfs.namenode.shared.edits.dir 配置名稱服務對應的JournalNode
dfs.journalnode.edits.dir JournalNode存儲數據的路徑

 

 1 <property>
 2     <name>dfs.nameservices</name>
 3     <value>ns1</value>
 4 </property>
 5 <property>
 6     <name>dfs.ha.namenodes.ns1</name>
 7     <value>nn1,nn2</value>
 8 </property>
 9 <property>
10     <name>dfs.namenode.rpc-address.ns1.nn1</name>
11     <value>cloud1:9000</value>
12 </property>
13 <property>
14     <name>dfs.namenode.http-address.ns1.nn1</name>
15     <value>cloud1:50070</value>
16 </property>
17 <property>
18     <name>dfs.namenode.rpc-address.ns1.nn2</name>
19     <value>cloud2:9000</value>
20 </property>
21 <property>
22     <name>dfs.namenode.http-address.ns1.nn2</name>
23     <value>cloud2:50070</value>
24 </property>
25 <property>
26     <name>dfs.namenode.shared.edits.dir</name> 
27     <value>qjournal://cloud1:8485;cloud2:8485;cloud3:8485/ns1</value>
28 </property>
29 <property>
30     <name>dfs.journalnode.edits.dir</name>
31     <value>/root/hadoop/journal</value>
32 </property>
33 <property>
34     <name>dfs.ha.automatic-failover.enabled</name>
35     <value>true</value>
36 </property>
37 <property>
38     <name>dfs.client.failover.proxy.provider.ns1</name>
39     <value>
40     org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider
41     </value>
42 </property>
43 <property>
44     <name>dfs.ha.fencing.methods</name>
45     <value>
46     sshfence
47     shell(/bin/true)
48     </value>
49 </property>
50 <property>
51     <name>dfs.ha.fencing.ssh.private-key-files</name>
52     <value>/root/.ssh/id_rsa</value>
53 </property>
54 <property>
55     <name>dfs.ha.fencing.ssh.connect-timeout</name>
56     <value>30000</value>
57 </property>

  修改Yarn的配置文件(/usr/hadoop-2.6.4/etc/hadoop/yarn-site.xml):

參數 說明
yarn.resourcemanager.hostname RescourceManager的地址,NodeManager的地址在slaves文件中定義

 

1 <property>
2     <name>yarn.resourcemanager.hostname</name>
3     <value>cloud1</value>
4 </property>
5 <property> 
6     <name>yarn.nodemanager.aux-services</name> 
7     <value>mapreduce_shuffle</value> 
8 </property>

  修改指定DataNode和NodeManager的配置文件(/usr/hadoop-2.6.4/etc/hadoop/slaves):

1 cloud1
2 cloud2
3 cloud3

 8 Spark安裝及配置

  Spark安裝包下載後,解壓在/usr目錄下。在~/.bashrc中添加環境變量:

1 export SPARK_HOME=/usr/spark-1.6.1-bin-hadoop2.6
2 export PATH=$SPARK_HOME/bin:$SPARK_HOME/sbin:$PATH

  Spark啓動配置文件:

1 cp /usr/spark-1.6.1-bin-hadoop2.6/conf/spark-env.sh.template /usr/spark-1.6.1-bin-hadoop2.6/conf/spark-env.sh

  修改Spark啓動配置文件(/usr/spark-1.6.1-bin-hadoop2.6/conf/spark-env.sh):

參數 說明
SPARK_MASTER_IP Master的地址,Worker的地址在slaves文件中定義

 

 1 export SPARK_MASTER_IP=cloud1
 2 export SPARK_WORKER_MEMORY=128m 
 3 export JAVA_HOME=/usr/jdk1.8.0_77 4 export SCALA_HOME=/usr/scala-2.10.6 5 export SPARK_HOME=/usr/spark-1.6.1-hadoop2.6 6 export HADOOP_CONF_DIR=/usr/hadoop-2.6.4/etc/hadoop 7 export SPARK_LIBRARY_PATH=$$SPARK_HOME/lib 
 8 export SCALA_LIBRARY_PATH=$SPARK_LIBRARY_PATH 
 9 export SPARK_WORKER_CORES=1 
10 export SPARK_WORKER_INSTANCES=1 
11 export SPARK_MASTER_PORT=7077

  修改指定Worker的配置文件(/usr/spark-1.6.1-bin-hadoop2.6/conf/slaves):

1 cloud1
2 cloud2
3 cloud3

 9 集羣部署

  在宿主機上提交cloud1容器爲新的鏡像,並打其標籤爲Spark:

1 #提交cloud1容器,命令返回新鏡像的編號
2 docker commit cloud1
3 #爲新鏡像打標籤爲Spark
4 docker tag <mirror id> Spark

  基於Spark鏡像建立cloud2和cloud3容器:

1 docker --name cloud2 -h cloud2 --add-host cloud1:172.17.0.2 --add-host cloud2:172.17.0.3 --add-host cloud3:172.17.0.4 -it Spark
2 docker --name cloud3 -h cloud3 --add-host cloud1:172.17.0.2 --add-host cloud2:172.17.0.3 --add-host cloud3:172.17.0.4 -it Spark

  還記得以前提到的cloud2和cloud3的當前Zkserver還未配置嗎?分別在cloud2和cloud3容器中修改Zookeeper配置:

1 #在cloud2執行
2 echo 2 > ~/zookeeper/tmp/myid
3 #在cloud3執行
4 echo 3 > ~/zookeeper/tmp/myid

  在全部節點啓動Zkserver(Zkserver並非用ssh啓動的,呵呵):

1 zkServer.sh start

  在全部節點查看Zkserver運行狀態:

1 #顯示鏈接不到Zkserver的錯誤,可稍後查看
2 #Master表示主Zkserver,Follower表示從Zkserver
3 Zkserver.sh status

  初始化其中一個NameNode,就選cloud1吧:

1 #格式化zkfc
2 hdfs zkfc -formatZK
3 #格式化NameNode
4 hdfs namenode -format

  在cloud1啓動HDFS,Yarn,Spark:

1 #啓動NameNode,DataNode,zkfc,JournalNode
2 start-dfs.sh
3 #啓動ResouceManager,NodeManager
4 start-yarn.sh
5 #啓動Master,Worker
6 start-all.sh

  使用jps命令查看各節點服務運行狀況:

1 jps

  還能夠登陸web管理臺來查看運行情況:

服務 地址
HDFS cloud1:50070
Yarn cloud1:8088
Spark cloud1:8080

10 總結

  • 環境搭建切不可知其然,但不知其因此然
  • 明確本身的需求是什麼,不可能一開始就弄懂全部配置項,掌握一個最小的知識集就好

11 參考資料

  1. 在Docker中從頭部署本身的Spark集羣
  2. Docker (軟件)
  3. HDFS-HA的配置-----自動Failover
  4. Spark:Yarn-cluster和Yarn-client區別與聯繫
  5. Installation On CentOS
相關文章
相關標籤/搜索