使用Mesos和Marathon管理Docker集群

前言

针对“互联网+”时代的业务增长、变化速度及大规模计算的需求,廉价的、高可扩展的分布式x86集群已成为标准解决方案,如Google已经在几千万台服务器上部署分布式系统。Docker及其相关技术的出现和发展,又给大规模集群管理带来了新的想象空间。如何将二者进行有效地结合?本人将以实验的角度来部署mesos + marathon的docker集群

一、熟知mesos

Mesos是Apache下的开源分布式资源管理框架,它被称为是分布式系统的内核。Mesos最初是由加州大学伯克利分校的AMPLab开发的,后在Twitter得到广泛使用。接下来将简单介绍mesos。

1.1 mesos中的基本术语解释

Mesos-master:Mesos master,主要负责管理各个framework和slave,并将slave上的资源分配给各个framework
Mesos-slave:Mesos slave,负责管理本节点上的各个mesos-task,比如:为各个executor分配资源
Framework:计算框架,如:Hadoop,Spark等,通过MesosSchedulerDiver接入Mesos
Executor:执行器,安装到mesos-slave上,用于启动计算框架中的task。

1.2 总体架构

Mesos Architecture
上图展示了mesos的重要组成部分,mesoso由一个master进程管理运行着每个客户端节点的salve进程和跑任务的mesos计算框架。master进程通过计算框架可以很细致的管理cpu和内存等,从而提供资源。每个资源提供与包含了一个清单(slave ID, resource1: amount1, resource2, amount2, …),master会根据现有的政策决定提供每个计算框架多少资源,例如公平分享或者根据优先级分享。为了支持不同种的政策,master通过插件机制新增了一个allocation模块使之分配资源更简单方便。
一个计算框架运行在两个组件之上,一个是scheduler,他是master提供资源的注册中心,另一个是executor程序,用来发起在slave节点上运行计算框架的任务。master决定给每个计算框架提供多少计算资源,计算框架的的调度去选择使用哪个资源。当一个计算框架接受了提供的资源,他会通过mesos的任务描述运行程序,mesos也会在相应的slave上发起任务。

1.3 资源提供的例子

Mesos Architecture
让我们一起来熟悉下这个图上的流程步骤
1)slave 1 报告给master他拥有4核cpu和4G剩余内存,matser调用allocation政策模块,告诉salve 1 计算框架1应该被提供可用的资源。
2)master给计算框架1发送一个在slave1上可用的资源描述。
3)计算框架的调度器回复给master运行在slave上两个任务的相关信息,任务1需使用2个cpu,内存1G,任务2需使用1个cpu,2G内存。
4)最后,master发送任务给slave,分配适当的给计算框架执行器,继续发起两个任务(图上虚线处),因为仍有1个cpu和1G内存未分配,allocation模块现在或许提供剩下的资源给计算框架2。
除此之外,当任务完成,新的资源成为空闲时,这个资源提供程序将会重复。

二、学习zookeeper

2.1 Zookeeper简介

ZooKeeper是用来给集群服务维护配置信息,域名服务,提供分布式同步和提供组服务。所有这些类型的服务都使用某种形式的分布式应用程序。是一个分布式的,开放源码的协调服务,是的Chubby一个的实现,是Hadoop和Hbase的重要组件。

2.2角色


领导者(leader):领导者负责投票发起和决议,更新系统状态
跟随者(follwoer):follower用于接收客户请求并向客户端返回结果,在选主过程中参与投票
观察者:ObServer可以接受客户端连接,将写请求转发给leader节点,但ObServer不参加投票过程,只同步leader的状态,ObServer的目的是为了拓展系统,提高读取速度。
客户端:请求发起方

2.3 ZooKeeper的工作原理

Zookeeper的核心是原子广播,这个机制保证了各个Server之间的同步。实现这个机制的协议叫做Zab协议。Zab协议有两种模式,它们分别是恢复模式(选主)和广播模式(同步)。当服务启动或者在领导者崩溃后,Zab就进入了恢复模式,当领导者被选举出来,且大多数Server完成了和leader的状态同步以后,恢复模式就结束了。状态同步保证了leader和Server具有相同的系统状态。
为了保证事务的顺序一致性,zookeeper采用了递增的事务id号(zxid)来标识事务。所有的提议(proposal)都在被提出的时候加上了zxid。实现中zxid是一个64位的数字,它高32位是epoch用来标识leader关系是否改变,每次一个leader被选出来,它都会有一个新的epoch,标识当前属于那个leader的统治时期。低32位用于递增计数。
每个Server在工作过程中有三种状态:

  • LOOKING:当前Server不知道leader是谁,正在搜寻

  • LEADING:当前Server即为选举出来的leader

  • FOLLOWING:leader已经选举出来,当前Server与之同步

