由于项目需要,最近在研究阿里云的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
fs.defaultFS
hdfs://hadoop0:9000
hadoop.tmp.dir
/usr/local/hadoop/tmp
fs.trash.interval
1440
hdfs-site.xml
dfs.replication
1
dfs.permissions
false
yarn-site.xml
yarn.nodemanager.aux-services
mapreduce_shuffle
yarn.log-aggregation-enable
true
The hostname of the RM.
yarn.resourcemanager.hostname
hadoop0
mapred-site.xml (不存在则创建)
mapreduce.framework.name
yarn
**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