在Docker上使用Weave搭建Hadoop和Spark跨主机容器集群


功能和环境说明
实际环境是开发使用的两台服务器,每个服务器上是三个集群容器节点,总共六个节点,使用weave实现跨主机的通信,并且利用小插件可以实现在局域网或者是在外网查看监控集群的webUI和开放7077等关键端口进行程序远程调试功能。
目前网上跨主机的工具很多,我挑选的是使用普遍点和资料多点的weave,我实习的这个公司的需求并不大,只需要解决他们的hadoop,spark的开发环境就行了。
本文的重点有两个,第一,使用weave解决跨主机通信,第二,实际使用当中,开放端口调试程序和webUI监控等。至于hadoop,spark本身的安装配置等参数并没有涉及。

----------

时间:起草于2016/2/4,截止于2016/2/24。
地点:寒假老家和回到某高校教研室。
作者:duweike。
原因:某实习公司spark开发环境需要。
主机系统:CentOS7,两台服务器,分别32G内存。
软件版本:hadoop-2.6.0,jdk1.8.0_66,scala-2.10.4,spark-1.6.0-bin-hadoop2.6,docker版本:1.8.2(CentOS7默认安装的是这个版本,极力推荐升级到最新版),镜像:ubuntu14.04(不建议使用centos作为基础镜像)。

----------

具体部署过程

建议阅读我上一篇的单机版集群,虽然上篇的实际使用价值并不算大,但是其中的很多知识和技巧还是有参考价值的,比如ssh免密码登录技巧等。下面的过程没有办法那么详尽,请实际动手操作搞定。

第一步,制作Spark基础镜像。

这一步和我上一篇的意思差不多,基本操作也很简单,具有一定的实际操作经验的话会更顺利的完成。

1.我使用的是ubuntu14.04作为基础镜像,然后安装vim,ssh,并配置ssh允许远程root登录,然后ssh-keygen生成秘钥,然后设置“自己免密码登录自己”,请注意这里是一个很实用的小技巧。上面过程请自己完成,还是比较简单的。

2.把hadoop,spark,scala,java传入到这个镜像。在传入之前,要把hadoop,spark的“配置文件修改好”,修改的内容可以参考下文的集群信息,这里就不赘述了。在启动ssh的情况下可以使用scp,也可以在启动镜像的时候,利用数据卷传入。我是把所有的软件放到容器目录/opt/下面。

root@master:/opt# ls
hadoop-2.6.0 jdk1.8.0_66 scala-2.10.4 spark-1.6.0-bin-hadoop2.6

3.下面把所有的变量写入/root/.bashrc,不写入/etc/profile里面是因为不起作用,读者可以自己尝试一下,我就套用上篇的变量,自己修改为自己的吧

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

4.设置开机启动ssh,这一步很简单,写一个run.sh脚本就行了。

root@master:~# pwd
/root
root@master:~# cat run.sh
#!/bin/bash
/etc/init.d/ssh start -D
5.新建文件/root/hosts,来提前写入自己规划的IP-主机名的对应关系,这是为下面的操作做准备的,/root/hosts内容如下:

root@master:~# cat hosts
192.168.0.100 master
192.168.0.101 node1
192.168.0.102 node2
192.168.0.103 node3
192.168.0.104 node4
192.168.0.105 node5

6.使用docker commit提交成镜像,镜像名称为:spark:v1,然后分发到另外一台主机上。
如果有私有仓库就用push,pull分发。
如果没有,就使用save,load命令分发。

到这一步,spark:v1基础镜像也就是做好了,步骤太多没有办法那么详尽,不过应该没有太大问题。最终的目的就是hadoop,spark的基础镜像包生成。虽然工作量是蛮大的,但这并不是本文的重点。

----------

第二步,安装weave,创建容器,启动spark容器集群。

关于weave的介绍,请参考这两篇文档,请先阅读下面的文档之后再往下看。
github网址:https://github.com/weaveworks/weave
推荐网址:http://blog.csdn.net/wangtaoki ... 44525
我觉得他们的介绍意境很清楚了,阅读几遍,操作几遍,熟悉一下之后再继续下往下看。

首先介绍一下环境规划(此时是我笔记本的虚拟机IP):

服务器docker100 IP:172.16.203.100
服务器docker101 IP:172.16.203.101

服务器docker100和docker101的/etc/hosts添加一下映射会方便很多,还有ssh相互免密码登录

服务器docker100,一个主节点,二个从节点:
容器名:master,容器主机名:master,IP:192.168.0.100,
容器名:node1,容器主机名:node1,IP:192.168.0.101,
容器名:node2,容器主机名:node2,IP:192.168.0.102,
服务器docker101,三个从节点:
容器名:node3,容器主机名:node3,IP:192.168.0.103,
容器名:node4,容器主机名:node4,IP:192.168.0.104,
容器名:node5,容器主机名:node5,IP:192.168.0.105,