2.3 选主流程

当leader崩溃或者leader失去大多数的follower,这时候zk进入恢复模式,恢复模式需要重新选举出一个新的leader,让所有的Server都恢复到一个正确的状态。Zk的选举算法有两种:一种是基于basic paxos实现的,另外一种是基于fast paxos算法实现的。系统默认的选举算法为fast paxos。先介绍basic paxos流程:
1)选举线程由当前Server发起选举的线程担任,其主要功能是对投票结果进行统计,并选出推荐的Server;
2)选举线程首先向所有Server发起一次询问(包括自己);
3)选举线程收到回复后,验证是否是自己发起的询问(验证zxid是否一致),然后获取对方的id(myid),并存储到当前询问对象列表中,最后获取对方提议的leader相关信息(id,zxid),并将这些信息存储到当次选举的投票记录表中;
4)收到所有Server回复以后,就计算出zxid最大的那个Server,并将这个Server相关信息设置成下一次要投票的Server;
5)线程将当前zxid最大的Server设置为当前Server要推荐的Leader,如果此时获胜的Server获得n/2 + 1的Server票数, 设置当前推荐的leader为获胜的Server,将根据获胜的Server相关信息设置自己的状态,否则,继续这个过程,直到leader被选举出来。
通过流程分析我们可以得出:要使Leader获得多数Server的支持,则Server总数必须是奇数2n+1,且存活的Server的数目不得少于n+1.
每个Server启动后都会重复以上流程。在恢复模式下,如果是刚从崩溃状态恢复的或者刚启动的server还会从磁盘快照中恢复数据和会话信息,zk会记录事务日志并定期进行快照,方便在恢复时进行状态恢复。选主的具体流程图如下所示:

fast paxos流程是在选举过程中,某Server首先向所有Server提议自己要成为leader,当其它Server收到提议以后,解决epoch和zxid的冲突,并接受对方的提议,然后向对方发送接受提议完成的消息,重复这个流程,最后一定能选举出Leader。其流程图如下所示:

2.4 同步流程

选完leader以后,zk就进入状态同步过程。
1)leader等待server连接;
2)Follower连接leader,将最大的zxid发送给leader;
3)Leader根据follower的zxid确定同步点;
4)完成同步后通知follower 已经成为uptodate状态;
5)Follower收到uptodate消息后,又可以重新接受client的请求进行服务了。
流程图如下所示:

2.5 工作流程

2.5.1 Leader工作流程

Leader主要有三个功能:
1)恢复数据;
2)维持与Learner的心跳,接收Learner请求并判断Learner的请求消息类型;
3)Learner的消息类型主要有PING消息、REQUEST消息、ACK消息、REVALIDATE消息,根据不同的消息类型,进行不同的处理。
PING消息是指Learner的心跳信息;REQUEST消息是Follower发送的提议信息,包括写请求及同步请求;ACK消息是Follower的对提议的回复,超过半数的Follower通过,则commit该提议;REVALIDATE消息是用来延长SESSION有效时间。
Leader的工作流程简图如下所示,在实际实现中,流程要比下图复杂得多,启动了三个线程来实现功能。

2.5.2 Follower工作流程

Follower主要有四个功能:
1)向Leader发送请求(PING消息、REQUEST消息、ACK消息、REVALIDATE消息);
2)接收Leader消息并进行处理;
3)接收Client的请求,如果为写请求,发送给Leader进行投票;
4)返回Client结果。
Follower的消息循环处理如下几种来自Leader的消息:
1)PING消息: 心跳消息;
2)PROPOSAL消息:Leader发起的提案,要求Follower投票;
3)COMMIT消息:服务器端最新一次提案的信息;
4)UPTODATE消息:表明同步完成;
5)REVALIDATE消息:根据Leader的REVALIDATE结果,关闭待revalidate的session还是允许其接受消息;
6)SYNC消息:返回SYNC结果到客户端,这个消息最初由客户端发起,用来强制得到最新的更新。
Follower的工作流程简图如下所示,在实际实现中,Follower是通过5个线程来实现功能的。

三、搞懂marathon

