鱼喃

听!布鲁布鲁,大鱼又在那叨叨了

基于Docker Swarm搭建Hadoop集群

背景

近两年Docker技术火热,不少公司开始向Docker转换。不仅仅是为了赶热度,更多的是确实感受到了Docker的魅力:虚拟化的同时并不会损耗多大的性能。Docker的魅力不仅在此,更重要的是它的部署、维护简易,Docker经常跟Devops联系在一起。一定意义上说,Docker真的很大程度上大大降低了这些事情的难度(或者说琐屑?),以前需要费心费力去部署和维护的系统环境在Docker的帮助下可以做到(very)快速的部署、伸缩。

实验室新集群在设立初期,就计划all in docker,并把用到的一些技术都切换到docker上来,包括storm、hadoop等等。

之前我对Hadoop的接触仅限于概念,从来没有实际操作过。一方面是没有机会,另一方面更多的是部署这样的一个集群不是简单的事,你很难在什么都不懂得情况下短时间内成功搭建一个集群。

于是,什么都不懂的我开始基于Docker搭建Hadoop集群。把Hadoop docker化的工作前人已经做过了(sequenceiq/hadoop-docker),我基本就是基于这个镜像开始搭建。很可惜,这个镜像是本地版的,没有提供真正的分布式的教程。

在成功部署上单机版后,又开始马不停蹄的增加节点调试。碰到了两个问题,一个是如何互连(配置文件怎么写),还有一个就是通过start-all.sh 脚本启动会产生多个不互联的集群。

在刘建宏师兄的指导下最终成功实现了分布式的部署。

一开始,我是在所有的节点上执行start-all.sh脚本来启动集群的,但是似乎Hadoop节点会对比自己的hostname和配置文件来决定服务是否要启动,而docker swarm service name跟hostname是不一样的,导致了与预期不符的情况。而且当时的版本hostname不能自己指定,我当时的解决方案就是改写bootstrap.sh,在启动的时候根据传入的参数来决定启动什么服务,脚本相当混乱。

正文开始

好在docker swarm从1.13开始支持--hostname,这下之前写的脚本就可以大大缩减了。在完成升级之后,整理了一下脚本和配置文件,把原来的镜像做了一点改动(加入默认配置,自动开机创建集群),创建了一个新的镜像(newnius/hadoop),使得创建集群更加便捷。就当是中文版的README了吧。

注意:docker版本要在1.13以上

从最简单的开始

创建1个mastre节点,3个slave节点的集群

创建集群

hadoop-master1

1
2
3
4
5
6
7
docker service create \
--name hadoop-master \
--hostname hadoop-master \
--network swarm-net \
--replicas 1 \
--endpoint-mode dnsrr \
newnius/hadoop:2.7.4

hadoop-slave1

1
2
3
4
5
6
7
docker service create \
--name hadoop-slave1 \
--network swarm-net \
--hostname hadoop-slave1 \
--replicas 1 \
--endpoint-mode dnsrr \
newnius/hadoop:2.7.4

hadoop-slave2

1
2
3
4
5
6
7
docker service create \
--name hadoop-slave2 \
--network swarm-net \
--hostname hadoop-slave2 \
--replicas 1 \
--endpoint-mode dnsrr \
newnius/hadoop:2.7.4

hadoop-slave3

1
2
3
4
5
6
7
docker service create \
--name hadoop-slave3 \
--network swarm-net \
--hostname hadoop-slave3 \
--replicas 1 \
--endpoint-mode dnsrr \
newnius/hadoop:2.7.4

这样一个集群就创建好了。
默认配置文件里已经按照这个写好了,所以不需要再做其他的配置。

因为hadoop要暴露的端口太多,而且slave节点端口会冲突,这里没有映射端口,是通过代理的方式进行访问web的,见无需端口映射,实现外部网络访问Docker集群内部服务,暂时没有办法通过浏览器来确认

初始化HDFS

因为集群是第一次创建,需要进行HDFS的初始化工作

hadoop-master节点,停止集群

1
2
sbin/stop-yarn.sh
sbin/stop-dfs.sh

所有节点,删除原有HDFS的数据

1
rm -rf /tmp

hadoop-master节点执行namenode的格式化工作

1
bin/hadoop namenode -format

hadoop-master节点启动集群

1
2
sbin/start-dfs.sh
sbin/start-yarn.sh

由于docker 容器在重启之后数据会丢失,建议把相关目录映射到host文件系统进行持久化。

测试Map-Redude

往HDFS加入几个文件用于输入

1
2
bin/hadoop dfs -mkdir -p /user/root/input
bin/hadoop dfs -put etc/hadoop/* /user/root/input

提交MR

1
bin/hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-2.7.1.jar grep input output 'dfs[a-z.]+'

可能jar文件路径和名称会有不同,根据实际情况调整

自定义(配置文件,数据持久化)

由于Hadoop配置文件夹里的配置文件太多,并且大多是不需要修改的。我采取了在启动前用/mnt/hadoop-config里的文件覆盖原有的配置,所以只需要把想要替换的配置文件(一般是core-site.xml, hdfs-site.xml, mapred-site.xml, slaves, yarn-site.xml)放在容器的/mnt/hadoop-config目录即可(通过文件映射的形式,见下)。

一个更加丰富的启动脚本(hadoop-master)如下,其他类似

1
2
3
4
5
6
7
8
9
10
docker service create \
--name hadoop-master \
--network swarm-net \
--hostname hadoop-master \
--replicas 1 \
--mount type=bind,source=/mnt/data/hadoop/hdfs/master,target=/tmp/hadoop-root \
--mount type=bind,source=/mnt/data/hadoop/logs/master,target=/usr/local/hadoop/logs \
--mount type=bind,source=/mnt/data/hadoop/config,target=/mnt/hadoop-config \
--endpoint-mode dnsrr \
newnius/hadoop:2.7.4

Dockerfile和默认的配置文件见:newnius/Dockerfiles

好久没写博客了,语无伦次,见谅。