1.启动weave:weave launch。

2.执行:weave connect IP,这时两台主机的容器就可以连通了。IP不要使用主机名,直接使用IP地址。

3.下面开始利用weave启动集群。我这里是写了一个脚本来方便启动,初期可以手动一个一个节点执行启动。下面是脚本是在docker100服务器上执行的,这样就可以利用这个脚本一键创建集群了。

1 weave run 192.168.0.100/24 -itd --name master -p 8090:18090 -p 8998:18998 -p 23233:23233 -p 50070:50070 -p 8080:8080 -p 9000:19000 -p 8088:8088 -p 4040:4040 -p 6066:16066 -p 7077:17077 spark:v1 /root/run.sh
2 weave run 192.168.0.101/24 -itd --name node1 spark:v1 /root/run.sh
3 weave run 192.168.0.102/24 -itd --name node2 spark:v1 /root/run.sh
4

5 ssh root@172.16.203.101 "weave run 192.168.0.103/24 -itd --name node3 spark:v1 /root/run.sh"
6 ssh root@172.16.203.101 "weave run 192.168.0.104/24 -itd --name node4 spark:v1 /root/run.sh"
7 ssh root@172.16.203.101 "weave run 192.168.0.105/24 -itd --name node5 spark:v1 /root/run.sh"
8

9 docker exec master cp /root/hosts /etc/hosts
10 docker exec node1 cp /root/hosts /etc/hosts
11 docker exec node2 cp /root/hosts /etc/hosts
12

13 ssh root@172.16.203.101 "docker exec node3 cp /root/hosts /etc/hosts"
14 ssh root@172.16.203.101 "docker exec node4 cp /root/hosts /etc/hosts"
15 ssh root@172.16.203.101 "docker exec node5 cp /root/hosts /etc/hosts"

上面的脚本需要详细的解释一下:

1)这里使用的是docker原生的网络功能,端口映射,实际当中并不需要运行weave expose来暴露端口到本机,后面会再次解释为什么。第1行的意思是,启动master主节点容器,其中映射出来很多端口都是按照需求映射的,例如spark的端口7077和webUI端口8080,下一个过程解释为什么7077映射的是17077端口。

这里需要注意的是,--name master,给的是容器名,不过这里的容器主机名也已经变为master,着实方便了很多。

还有一个点是,在master容器内部运行一下ifconfig,可以查看到是两个网卡,两个IP,其中一个是原生的网桥docker0生成的172.17.0.0网段,另一个是使用weave生成的192.168.0.0网段。

第2行,第3行,就是创建node1,和node2节点了。这三个节点使用的IP地址是提前规划好的内网IP地址192.168.0.*。

2)第5,6,7行是利用ssh功能远程执行命令,创建node3,node4,node5节点。也可以在docker101上面直接执行。

3)第9-15行,是修改这六个容器的/etc/hosts文件,上面已经提前把/root/hosts这个文件写到容器里面了,容器启动之后再修改/etc/hosts为自己需要的,因为容器关闭重启之后这个文件会变动,所以如果容器关闭再次启动的时候,需要再次执行此段代码。

4.到目前为止,已经启动了使用weave创建的192.168.0.0网段相互连通的六个容器,并且IP地址,主机名,/etc/hosts文件,ssh免密码登录都已经设定好了。现在就可以登录到master节点,格式化HDFS,启动hdfs,yarn,spark等了。关于hadoop和spark都是安装我们的网络规划提前配置好集群的配置文件,和普通的主机集群配置一样。如果hadoop,spark的配置有点问题,为了方便也可以直接在容器里面再次修改正确就行了。

------------
网络部分解释----很重要

此时利用的weave生成的容器会有两个网卡。其中一个网卡时weave生成的,目的是为了跨主机连通,ip地址是自己规划的192.168.0.0网段。另一个网卡是原生网络docker0网桥生成的,可以连接外网使用,由于是NAT方式,所以要使用端口映射从外网连接进入“容器”,IP地址是自动生成的172.17.0.0网段。这一点相当重要,也是下一步为什么要进行端口转发的问题所在,可以在容器里面运行ifconfig查看一下两个IP。

----------

第三步,打开端口,实现远程监控和调试。

在实际生产中远程的web监控和程序调试是相当实用的,我实习的公司实际的需求就是这样,先看一个我画的整体的网络拓扑图。

1.png


----------
一,整体构架介绍和存在的一个问题。

从上面这个图来看,貌似有点复杂,先来解释一下这个真实的环境。

1.网络部分。

蓝色圆形和箭头是weave相关的网络部分,是实现跨主机通信的。
红色圆形和箭头是docker原生网络部分,是实现容器访问外网和外网访问容器的。

2.client1,client2,client3,这三个客户端是访问“master容器”的三种情况。

