由于項目需要,最近在研究阿里云的E-Mapreduce,出于開發需要,想搭建一個hadoop集群,
關于Hadoop集群的配置,網上有很多這方面的文章,本文不再贅述。
本文主要講述通過docker自動化完成一個hadoop的步驟。
本文目標:
- 熟悉Docker相關操作
- 熟悉hadoop集群的安裝配置
- 熟練使用Shell去創建自動化腳本初始化hadoop容器,自動互信等
本文使用相關軟件版本
- Centos 7
- Docker 1.11.2
相關步驟簡介:
- 構建基礎鏡像
- 配置相應hadoop配置
- 基于基礎鏡像以及配置完全的hadoop2.X.tar.gz構建hadoop鏡像
- 創建自動化配置腳本,初始化hadoop容器
- 提交一個文件到hdfs,運行wordcount的樣例Mapreduce
Note:
本文最終會啟動三個容器,hadoop0,hadoop1,hadoop2,
設置靜態IP,100.10.0.100,100.10.0.101,100.10.0.102,
其中hadoop0是master,hadoop1和2是slave
一、構建基礎鏡像
基于一個已經存在的centos,由于hadoop集群在啟動的時候,需要依賴一些軟件,比如建立互信需要ssh相關,在自動化配置的時候需要自動輸入expect等。
詳細的Dockfile如下:
# 選擇一個已有的os鏡像作為基礎
FROM centos
# 鏡像的作者
MAINTAINER xingchuan.qxc
# 安裝openssh-server和sudo軟件包,并且將sshd的UsePAM參數設置成no
RUN yum install -y openssh-server sudo
RUN sed -i 's/UsePAM yes/UsePAM no/g' /etc/ssh/sshd_config
#安裝openssh-clients
RUN yum install -y openssh-clients
# 安裝網絡相關命令
RUN yum install -y net-tools
# 安裝編輯器
RUN yum install -y vim
# 安裝which
RUN yum install -y which
# 安裝expect
RUN yum install -y expect
# 添加測試用戶root,密碼root,并且將此用戶添加到sudoers里
RUN echo "root:root" | chpasswd
RUN echo "root ALL=(ALL) ALL" >> /etc/sudoers
# 下面這兩句比較特殊,在centos6上必須要有,否則創建出來的容器sshd不能登錄
RUN ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key
RUN ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key
# 啟動sshd服務并且暴露22端口
RUN mkdir /var/run/sshd
EXPOSE 22
CMD ["/usr/sbin/sshd", "-D"]
運行 docker build -t "xingchuan/centos" .
docker build 相關的命令,自行google,這里是通過該命令構建一個叫xingchuan/centos的鏡像
二、 基于基礎鏡像,構建Jdk8的鏡像
在Oracle官網下載jdk8,我今天下載的是jdk-8u121-linux-x64.tar.gz
構建JDK8的鏡像Dockfile如下:
FROM xingchuan/centos
MAINTAINER xingchuan.qxc
ADD jdk-8u121-linux-x64.tar.gz /usr/local
ENV JAVA_HOME /usr/local/jdk1.8.0_121
ENV PATH $JAVA_HOME/bin:$PATH
RUN echo "export JAVA_HOME=/usr/local/jdk1.8.0_121" >> /etc/profile
RUN echo "export CLASSPATH=.:$JAVA_HOME/lib" >> /etc/profile
RUN echo "export PATH=$JAVA_HOME/bin:$PATH" >> /etc/profile
Note:
Dockerfile的ADD命令,含有解壓功能,詳細用法可以自行查找相關資料
這個地方我使用ENV發現JDK的環境變量沒有自動給配置上(具體原因回頭詳查),
所以在最后加了三個RUN,手動配置了一下JDK環境變量
運行 docker build -t "xingchuan/jdk8" . 完成JDK8鏡像的構建
三、 構建hadoop環境的鏡像,基于Jdk8鏡像
3.1、基礎配置
在hadooop.apache.org下載hadoop,我這里使用的是hadoop-2.7.3.tar.gz,下載后,我做了如下配置。
解壓后,修改相關配置
hadoop-env.sh
export JAVA_HOME=/usr/local/jdk1.7
core-site.xml
<configuration>
<property>
<name>fs.defaultFS</name>
<value>hdfs://hadoop0:9000</value>
</property>
<property>
<name>hadoop.tmp.dir</name>
<value>/usr/local/hadoop/tmp</value>
</property>
<property>
<name>fs.trash.interval</name>
<value>1440</value>
</property>
</configuration>
hdfs-site.xml
<configuration>
<property>
<name>dfs.replication</name>
<value>1</value>
</property>
<property>
<name>dfs.permissions</name>
<value>false</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>
<description>The hostname of the RM.</description>
<name>yarn.resourcemanager.hostname</name>
<value>hadoop0</value>
</property>
</configuration>
mapred-site.xml (不存在則創建)
<configuration>
<property>
<name>mapreduce.framework.name</name>
<value>yarn</value>
</property>
</configuration>
**slaves **
hadoop1
hadoop2
配置完成后,重新打包成hadoop-2.7.3.tar.gz
3.2 創建互信自動腳本
3.2.1 genSSH.exp
目的:
在容器啟動的時候,hadoop三個節點之間需要互信,本文目標就是全部自動化完成,
所以必須借助expect軟件(該軟件Centos默認沒有安裝,執行 yum install -y expect可以安裝調試)
腳本如下:
#!/usr/bin/expect
set timeout 10
set username [lindex $argv 0]
set password [lindex $argv 1]
set hostname [lindex $argv 2]
spawn ssh-copy-id -i /root/.ssh/id_rsa.pub $username@$hostname
expect {
#first connect, no public key in ~/.ssh/known_hosts
"Are you sure you want to continue connecting (yes/no)?" {
send "yes\r"
expect "password:"
send "$password\r"
}
#already has public key in ~/.ssh/known_hosts
"password:" {
send "$password\r"
}
"Now try logging into the machine" {
#it has authorized, do nothing!
}
}
expect eof
3.2.2 startHadoop.exp
目的
容器初始化成功之后,一切配置都ok了,自動啟動hadoop集群
腳本如下:
#!/usr/bin/expect
set timeout 30
spawn /usr/local/hadoop/sbin/start-all.sh
expect "Are you sure you want to continue connecting (yes/no)?" {
send "yes\r"
}
Note:expect其他高級用法,自行Google
3.3 構建Hadoop鏡像
Dockerfile如下:
FROM xingchuan/jdk8
MAINTAINER xingchuan.qxc
ADD hadoop-2.7.3.tar.gz /usr/local
ADD genSSH.exp /root
ADD startHadoop.exp /root
RUN chmod +x /root/genSSH.exp
RUN chmod +x /root/startHadoop.exp
RUN mv /usr/local/hadoop-2.7.3 /usr/local/hadoop
ENV HADOOP_HOME /usr/local/hadoop
ENV PATH $HADOOP_HOME/bin:$PATH
RUN echo "export HADOOP_HOME=/usr/local/hadoop" >> /etc/profile
RUN echo "export PATH=$HADOOP_HOME/bin:$HADOOP_HOME/sbin:$PATH" >> /etc/profile
上述文件創建好之后,我都是丟在同一個目錄的,目錄結構如下:
創建一個Dockerfile的軟鏈接
運行docker build -t "xingchuan/hadoop:2.7" .
鏡像創建成功后,如圖:
4、構建自動初始化腳本
創建一個startHadoop.sh,腳本內容如下:
#/bin/bash
# hadoop的三個容器名字
hadoop_arr=("hadoop0" "hadoop1" "hadoop2");
# hadoop三個容器對應的ip地址
hadoop_ip=("100.10.0.100" "100.10.0.101" "100.10.0.102");
for((m=0;m<${#hadoop_arr[*]};m++));
do
docker run -tid --name ${hadoop_arr[$m]} -h ${hadoop_arr[m]} --add-host hadoop0:100.10.0.100 --add-host hadoop1:100.10.0.101 --add-host hadoop2:100.10.0.102 --net=HZ --ip=${hadoop_ip[m]} xingchuan/hadoop:2.7
done;
# 創建ssh公鑰私鑰
for((m=0;m<${#hadoop_arr[*]};m++));
do
docker exec ${hadoop_arr[m]} rm -rf ~/.ssh;
docker exec ${hadoop_arr[m]} mkdir -p ~/.ssh;
docker exec ${hadoop_arr[m]} ssh-keygen -t rsa -f ~/.ssh/id_rsa -P "";
done;
# 建立互信
for((m=0;m<${#hadoop_arr[*]};m++));
do
for((n=0;n<${#hadoop_arr[*]};n++));
do
docker exec ${hadoop_arr[m]} expect -f /root/genSSH.exp root root ${hadoop_arr[n]};
done;
done;
# format hdfs
docker exec hadoop0 hdfs namenode -format
# 啟動hadoop集群
docker exec hadoop0 /root/startHadoop.exp
Note:
--add-host 可以在容器啟動的時候自動配置/etc/hosts
在宿主機給startHadoop.sh加上可執行權限
chmod +x startHadoop.sh
運行后,容器啟動成功且互信關系創建完成
檢查相應進程是否都啟動完成:
hadoop0
[root@hadoop0 ~]# jps
1120 Jps
403 NameNode
596 SecondaryNameNode
756 ResourceManager
hadoop1
[root@hadoop0 ~]# ssh hadoop1
Last login: Sat Feb 4 12:38:35 2017 from hadoop0
[root@hadoop1 ~]# jps
354 NodeManager
547 Jps
252 DataNode
hadoop2
[root@hadoop1 ~]# ssh hadoop2
Last login: Sat Feb 4 12:38:39 2017 from hadoop1
[root@hadoop2 ~]# jps
357 NodeManager
550 Jps
255 DataNode