這一節將在《Dockerfile完成Hadoop2.6的偽分布式搭建》的基礎上搭建一個完全分布式的Hadoop集群。
1. 搭建集群中需要用到的文件
[root@centos-docker hadoop-cluster]# ll total 340648
# 用自動化構建集群的腳本 -rwxr-xr-x. 1 root root 2518 Aug 13 01:20 build-cluster.sh
# 使用scp 來下載的文件的腳本 -rwxr-xr-x. 1 root root 314 Aug 12 19:31 download.sh
# 使用scp 來上傳文件的腳本 -rwxr-xr-x. 1 root root 313 Aug 12 19:02 upload.sh
# 在集群構建完成后,每一次開啟和關閉Docker集群的腳本 -rwxr-xr-x. 1 root root 203 Aug 13 00:57 cluster.sh # 用來構建鏡像的Dockerfile -rw-r--r--. 1 root root 2810 Aug 13 00:30 Dockerfile
# hadoop軟件 -rwxr-x---. 1 root root 195257604 Aug 12 23:18 hadoop-2.6.0.tar.gz
# java JDK -rwxr-x---. 1 root root 153512879 Aug 12 23:18 jdk-7u79-linux-x64.tar.gz # hadoop的配置文件 -rw-r--r--. 1 root root 387 Aug 12 20:57 yarn-site.xml -rw-r--r--. 1 root root 643 Aug 11 23:47 hdfs-site.xml -rw-r--r--. 1 root root 400 Aug 11 23:47 core-site.xml -rw-r--r--. 1 root root 138 Aug 11 23:27 mapred-site.xml -rw-r--r--. 1 root root 21 Aug 13 01:20 slaves
2. Hadoop的配置文件內容:
core-site.xml文件:
<?xml version="1.0" encoding="UTF-8"?> <?xml-stylesheet type="text/xsl" href="configuration.xsl"?> <configuration> <property> <name>hadoop.tmp.dir</name> <value>file:/data/hadoop/tmp</value> </property> <property> <name>fs.defaultFS</name> <value>hdfs://master:9000</value> </property> </configuration>
hdfs-site.xml文件:
<?xml version="1.0" encoding="UTF-8"?> <?xml-stylesheet type="text/xsl" href="configuration.xsl"?> <configuration> <property> <name>dfs.replication</name> <value>3</value> </property> <property> <name>dfs.namenode.name.dir</name> <value>file:/data/hadoop/dfs/name</value> </property> <property> <name>dfs.datanode.data.dir</name> <value>file:/data/hadoop/dfs/data</value> </property> <property> <name>dfs.permissions</name> <value>false</value> </property> </configuration>
mapred-site.xml文件:
<configuration> <property> <name>mapreduce.framework.name</name> <value>yarn</value> </property> </configuration>
yarn-site.xml文件:
<configuration> <property> <name>yarn.nodemanager.aux-services</name> <value>mapreduce_shuffle</value> </property> <property> <name>yarn.log-aggregation-enable</name> <value>true</value> </property> <property> <name>yarn.resourcemanager.hostname</name> <value>master</value> </property> </configuration>
3. Dockerfile內容解釋
# build a new hadoop image with basic centos FROM centos # who is the author MAINTAINER amei ####################Configurate JDK################################ # 安裝ssh(集群必要),iproute(內涵各種網絡命令),which(沒有這個命令,在執行hadoop的一些命令的時候就會報錯)
# 同時建立存放JDK的目錄 RUN yum -y install openssh-server openssh-clients iproute which && mkdir /usr/local/java # 通過ADD指令將JDK復制到,ADD這個指令會將壓縮包自動解壓 ADD jdk-7u79-linux-x64.tar.gz /usr/local/java/ ###################Configurate SSH################################# # 生成必要的host key文件,否則,/usr/sbin/sshd將無法啟動 RUN ssh-keygen -q -t rsa -b 2048 -f /etc/ssh/ssh_host_rsa_key -N '' && ssh-keygen -q -t ecdsa -f /etc/ssh/ssh_host_ecdsa_key -N '' && ssh-keygen -q -t dsa -f /etc/ssh/ssh_host_ed25519_key -N '' # 配置無密碼登陸到本機,首相生成公私鑰對,然后建立authorized_keys文件 RUN ssh-keygen -f /root/.ssh/id_rsa -N '' && cat /root/.ssh/id_rsa.pub >> /root/.ssh/authorized_keys ###################Configurate Hadoop############################## # 將hadoop軟件包copy到鏡像中,同時會自動解壓 ADD hadoop-2.6.0.tar.gz /usr/local/ # 建立hadoop文件夾的軟連接 RUN ln -s /usr/local/hadoop-2.6.0 /usr/local/hadoop # 復制編輯好的配置文件到鏡像中去,會直接覆蓋鏡像中原有的文件 COPY core-site.xml /usr/local/hadoop/etc/hadoop/ COPY hdfs-site.xml /usr/local/hadoop/etc/hadoop/ COPY mapred-site.xml /usr/local/hadoop/etc/hadoop/ COPY yarn-site.xml /usr/local/hadoop/etc/hadoop/ COPY slaves /usr/local/hadoop/etc/hadoop/ # 重新設置hadoop-env.sh中的JAVA_HOME變量,否則將無法正常啟動集群
# 配置ssh_config文件中: StrictHostKeyChecking no, 可以消除ssh,scp等訪問時詢問yes/no。
# 配置sshd_config 文件中, UseDNS no , UseDNS 的默認值為 yes。 配置為no之后可以加速ssh,scp鏈接速度。 RUN sed -i "s?JAVA_HOME=\${JAVA_HOME}?JAVA_HOME=/usr/local/java/jdk?g" /usr/local/hadoop/etc/hadoop/hadoop-env.sh && \ sed -i "s?#\s\+StrictHostKeyChecking\s\+ask?StrictHostKeyChecking no?g" /etc/ssh/ssh_config && \ sed -i "s?#UseDNS yes?UseDNS no?g" /etc/ssh/sshd_config ################### Integration configuration ####################### # 這里配置鏡像的環境變量,但是這樣設置的環境變量只能在運行時使用/bin/bash時才會生效。當用ssh登錄到容器后,這些變量將失效(坑爹的玩意) ENV JAVA_HOME /usr/local/java/jdk ENV JRE_HOME ${JAVA_HOME}/jre ENV CLASSPATH .:${JAVA_HOME}/lib:${JRE_HOME}/lib ENV HADOOP_HOME /usr/local/hadoop ENV PATH ${HADOOP_HOME}/bin:${HADOOP_HOME}/sbin:${JAVA_HOME}/bin:$PATH # 當用ssh登錄到容器后,上述設置的變量將失效,為了能夠在ssh登陸時也能使用這些變量,將這些變量加入到root賬戶的.bash_profile文件中。
# 而且還有比較坑的是,export JRE_HOME=/usr/local/java/jdk/jre 不能寫成 export JRE_HOME=${JAVA_HOME}/jre。其它的也是同理,所以一下配置中都是從絕對路徑寫起。(多么痛的領悟)
RUN ln -s /usr/local/java/jdk1.7.0_79 /usr/local/java/jdk && \
echo "export JAVA_HOME=/usr/local/java/jdk" >> /root/.bash_profile && \
echo "export JRE_HOME=/usr/local/java/jdk/jre" >> /root/.bash_profile && \
echo "export CLASSPATH=.:/usr/local/java/jdk/lib:/usr/local/java/jdk/jre/lib" >> /root/.bash_profile && \
echo "export HADOOP_HOME=/usr/local/hadoop" >> /root/.bash_profile && \
echo "export PATH=/usr/local/hadoop/bin:/usr/local/hadoop/sbin:/usr/local/java/jdk/bin:$PATH" >> /root/.bash_profile
# 設置root賬戶的密碼 RUN echo "root:1234" | chpasswd # 設置容器啟動時未指定要執行的時候,默認要的執行的命令 CMD ["/usr/sbin/sshd","-D"]
4. 自動化集群建立過程
自動化的構建集群通過build-cluster.sh腳本完成。
其中只要在腳本執行過程中輸入Datanode 的個數,並可以自動通過Dockerfile生成鏡像文件,然后通過鏡像建立容器集群,再配置網絡。
#!/bin/bash
# 單個節點鏡像的名稱 IMAGE=hadoop-cluster echo "The hostname of namenode will be master" echo "How many datanode would you want? Please enter:"
# 讀入Datanode的個數 read num
echo "the hostname of datanode will be:" if [ -f "slaves" ]; then rm -f slaves fi
# namenode 主機名直接配置為master,並將其加入到hadoop配置文件中的slaves文件,以及容器的配置文件hosts。
# (此時這兩文件在本地,配置完成后會上傳到容器中) if [ -f "hosts" ]; then rm -f hosts echo "127.0.0.1 localhost" >> hosts echo "192.168.1.10 master" >> hosts fi # 配置hadoop中的slaves文件,說明有哪些是datanode
# 其中每一個datanode容器的主機名都為slave再接上一個數字,主機的ip所在的網絡為: 192.168.1.0/24 for count in $(seq $num) do echo "slave$count" echo "slave$count" >> slaves echo 192.168.1.1$count" "slave$count >> hosts done # 因為要重新建立鏡像,所以停止以前的容器所用鏡像名為hadoop-cluster的容器,並將這些容器刪除 echo "stop and remove the relevant containers.." names=(`docker ps -a | grep $IMAGE | awk '{print $1}'`) for name in ${names[*]} do echo $name docker stop $name docker rm $name done # 刪除舊版的鏡像名為hadoop-cluster鏡像(如果存在) cluster=`docker images | grep $IMAGE` if [ -z "$cluster" ]; then echo "the $IMAGE image is not existed!" else echo "removing the $IMAGE..." docker rmi $IMAGE fi # 通過上述的Dockerfile構建新的鏡像名為hadoop-cluster的鏡像 echo "build the $IMAGE image..." docker build -t "$IMAGE" . # 容器和主機可能會可能會與主機共享文件,先建立共享的文件夾(不同的容器的主機名對應不同的文件夾) echo "creating the namenode master..." if [ ! -d "/data/share" ]; then mkdir -p /data/share fi if [ ! -d "/data/share/master" ]; then mkdir /data/share/master fi # 后邊的配置會用到br0虛擬網橋,如果存在就先將其刪除 ip link set br0 down ip link delete br0 # 刪除主機中的~/.ssh/known_hosts文件,不然可能會報這樣的錯誤: IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!。。。rm -f ~/.ssh/known_hosts # 建立namenode容器,其主機名為master docker run -itd -p 50070:50070 -p 8088:8088 --name=master --hostname=master --privileged=true --net=none -v /data/share/master:/opt/share $IMAGE # 通過pipework為容器設置固定IP(重新開啟容器將不存在) pipework br0 master 192.168.1.10/24@192.168.1.1
# 創建並配置datanode容器 echo "creating the datanodes.." for count1 in $(seq $num) do nodename=slave$count1 addr=192.168.1.1$count1
# 建立共享目錄 if [ ! -d "/data/share/$nodename" ]; then mkdir /data/share/$nodename fi docker run -itd --name=$nodename --hostname=$nodename --privileged=true --net=none -v /data/share/$nodename:/opt/share $IMAGE # 設置固定IP
pipework br0 $nodename $addr/24@192.168.1.1 done # 為虛擬網橋br0添加IP,同時會增加通往192.168.1.0/24子網的路由。 ip addr add 192.168.1.1/24 broadcast +1 dev br0 # 先刪除文件夾下的authorized_keys文件if [ -f "authorized_keys" ]; then rm -f authorized_keys fi # 先將每個主機中的id_rsa.pub中的內容先下載到到此文件夾下,然后將其中的內容加入到的authorized_keys文件中
# 然后在將authorized_keys放置到每個容器的 ~/.ssh/中,這樣每個容器之間就可以完成免密碼登陸
# 腳本download.sh和upload.sh中使用expect命令,來完成登陸過程中不用輸入密碼,在腳本中事先指定密碼。
for ((i=0; i<=$num; i++)) do addr=192.168.1.1$i ./download.sh $addr ~/.ssh/id_rsa.pub ./rsa_tmp cat rsa_tmp >> authorized_keys rm -f rsa_tmp done # 將hosts以及authorized_keys文件復制到每個容器的指定位置中去 for ((i=0; i<=$num; i++)) do addr=192.168.1.1$i ./upload.sh $addr authorized_keys ~/.ssh/ ./upload.sh $addr hosts /etc/hosts done
5. scp 指定密碼登陸,不用交互式的手動輸入面
scp下載文件:
#!/usr/bin/expect -f
# 第一個參數為ip地址 set addr [lrange $argv 0 0]
# 第二個參數為 要下載的文件的完整路徑名 set source_name [lrange $argv 1 1]
# 保存到本地的位置或者是新名字 set dist_name [lrange $argv 2 2] set password 1234 spawn scp root@$addr:$source_name ./$dist_name set timeout 30 expect { "yes/no" { send "yes\r"; exp_continue} "password:" { send "$password\r" } } send "exit\r" expect eof
scp上傳文件:
#!/usr/bin/expect -f set addr [lrange $argv 0 0] set source_name [lrange $argv 1 1] set dist_name [lrange $argv 2 2] set password 1234 spawn scp $source_name root@$addr:$dist_name set timeout 30 expect { "yes/no" { send "yes\r"; exp_continue} "password:" { send "$password\r" } } send "exit\r" expect eof
6. 測試:
直接在文件夾下輸入: ./build-cluster.sh命令,然后輸入想要的DataNode的數量, 就會自動完成Hadoop集群的搭建。
所建立的容器
登陸到master格式化namenode。
[root@centos-docker ~]# ssh root@master Warning: Permanently added 'master' (ECDSA) to the list of known hosts. root@master's password: [root@master ~]# hdfs namenode -format 16/08/12 20:57:07 INFO namenode.NameNode: STARTUP_MSG: /************************************************************ STARTUP_MSG: Starting NameNode STARTUP_MSG: host = master/192.168.1.10 STARTUP_MSG: args = [-format] STARTUP_MSG: version = 2.6.0 。。。。。。。。。。。。。。。
開啟hadoop
[root@master ~]# start-all.sh This script is Deprecated. Instead use start-dfs.sh and start-yarn.sh Starting namenodes on [master] master: Warning: Permanently added 'master,192.168.1.10' (ECDSA) to the list of known hosts. master: starting namenode, logging to /usr/local/hadoop-2.6.0/logs/hadoop-root-namenode-master.out slave2: Warning: Permanently added 'slave2,192.168.1.12' (ECDSA) to the list of known hosts. slave3: Warning: Permanently added 'slave3,192.168.1.13' (ECDSA) to the list of known hosts. slave1: Warning: Permanently added 'slave1,192.168.1.11' (ECDSA) to the list of known hosts. slave3: starting datanode, logging to /usr/local/hadoop-2.6.0/logs/hadoop-root-datanode-slave3.out slave2: starting datanode, logging to /usr/local/hadoop-2.6.0/logs/hadoop-root-datanode-slave2.out slave1: starting datanode, logging to /usr/local/hadoop-2.6.0/logs/hadoop-root-datanode-slave1.out Starting secondary namenodes [0.0.0.0] 0.0.0.0: Warning: Permanently added '0.0.0.0' (ECDSA) to the list of known hosts. 0.0.0.0: starting secondarynamenode, logging to /usr/local/hadoop-2.6.0/logs/hadoop-root-secondarynamenode-master.out starting yarn daemons starting resourcemanager, logging to /usr/local/hadoop-2.6.0/logs/yarn-root-resourcemanager-master.out slave2: starting nodemanager, logging to /usr/local/hadoop-2.6.0/logs/yarn-root-nodemanager-slave2.out slave1: starting nodemanager, logging to /usr/local/hadoop-2.6.0/logs/yarn-root-nodemanager-slave1.out slave3: starting nodemanager, logging to /usr/local/hadoop-2.6.0/logs/yarn-root-nodemanager-slave3.out
7. 其它
構建hadoop集群的所有文件都已經上傳到百度雲中。解壓之后之后直接在文件夾下執行./build-cluster.sh 就可以完成集群的搭建。
注意: 在系統中要事先安裝好docker,並且有名為centos的鏡像,並且安裝了pipework,expect,以及iproute,bridge-utils軟件。
將build-cluster.sh文件中的 docker build -t "hadoop-cluster" . 前邊的注釋去掉