1)client3,在docker100服务器上访问容器集群。第一种方法,利用docker0原生网络端口映射进去。第二种方法,利用weave expose暴露集群的端口到本地主机docker100。
2)client2,从局域网内部别的主机访问容器集群。只能通过原生网络docker0。
3)client1,从外网访问局域网内部的容器集群。只能通过原生网络docker0。

实际当中,并不需要client3这个方式,下面就不再涉及,client2和client1这两个方式其实是可以归为一类,下面以client2来举例。

3.右上角的那个图是对master容器节点的一个解释,现在存在一个问题需要解决--那就是,可以实现client2访问master容器,但是client2无法访问到spark集群。下面解释为什么。
先在master容器里面输入netstat -tunlp查看一下端口的情况。

root@master:~# netstat -tunlp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name

tcp6 0 0 192.168.0.100:7077 :::* LISTEN 9843/java

tcp6 0 0 :::8080 :::* LISTEN 9843/java

上面是还以8080和7077端口为例,

: : : 8080 ,8080 端口前面是 : : : ,也就是任意IP。
192.168.0.100:7077,但是7077端口已经被绑定到预先设定好的192.168.0.100上了。

结合画的图示解释:

docker100的IP为IP2:172.16.203.100.
原生网络docekr0生成的IP3为:172.17.0.*。
weave生成的集群地址IP4位:192.168.0.100。

从图上显示可知,利用docker的 -p 参数端口映射可以顺利实现IP2 :Port2 --> IP3 :Port3,但是在容器内部无法实现IP3 :Port3 --> IP4 :Port4访问集群。分析可知,从client2通过原生网络访问到容器集群的master容器节点,如果访问8080端口,可以顺利显示webUI,但是如果想要使用IDEA工具远程调试程序使用7077端口则不行,因为7077端口是被weave的IP 192.168.0.100占用,此时的问题就是如何才能实现master容器内部从172.17.0.*:prot到192.168.0.100:7077端口的访问,这样才能最终访问到整个spark集群。

----------
二,利用rinetd实现容器内部端口的转发。

参考网址推荐:
官方网址:http://www.boutell.com/rinetd/
推荐博客:http://iblog.daobidao.com/linu ... BiDao

通过上面两个资料的阅读学习,相信已经知道的问题所在和如何解决了。下面就解释一下是如何操作的。

----------
假设已经在master容器上安装好rinetd和了解如何使用了。

1.首先查看所有的端口映射的配置文件,这个配置文件按需设定。然后使用命令:rinetd -c /root/rinetd.conf,启动端口转发功能,也就是在master内部,端口17077的数据会重定向到spark集群IP和端口192.168.0.100:7077上,最终实现外网访问spark集群的目的。

root@master:~# cat rinetd.conf
0.0.0.0 19000 192.168.0.100 9000
0.0.0.0 17077 192.168.0.100 7077
0.0.0.0 16066 192.168.0.100 6066
0.0.0.0 18090 192.168.0.100 8090
0.0.0.0 18998 192.168.0.100 8998
0.0.0.0 23233 192.168.0.100 23233
2.再次回顾一下上面生成master 节点容器的命令。

weave run 192.168.0.100/24 -itd --name master -p 8090:18090 -p 8998:18998 -p 23233:23233 -p 50070:50070 -p 8080:8080 -p 9000:19000 -p 8088:8088 -p 4040:4040 -p 6066:16066 -p 7077:17077 spark:v1 /root/run.sh
3.结合上面的整体框架示意图,以client2和spark程序端口7077和webUI端口8080为例,来描述一下整个实际流程。

1)浏览器查看spark集群,在浏览器中输入:172.16.203.100:8080。

172.16.203.100:8080-->master:8080 #端口映射

2)client2主机上面装有IDEA来编写scala程序,IDEA软件里面的地址应该填:172.16.203.100:7077。

172.16.203.100:7077-->master:17077-->master:7077
第一次是端口映射,创建时-p参数指定的17077,第二次是利用rinetd重定向到7077的。

0.png


----------

结束语

到此,整个过程就结束了,这篇文章的重点我觉得是画的那个图,这是真实的实际环境,应该有点帮助。

再次总结一下重点:

第一,利用weave实现跨主机的通信。
容器可以跨主机通信了,在上面部署hadoop,spark集群就没有什么压力了。

第二,实现在外网访问spark集群程序端口在线调试程序。
也就是就是端口之间的映射,转发的一些复杂关系,最终的效果就是可以实现远程调试程序的目的,相当方便。

为了把整个过程讲清楚花费了大量的口舌,也不知道讲的怎么样,如有问题,请联系QQ:604212506,非诚勿扰。

下一篇写一个shipyard加swarm来监控集群容器的一个工具。

----------

1 个评论

随着知识的增加,跨网络工具的学习,Kubernetes的使用,Dockerfile的学习,上文中有很多可以改进的地方,下一个目标,Kubernetes部署Spark集群。

要回复文章请先登录注册