所有文章

Bigdata on Docker

最近我们在把自己的大数据平台迁移到 Docker 上面来,最初的想法是用 Docker 技术代替我们现在的 Open Stack 平台,也就是把 Docker 容器当成虚拟来用,看到这里可能人要说了:这明显没有遵循 Docker 的佳实践啊!是的,但具我了解,很多大数据厂商都在想办法把自家的平台容器化,而且有不少厂商已经做到了,也许这就是趋势吧,尽管 Docker 的设计者并不建议这样做,到后面我们会把大数据平台中的每一个组件一个个的拆开,每一个组件都容器化。现在我们已经实践有一段时间了,并且下一步打算用 Kubernetes 来管理我们的 Docker 集群,先来整理一下在 bigdata on docker 实践中遇到的问题,这些问题都是最实际的,正所谓:真正的工作在细节之中。也希望能给读者一条捷径。


现在我们来把一个已有的大数据集群放在 Docker 环境中,我指的是重新搭一个集群而不是完整的挪过去。。

系统环境

大数据平台在整体架构上不会有什么变化,就是把物理机换成是 Docker 容器而已,那么容器从哪来?一般情况下你需要自己构建一个出来,比如你的大数据平台是基于 CentOS6.5 的,那就要自己动手构建一个基础镜像作为系统,这个镜像中可以包含你需要的一切依赖,如 jdk 和 python 等,然后用这个镜像创建指定数据的容器,比如我打算搭建一个 5 节点的集群那就创建 5 个容器出来,关于创建容器的参数下面再讲,因为还要涉及到网络和挂载之类的问题。

同步镜像

有了基础镜像之后,我们需要把这个镜像同步到所有物理机上,如果你如有一台物理机的话,可能不需要这一步,直接用 docker pull docker.io/... 这样的方式就可以了,但如果你有几十台或者更多的物理机,那么你需要搭建一个私有仓库,把你的镜像 push 进入,然后其它机器执行 docker pull 即可。

网络

解决 Docker 的跨主机通信是比较重要的一环,好在 Docker 1.9 版本中加入了 Overlay 网络,官方给出来两种方案解决跨主机的通信问题,一个是创建 Swarm 集群,创建好后它会自带一个 Overlay 网络,然后在这个集群中用 Docker service create 这样的方式创建一些容器,它们相互之间就可以直接通信了,但这个网络不能用 Docker run --network 的方式使用。

另一个是依赖第三方的 Key Value 存储系统,如:etcd, zookeeper 等,让所有 Docker 将自己的信息注册进入,然后手动创建一个 Overlay 网络,以此来实现多主机通信,笔者一直在用 zookeeper 因为对它比较熟悉啦,关于实现的细节可以看 Docker 多主机通信之ZK

在 Docker 1.13 版本中,官方去除了一些限制,即前面说到的 Swarm 集群自带的网络,新的版本允许以 Docker run --network 的方式使用了,而且不依赖第三方工具,实现起来相当简单,只需在创建 Overlay 网络时加上 --attachable 选项即可。

存储

容器的大小是有限制的,如果安装 Docker 后不作任何配置,那么每个容器最多使用 10G 的容间,如果你之前只是用容器跑一些 Tomcat 之类的应用可以不会注意到这个问题,但是如果把它当虚机用的话,你很快会发现容器空间不足之类的告警,这时你需要重新配置你的 Docker 启动参数,如果你用的是 CentOS7 那么可以参考这篇文章

到这里还没完,我们还需要解决大数据的平台中的核心问题:“大数据的存储”,比如 HDFS 中的数据要存在哪?容器里当然是不行的,这时需要把物理机上的硬盘先 mount 到物理机上不同的目录上,如 mount /dev/sdb /data/sdb ,然后通过 Docker run -v /data/sdb:/data/sdb 参数将目录挂载到容器内,假设有三台物理机,每台物理有6块硬盘,然后我打算在每个物理机上跑两个容器,那么每个容器可以分到三个硬盘,这些应该提前规划好。

访问端口

到这里集群已经可以跑起来了,但是从外面访问集群内的服务时,你可能还会遇到问题:docker run -p 选项可以把想要访问的端口映射到物理机的IP上,问题是大数据平台中的端口那么多,难道我要全部通过这种方式指定?再者说动态端口怎么办?关于这个问题,首先 docker run -p 选项可以指定端口范围,比如这样:docker run -p 6000-6010:6000-6010,这样就映射了十个端口出来,但是如果范围太大就不行了,启动慢不说,还浪费系统资源,而且它不能动态修改,容器启动后万一想修改一下是比较麻烦的。

其实还可以动态映射,docker run -p 选项其实是通过 iptables 命令实现的,像上面那条命令实际是在物理机上创建了十条 iptables 规则,我们可以通过直接操作 iptables 达到 Docker 动态映射端口 的目的,比如物理机的IP是 10.100.0.101 ,容器的IP是 10.200.0.101 ,那么只需要一条命令就可以把所有端口映射出来,如下:

iptables -t nat -A DOCKER -d 10.100.0.101/32 ! -i docker_gwbridge \
-p tcp -m tcp --dport 1025:62000 -j DNAT --to-destination 10.200.0.101

但是如果同一物理机上有两个容器相需要映射相同的端口出来,岂不是会冲突?当然会啊,,这个问题我总结出来的最好用的方式是,在每个物理机上设定多个IP,不同的容器映射到不同的IP上就可以了,CentOS7 增加子IP的方式可以参考这篇文章

启动参数

结合上面所有的内容,创建容器时可能会用到以下参数:

docker run \
--name node1 \
-h node1.overlay.com \
--network overlay.com \
-v /data/sdb-node1:/data \
--privileged=true \
-p 10.100.0.101:23:22 \
-tid registry.io:5000/centos:6.5

-End-


编写日期:2017-09-16