marathon是一个mesos框架,能够支持运行长服务,比如web应用等。是集群的分布式Init.d,能够原样运行任何Linux二进制发布版本,如Tomcat Play等等,可以集群的多进程管理。也是一种私有的Pass,实现服务的发现,为部署提供提供REST API服务,有授权和SSL、配置约束,通过HAProxy实现服务发现和负载平衡。
我们可以如同一台Linux主机一样管理数千台服务器,它们的对应原理如下图,使用Marathon类似Linux主机内的init Systemd等外壳管理,而Mesos则不只包含一个Linux核,可以调度数千台服务器的Linux核,实际是一个数据中心的内核:

四、引入docker

2016,我用docker!
关于docker的文章,详情请关注另一篇博文docker实战

五、实战准备

5.1 centos7.1虚拟机两台

主机名:linux-node1.example.com IP地址:192.168.56.11 描述:Mesos Master Mesos Slave Marathon
主机名:linux-node2.example.com IP地址:192.168.56.12 描述:Zookeeper Mesos Slave

5.2 系统环境

  1. [root@linux-node2 ~]# cat /etc/redhat-release
  2. CentOS Linux release 7.1.1503 (Core)
  3. [root@linux-node2 ~]# uname -m
  4. x86_64
  5. [root@linux-node2 ~]# uname -r
  6. 3.10.0-229.el7.x86_64
  7. [root@linux-node2 ~]# uname -a
  8. Linux linux-node2.example.com 3.10.0-229.el7.x86_64 #1 SMP Fri Mar 6 11:36:42 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux

六、部署Zookeeper

准备java环境

  1. [root@linux-node2 ~]# yum install -y java

下载zookeeper并解压

  1. [root@linux-node2 src]# tar zxf zookeeper-3.4.6.tar.gz
  2. [root@linux-node2 src]# mv zookeeper-3.4.6 /usr/local/
  3. [root@linux-node2 src]# ln -s /usr/local/zookeeper-3.4.6/ /usr/local/zookeeper

修改配置文件生效,由于虚拟机数量限制,这里采用了伪集群的配置方式,只能用不同端口实现通信,生产环境不建议采纳。

  1. [root@linux-node2 src]# cd /usr/local/zookeeper/conf
  2. [root@linux-node2 conf]# mv zoo_sample.cfg zoo.cfg
  3. [root@linux-node2 conf]# cat /usr/local/zookeeper/conf/zoo.cfg
  4. # The number of milliseconds of each tick
  5. tickTime=2000 #Zookeeper 服务器之间或客户端与服务器之间维持心跳的时间间隔,也就是每个 tickTime 时间就会发送一个心跳。
  6. # The number of ticks that the initial
  7. # synchronization phase can take
  8. initLimit=10 #Zookeeper的Leader 接受客户端(Follower)初始化连接时最长能忍受多少个心跳时间间隔数。当已经超过 5个心跳的时间(也就是tickTime)长度后 Zookeeper 服务器还没有收到客户端的返回信息,那么表明这个客户端连接失败。总的时间长度就是 5*2000=10 秒
  9. # The number of ticks that can pass between
  10. # sending a request and getting an acknowledgement
  11. syncLimit=5 表示 Leader Follower 之间发送消息时请求和应答时间长度,最长不能超过多少个tickTime 的时间长度,总的时间长度就是 2*2000=4 秒。
  12. # the directory where the snapshot is stored.
  13. # do not use /tmp for storage, /tmp here is just
  14. # example sakes.
  15. dataDir=/tmp/zk1 #数据存放目录
  16. # the port at which the clients will connect
  17. clientPort=2181 #客户端连接端口
  18. # the maximum number of client connections.
  19. # increase this if you need to handle more clients
  20. #maxClientCnxns=60
  21. #
  22. # Be sure to read the maintenance section of the
  23. # administrator guide before turning on autopurge.
  24. #
  25. # http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance
  26. #
  27. # The number of snapshots to retain in dataDir
  28. #autopurge.snapRetainCount=3
  29. # Purge task interval in hours
  30. # Set to "0" to disable auto purge feature
  31. #autopurge.purgeInterval=1
  32. #server.A=B:C:D:
  33. #A 是一个数字,表示这个是第几号服务器;
  34. #B 是这个服务器的 ip 地址;
  35. #C 表示的是这个服务器与集群中的 Leader 服务器交换信息的端口;
  36. #D 表示的是万一集群中的 Leader 服务器挂了,需要一个端口来重新进行选举,选出一个新的 Leader,而这个端口就是用来执行选举时服务器相互通信的端口。
  37. server.1=192.168.56.12:3181:4181
  38. server.2=192.168.56.12:3182:4182
  39. server.3=192.168.56.12:3183:4183

