使用Docker在本地搭建hadoop,spark集群
本環(huán)境使用的單個(gè)宿主主機(jī),而不是跨主機(jī)集群,本spark集群環(huán)境存在的意義可能在于便于本地開發(fā)測(cè)試使用,非常輕量級(jí)和便捷。這個(gè)部署過程,最好在之前有過一定的hadoop,spark集群部署經(jīng)驗(yàn)的基礎(chǔ),本文重點(diǎn)在于docker相關(guān)的操作,至于hadoop和spark集群的部署,極力推薦這兩個(gè)網(wǎng)頁(yè):
Hadoop集群:http://blog.csdn.net/stark_sum ... 24279。
Spark集群:http://blog.csdn.net/stark_sum ... 58081
主機(jī)系統(tǒng):ubuntu14.04,64位,內(nèi)存4G,主機(jī)名docker。(實(shí)際上是在虛擬機(jī)上安裝的)
軟件版本:hadoop-2.6.0,jdk1.7.0_79,scala-2.10.5,spark-1.2.0-bin-hadoop2.4,docker版本:1.9.1,鏡像:ubuntu14.04。
搭建環(huán)境前調(diào)研結(jié)果描述:
目前網(wǎng)上在docker上部署spark的介紹比較簡(jiǎn)單和沒有相關(guān)啟動(dòng)使用的操作,部署大致分為兩類情況:
1. 直接在docker倉(cāng)庫(kù)pull下來。這個(gè)方法我嘗試了一下,不建議使用,首先下載鏡像比較大,2G多,其次下載之后貌似只能單機(jī)啟動(dòng),也就是偽分布式,并不是集群(我自己沒有實(shí)際使用過,看到的相關(guān)資料是這樣說的)。如下sequenceiq/spark:1.2.0這個(gè)鏡像:
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
sequenceiq/spark 1.2.0 334aabfef5f1 10 months ago 2.115 GB
2. 自己使用基礎(chǔ)鏡像搭建環(huán)境。本文采用這種方式,由于自己也是剛接觸docker一個(gè)多月,還不會(huì)使用dockerfile,所以使用的是commit方式制作的集群。
具體部署過程
第一步,相關(guān)軟件準(zhǔn)備。
通過對(duì)spark源碼當(dāng)中docker文件夾的閱讀得出的思路,利用數(shù)據(jù)卷共享數(shù)據(jù)。相關(guān)的集群軟件都放在/opt目錄下,目的是為后面啟動(dòng)集群的時(shí)候使用docker數(shù)據(jù)卷共享和永久保存數(shù)據(jù),不會(huì)隨著容器的刪除而丟失。spark源碼docker文件夾解讀參考網(wǎng)頁(yè):http://blog.csdn.net/yunlong34 ... 33731
操作說明,直接把java等軟件解壓到/opt下,總共是四個(gè),java,hadoop,scala,spark。不需要在宿主主機(jī)做任何修改,包括/etc/hosts,/etc/profile添加變量等,因?yàn)槭窃谌萜鳟?dāng)中使用,宿主主機(jī)并不會(huì)用到。解壓之后如下:
- root@docker:/opt# ll
- total 32
- drwxr-xr-x 7 root root 4096 12月 22 22:12 ./
- drwxr-xr-x 23 root root 4096 11月 30 19:35 ../
- drwxr-xr-x 12 root root 4096 12月 22 22:07 hadoop-2.6.0/
- drwxr-xr-x 8 root root 4096 4月 11 2015 jdk1.7.0_79/
- drwxr-xr-x 9 root root 4096 12月 22 13:54 scala-2.10.5/
- drwxrwxr-x 12 root root 4096 12月 22 22:19 spark-1.2.0-bin-hadoop2.4/
然后把hadoop和spark 的配置文件修改,這一步主要是靠之前的相關(guān)基礎(chǔ)操作了,可以參考上面給出的兩個(gè)網(wǎng)站修改配置文件,我是直接拷貝我之前集群的配置文件替換的,然后再結(jié)合后面的主機(jī)名,ip等行稍作修改就行了。如果之前沒有部署過集群,這一步的工作量是相當(dāng)大的。
需要特別注意的一點(diǎn)是hadoop的配置文件中的hdfs-sit.xml中的dfs.datanode.data.dir,這個(gè)也就是hdfs的datanode的文件夾,也是通過小技巧修改為file:/root/data,為什么這么修改后面有講解,最終的想要的目的是通過鏈接文件,鏈接到數(shù)據(jù)卷/opt的hadoop目錄里面,這樣數(shù)據(jù)就能保存在容器之外了,不會(huì)隨著容器的刪除而丟失。修改如下:
- dfs.datanode.data.dir
- file:/root/data
第二步,制作基礎(chǔ)鏡像。(主要工作)
本集群的思路是盡可能的減少額外的工作量,使用的是固定網(wǎng)絡(luò)環(huán)境,這可能和docker本身的網(wǎng)絡(luò)不固定性相悖,所以使用了一點(diǎn)小技巧修改的網(wǎng)絡(luò),這也是這個(gè)方法不能大規(guī)模使用的原因,也算是一個(gè)弊端吧。我看到有人使用動(dòng)態(tài)的ip注冊(cè),我還沒有理解到哪個(gè)地步,在后期的學(xué)習(xí)中再慢慢完善吧。節(jié)點(diǎn)容器主機(jī)名和ip規(guī)劃如下:
主節(jié)點(diǎn)容器主機(jī)名hostname:node0,IP:172.17.0.150。
從節(jié)點(diǎn)容器主機(jī)名hostname:node1,IP:172.17.0.151。
從節(jié)點(diǎn)容器主機(jī)名hostname:node2,IP:172.17.0.152。
下面就開始一步一步的來設(shè)置:
1.查看鏡像,使用ubuntu:14.04做為基礎(chǔ)鏡像,如果沒有就pull一個(gè)吧。
- root@docker:/opt# docker images
- REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
- ubuntu 14.04 ca4d7b1b9a51 8 weeks ago 187.9 MB
2.啟動(dòng)一個(gè)容器,安裝vim和ssh。
- root@docker:/opt# docker run -it ubuntu:14.04 /bin/bash
- root@67f272584448:/# apt-get -y install vim openssh-server
3.修改ssh配置文件,允許root登陸。
- root@67f272584448:/# vim /etc/ssh/sshd_config
找到:PermitRootLogin without-password
修改為:PermitRootLogin yes
4.生成ssh公鑰,輸入ssh-keygen,一直回車就行了。著里需要說明的是,三個(gè)節(jié)點(diǎn)的公鑰都是一樣的,為了簡(jiǎn)單起見而利用了小技巧。如果比較了解ssh的話,我說的這些相當(dāng)于廢話了,后面還會(huì)有涉及的。
- root@67f272584448:/# ssh-keygen
此時(shí)/root/.ssh文件夾里如下:
- root@67f272584448:/# ls /root/.ssh/
- id_rsa id_rsa.pub
- root@67f272584448:/# cat /root/.ssh/id_rsa.pub >> /root/.ssh/authorized_keys
- root@67f272584448:/# ls /root/.ssh/
- authorized_keys id_rsa id_rsa.pub
5.下面開始關(guān)鍵步驟了。
把需要的變量寫入/root/.bashrc,為什么不寫入/etc/profile呢,因?yàn)槲以嚵艘幌?,寫?etc/proflie生成鏡像啟動(dòng)容器的時(shí)候變量不能生效。
看到這里,相信下面的變量都是很熟悉吧:
- export JAVA_HOME=/opt/jdk1.7.0_79
- export CLASSPATH=.:/opt/jdk1.7.0_79/lib/dt.jar:/opt/jdk1.7.0_79/lib/tools.jar
- export HADOOP_HOME=/opt/hadoop-2.6.0
- export SCALA_HOME=/opt/scala-2.10.5
- export SPARK_HOME=/opt/spark-1.2.0-bin-hadoop2.4
- export PATH=$JAVA_HOME/bin:$PATH:$SCALA_HOME/bin:$SPARK_HOME/bin
6.這個(gè)是最后一步了,在/root下新建一個(gè)run.sh腳本,對(duì)容器所做的修改,全部寫入這個(gè)腳本了,先把腳本貼出來,再解釋吧。
- 1 #!/bin/bash
- 2
- 3 echo "172.17.0.150 node0" > /etc/hosts
- 4 echo "172.17.0.151 node1" >> /etc/hosts
- 5 echo "172.17.0.152 node2" >> /etc/hosts
- 6
- 7 case $HOSTNAME in
- 8 "node0")
- 9 ifconfig eth0 172.17.0.150
- 10 sed -i 's/root@.*$/root@node0/g' /root/.ssh/authorized_keys
- 11 ;;
- 12 "node1")
- 13 ifconfig eth0 172.17.0.151
- 14 sed -i 's/root@.*$/root@node0/g' /root/.ssh/authorized_keys
- 15 ln -s /opt/hadoop-2.6.0/dfs/node1 /root/data
- 16 ;;
- 17 "node2")
- 18 ifconfig eth0 172.17.0.152
- 19 sed -i 's/root@.*$/root@node0/g' /root/.ssh/authorized_keys
- 20 ln -s /opt/hadoop-2.6.0/dfs/node2 /root/data
- 21 ;;
- 22 *)
- 23 echo "null"
- 24 ;;
- 25 esac
- 26
- 27 /etc/init.d/ssh start -D
- 28
1)3,4,5行,替換hosts。啟動(dòng)集群的時(shí)候,習(xí)慣性的喜歡使用主機(jī)名,而不是使用ip,所以做了這個(gè)修改。另一個(gè)原因是,容器在重啟之后hosts和ip是會(huì)變化的,所以每次啟動(dòng)都要修改。
2)7到25行,是利用容器的主機(jī)名來做三個(gè)修改。
- 第一,修改主機(jī)的IP,也就是我們的三個(gè)節(jié)點(diǎn)都是固定ip的,這個(gè)命令需要privileged。
- 第二,設(shè)置ssh免登錄,也就authorized_keys中最后一個(gè)字段root@......全部修改為root@node0,這樣node0節(jié)點(diǎn)就能免登錄到node1,node2,和自己node0。
- 第三,利用連接文件,把hdfs的數(shù)據(jù)保存到數(shù)據(jù)卷的相關(guān)目錄,也就是保存到了容器之外。利用連接文件時(shí)一個(gè)技巧,hdfs的配置文件都是/root/data,實(shí)際上卻保存到了不同的文件目錄上去。在上面的hadoop的配置文件中做的一個(gè)特殊的修改
dfs.datanode.data.dir ,file:/root/data ,這個(gè)是hdfs的實(shí)際存儲(chǔ)數(shù)據(jù)的目錄,通過軟連接到數(shù)據(jù)卷目錄,最終把數(shù)據(jù)保存在容器之外,這樣當(dāng)容器刪除時(shí),hdfs里面的數(shù)據(jù)并沒有消失,新建容器就可以再次使用數(shù)據(jù)了。
3)27行,這個(gè)就是啟動(dòng)ssh的,關(guān)鍵的是-D這個(gè)參數(shù),如果不加,啟動(dòng)容器的時(shí)候run -d容器就會(huì)停止,不會(huì)運(yùn)行。
4)最后保存退出,再修改一下執(zhí)行權(quán)限,退出容器
- root@67f272584448:~# chmod 744 /root/run.sh
- root@67f272584448:~# exit
7.使用commit提交鏡像吧。
- root@docker:~/docker# docker commit 67 ubuntu:base-spark
- 35341d63645cb5c23f88a6f4ac51d1000dc4431646ac3a948bd9c9f171dcbeeb
- root@docker:~/docker# docker images
- REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
- ubuntu base-spark 35341d63645c 4 minutes ago 261.1 MB
從上面可以看出,鏡像只有260MB,是非常小的。
到此整個(gè)基礎(chǔ)鏡像就做好了,其中有可能出錯(cuò)的地方是,hadoop和spark的配置文件修改的問題,這里是無(wú)關(guān)docker知識(shí)的“準(zhǔn)備工作”。
第三步,啟動(dòng)容器,啟動(dòng)集群,并測(cè)試。
最后這步是最最爽的時(shí)候了,一個(gè)命令,集群就啟動(dòng)起來了。
其實(shí)下面大部分的篇幅是在講解我的思路,啟動(dòng)集群本身是很簡(jiǎn)單的hadoop,spark知識(shí)。
一、啟動(dòng)容器集群
我寫了一個(gè)小腳本docker_start.sh,里面三行是啟動(dòng)三個(gè)容器的命令,先看一眼:
- root@docker:~/docker# cat docker_start.sh
- #!/bin/bash
- docker run -d --name node0 -h node0 -v /opt:/opt --privileged ubuntu:base-spark /root/run.sh
- docker run -d --name node1 -h node1 -v /opt:/opt --privileged ubuntu:base-spark /root/run.sh
- docker run -d --name node2 -h node2 -v /opt:/opt --privileged ubuntu:base-spark /root/run.sh
下面解釋一下這個(gè)啟動(dòng)命令的各個(gè)參數(shù):
1)-d這個(gè)命令能夠成功執(zhí)行的原因是run.sh這個(gè)腳本的/etc/init.d/ssh start -D這一行的-D這個(gè)參數(shù),容器才能成功后臺(tái)up。
2)--name node0,這個(gè)是node0的容器名。
3)-h node0,這里的node0是容器主機(jī)名,也就是hostname。
4)-v /opt:/opt,就是數(shù)據(jù)卷,四個(gè)目錄在這里java,hadoop,scala,spark,并且hdfs的數(shù)據(jù)存儲(chǔ)目錄在hadoop-2.6.0目錄里,dfs文件夾里有三個(gè)目錄,最好手動(dòng)提前新建name,node1和node2,其實(shí)是可以寫入run.sh腳本里面新建的,但是我已經(jīng)不想回頭去修改run.sh了。
- root@docker:/opt/hadoop-2.6.0/dfs# pwd
- /opt/hadoop-2.6.0/dfs
- root@docker:/opt/hadoop-2.6.0/dfs# ls
- name node1 node2
name文件夾是hadoop的配置文件指定的:
- dfs.namenode.name.dir
- file:/opt/hadoop-2.6.0/dfs/name
node1和node2是run.sh腳本通過連接文件過去的實(shí)際hdfs存儲(chǔ)數(shù)據(jù)的目錄:
- dfs.datanode.data.dir
- file:/root/data
- ln -s /opt/hadoop-2.6.0/dfs/node1 /root/data
- ln -s /opt/hadoop-2.6.0/dfs/node2 /root/data
5)--privileged,這個(gè)參數(shù)是獲得最高權(quán)限,才能夠執(zhí)行run.sh腳本里面的修改ip的命令。
ifconfig eth0 172.17.0.150
6)/root/run.sh,就是啟動(dòng)容器的時(shí)候,執(zhí)行一下我們提前寫好的腳本,對(duì)容器做一下修改了,雖然這些修改扭曲了docker的一些特性,不過對(duì)于我們這個(gè)本地的小環(huán)境來說,應(yīng)該還是有點(diǎn)實(shí)際使用的價(jià)值的。
二、進(jìn)入node0容器,啟動(dòng)并測(cè)試hdfs
其實(shí),到這里,就已經(jīng)差不多結(jié)束了,下面就是hadoop和spark的知識(shí)了
首先,先看一下啟動(dòng)的三個(gè)節(jié)點(diǎn)高興一下吧
- root@docker:~/docker# docker ps
- CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
- 7268b191b8fd ubuntu:base-spark "/root/run.sh" About an hour ago Up About an hour node2
- acce5919ed63 ubuntu:base-spark "/root/run.sh" About an hour ago Up About an hour node1
- 6494f90e1ecc ubuntu:base-spark "/root/run.sh" About an hour ago Up About an hour node0
進(jìn)入node0容器
- root@docker:/# docker exec -it node0 /bin/bash
- root@node0:/#
此時(shí)的容器都是已經(jīng)做過修改的,可以參看以下相關(guān)的信息,比如,ifconfig,/etc/hosts,hostname,/root/.ssh/authorized_keys,等。
下面就啟動(dòng)hadoop的hdfs吧,因?yàn)檫@里只用到hdfs所以就不管yarn了,第一次啟動(dòng)hdfs先來個(gè)格式化,然后,還要輸入若干個(gè)yes,這個(gè)yes是第一次ssh登陸的時(shí)候需要的,我就不貼出來格式化等相關(guān)的代碼了。
然后就是啟動(dòng)hdfs:
- root@node0:/# /opt/hadoop-2.6.0/sbin/start-dfs.sh
輸入jps查看一下node0上的進(jìn)程
- root@node0:/# jps
- 1310 Jps
- 843 NameNode
- 1025 SecondaryNameNode
下面就可以使用hdfs了,可以向hdfs上傳幾個(gè)文件試試,也可以通過webUI瀏覽器看一下hdfs的情況,總而言之,就是hdfs的知識(shí)了,我就不廢話了。
三,以standalone方式啟動(dòng)spark集群。
到這里直接啟動(dòng)spark進(jìn)程就可以了:
- root@node0:/# /opt/spark-1.2.0-bin-hadoop2.4/sbin/start-all.sh
再次jps一下看看啟動(dòng)的情況
- root@node0:/# jps
- 1532 Jps
- 843 NameNode
- 1025 SecondaryNameNode
- 1393 Master
一切正常,就可以開始啟動(dòng)spark-shell進(jìn)行測(cè)試了,以standalone方式啟動(dòng):
- root@node0:/# /opt/spark-1.2.0-bin-hadoop2.4/bin/spark-shell --master spark://node0:7077
root@node0:/# /opt/spark-1.2.0-bin-hadoop2.4/bin/spark-shell --master spark://node0:7077
到這里也基本已經(jīng)結(jié)束了,可以跑一個(gè)wordcount的例子,同樣也可以使用webUI查看spark的情況。