查看配置文件修改

  1. [root@linux-node2 conf]# grep '^[a-z]' zoo.cfg
  2. tickTime=2000
  3. initLimit=10
  4. syncLimit=5
  5. dataDir=/data/zk1
  6. clientPort=2181
  7. server.1=192.168.56.12:3181:4181
  8. server.2=192.168.56.12:3182:4182
  9. server.3=192.168.56.12:3183:4183

创建三个目录来存放zookeeper的数据

  1. [root@linux-node2 conf]# mkdir -p /data/zk1 /data/zk2 /data/zk3
  2. [root@linux-node2 conf]# echo "1" >/data/zk1/myid
  3. [root@linux-node2 conf]# echo "2" >/data/zk2/myid
  4. [root@linux-node2 conf]# echo "3" >/data/zk3/myid

生成三份zookeeper配置文件

  1. [root@linux-node2 conf]# cp zoo.cfg zk1.cfg
  2. [root@linux-node2 conf]# cp zoo.cfg zk2.cfg
  3. [root@linux-node2 conf]# cp zoo.cfg zk3.cfg

修改zk2和zk3的配置,使用对应的数据目录和端口

  1. [root@linux-node2 conf]# sed -i 's/zk1/zk2/g' zk2.cfg
  2. [root@linux-node2 conf]# sed -i 's/zk1/zk3/g' zk3.cfg
  3. [root@linux-node2 conf]# sed -i 's/2181/2182/g' zk2.cfg
  4. [root@linux-node2 conf]# sed -i 's/2181/2183/g' zk3.cfg

启动Zookeeper并查看角色

  1. [root@linux-node2 conf]# /usr/local/zookeeper/bin/zkServer.sh start /usr/local/zookeeper/conf/zk1.cfgJMX
  2. enabled by default
  3. Using config: /usr/local/zookeeper/conf/zk1.cfg
  4. Starting zookeeper ... STARTED
  5. [root@linux-node2 conf]# /usr/local/zookeeper/bin/zkServer.sh start /usr/local/zookeeper/conf/zk2.cfg
  6. JMX enabled by default
  7. Using config: /usr/local/zookeeper/conf/zk2.cfg
  8. Starting zookeeper ... STARTED
  9. [root@linux-node2 conf]# /usr/local/zookeeper/bin/zkServer.sh start /usr/local/zookeeper/conf/zk3.cfg
  10. JMX enabled by default
  11. Using config: /usr/local/zookeeper/conf/zk3.cfg
  12. Starting zookeeper ... STARTED
  13. [root@linux-node2 conf]# /usr/local/zookeeper/bin/zkServer.sh status /usr/local/zookeeper/conf/zk1.cfg
  14. JMX enabled by default
  15. Using config: /usr/local/zookeeper/conf/zk1.cfg
  16. ^[[AMode: follower
  17. [root@linux-node2 conf]# /usr/local/zookeeper/bin/zkServer.sh status /usr/local/zookeeper/conf/zk2.cfg
  18. JMX enabled by default
  19. Using config: /usr/local/zookeeper/conf/zk2.cfg
  20. Mode: leader
  21. [root@linux-node2 conf]# /usr/local/zookeeper/bin/zkServer.sh status /usr/local/zookeeper/conf/zk3.cfg
  22. JMX enabled by default
  23. Using config: /usr/local/zookeeper/conf/zk3.cfg
  24. Mode: follower

从以上状态来看目前zk2是leader,其它两个节点是follower
连接Zookeeper

  1. [root@linux-node2 conf]# /usr/local/zookeeper/bin/zkCli.sh -server192.168.56.12:2181

七、部署mesos

安装mesosphere仓库,需要在Mesos Master和MesosSlave节点均安装

  1. [root@linux-node1 ~]# rpm -ivh http://repos.mesosphere.com/el/7/noarch/RPMS/mesosphere-el-repo-7-1.noarch.rpm
  2. [root@linux-node2 ~]# rpm -ivh http://repos.mesosphere.com/el/7/noarch/RPMS/mesosphere-el-repo-7-1.noarch.rpm

在node1部署mesos和marathon

  1. [root@linux-node1 ~]# yum -y install mesos marathon

增加zookeeper配置

  1. [root@linux-node1 ~]# cat /etc/mesos/zk
  2. zk://192.168.56.12:2181,192.168.56.12:2182,192.168.56.12:2183/mesos

启动mesos master slave 和marathon

  1. [root@linux-node1 ~]# systemctl enable mesos-master mesos-slave
  2. [root@linux-node1 ~]# systemctl enable marathon
  3. [root@linux-node1 ~]# systemctl start mesos-master mesos-slave
  4. [root@linux-node1 ~]# systemctl start marathon

在node2部署mesos

  1. [root@linux-node2 conf]# yum -y install mesos

打开Mesos的Web管理界面,这时候你将得到下图的页面但可能在‘Tasks’表格没有任何的条目。

运行第一mesos任务,可以在web界面查看到task

  1. [root@linux-node1~]# MASTER=$(mesos-resolve `cat /etc/mesos/zk`)
  2. [root@linux-node1~]# mesos-execute --master=$MASTER --name="cluster-test"--command="sleep 60"

八、使用marathon调用mesos管理docker容器

下载docker,并pull下来nginx镜像(两个node均操作)

  1. [root@linux-node1 ~]# yum install -y docker
  2. [root@linux-node1 ~]# systemctl enable docker
  3. [root@linux-node1 ~]# systemctl start docker
  4. [root@linux-node1 ~]# docker pull nginx

再所有mesos-slave上增加配置参数,并重启

  1. [root@linux-node1 opt]# echo 'docker,mesos' | tee /etc/mesos-slave/containerizers
  2. docker,mesos
  1. [root@linux-node2 opt]# echo 'docker,mesos' | tee /etc/mesos-slave/containerizers
  2. docker,mesos

通过mesos调度,使用marathon来创建一个nginx镜像的docker容器,matathon默认监听8080端口,如下图

matathon通过zookeeper,marathon启动的时候会读取/etc/mesos/zk配置文件,通过Zookeeper来找到Mesos Master。marathon有自己的REST API,我们通过API的方式来创建一个nginx的docker容器。首先创建如下的配置文件nginx.json:

  1. [root@linux-node1 ~]# cat nginx.json
  2. {
  3. "id":"nginx",
  4. "cpus":0.2,
  5. "mem":32.0,
  6. "instances": 1,
  7. "constraints": [["hostname", "UNIQUE",""]],
  8. "container": {
  9. "type":"DOCKER",
  10. "docker": {
  11. "image": "nginx",
  12. "network": "BRIDGE",
  13. "portMappings": [
  14. {"containerPort": 80, "hostPort": 0,"servicePort": 0, "protocol": "tcp" }
  15. ]
  16. }
  17. }
  18. }

使用curl的方式调用

  1. [root@linux-node2 ~]# curl -X POST http://192.168.56.11:8080/v2/apps -d @/root/nginx.json -H "Content-type: application/json"
  2. {"id":"/nginx2","cmd":null,"args":null,"user":null,"env":{},"instances":1,"cpus":0.1,"mem":10,"disk":0,"executor":"","constraints":[["hostname","UNIQUE",""]],"uris":[],"fetch":[],"storeUrls":[],"ports":[0],"requirePorts":false,"backoffSeconds":1,"backoffFactor":1.15,"maxLaunchDelaySeconds":3600,"container":{"type":"DOCKER","volumes":[],"docker":{"image":"nginx","network":"BRIDGE","portMappings":[{"containerPort":80,"hostPort":0,"servicePort":0,"protocol":"tcp"}],"privileged":false,"parameters":[],"forcePullImage":false}},"healthChecks":[],"dependencies":[],"upgradeStrategy":{"minimumHealthCapacity":1,"maximumOverCapacity":1},"labels":{},"acceptedResourceRoles":null,"ipAddress":null,"version":"2016-02-24T09:21:01.876Z","tasksStaged":0,"tasksRunning":0,"tasksHealthy":0,"tasksUnhealthy":0,"deployments":[{"id":"ee83ba9a-35d8-4e9a-84e1-678f87bd0ba6"}],"tasks":

查看通过API和手动创建的容器

  1. [root@linux-node1 ~]# docker ps -a
  2. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  3. a8acac668a11 nginx "nginx -g 'daemon off" 56 seconds ago Up 55 seconds 443/tcp, 0.0.0.0:31933->80/tcp mesos-7ea34cc7-256a-40d2-bacf-1d2830503970-S0.e79c17ff-6a17-4392-b480-6de57c55efff
  4. a163fc688287 nginx "nginx -g 'daemon off" 2 minutes ago Up 2 minutes 443/tcp, 0.0.0.0:31108->80/tcp mesos-7ea34cc7-256a-40d2-bacf-1d2830503970-S0.7af05686-1b75-4987-be0d-121870081f58

访问31108端口,查看nginx

在marathonweb界面查看

在mesos的web界面查看

0
未经许可,不得转载,否则将受到作者追究,博主联系方式见首页右上角

该文章由 发布

这货来去如风,什么鬼都没留下!!!
发表我的评论
取消评论
代码 贴图 加粗 链接 删除线 签到