随着”互联网+”时代的业务增长、变化速度及大规模计算的需求,廉价的、高可扩展的分布式 x86 集群已成为标准解决方案,如 Google 已经在几千万台服务器上部署分布式系统。Docker 及其相关技术的出现和发展,又给大规模集群管理带来了新的想象空间。如何将二者进行有效地结合?下面将记录使用 Mesos+Zookeeper+Marathon+Docker 分布式部署 Paas 云平台环境,其中:
1234 | 1)Mesos:Mesos 采用与 Linux kernerl 相同的机制,只是运行在不同的抽象层次上。Mesos kernel 利用资源管理和调度的 API 在整个数据中心或云环境中运行和提供引用(例如,Hadoop,Spark,Kafaka,Elastic Search)。 2)Zookeeper:zooKeeper 是一个分布式的,开放源码的分布式应用程序协调服务,是 Google 的 Chubby 一个开源的实现,是 Hadoop 和 Hbase 的重要组件。它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、名字服务、分布式同步、组服务等。 3)Marathon:marathon 是一个mesos框架,能够支持运行长服务,比如 web 应用等。是集群的分布式 Init.d,能够原样运行任何 Linux 二进制发布版本,如 Tomcat Play 等等,可以集群的多进程管理。也是一种私有的 Pass,实现服务的发现,为部署提供提供 REST API 服务,有授权和 SSL、配置约束,通过 HAProxy 实现服务发现和负载平衡 4)Docker:Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。 |
一、Mesos 是什么?
Mesos 是 Apache 下的开源分布式资源管理框架,它被称为是分布式系统的内核。Mesos 能够在同样的集群机器上运行多种分布式系统类型,更加动态有效率低共享资源。提供失败侦测,任务发布,任务跟踪,任务监控,低层次资源管理和细粒度的资源共享,可以扩展伸缩到数千个节点。Mesos 已经被 Twitter 用来管理它们的数据中心。
Mesos 中的基本术语解释:
12345678910111213141516171819 | 1)Mesos-master:主要负责管理各个 framework 和 slave,并将 slave 上的资源分配给各个 framework 2)Mesos-slave:负责管理本节点上的各个mesos-task,比如:为各个 executor 分配资源 3)Framework:计算框架,如:Hadoop,Spark 等,通过 MesosSchedulerDiver 接入 Mesos 4)Executor:执行器,安装到mesos-slave 上,用于启动计算框架中的 task。 其中: 1)Mesos-master 是整个系统的核心,负责管理接入mesos的各个 framework(由 frameworks_manager 管理)和 slave(由 slaves_manager 管理),并将 slave 上的资源按照某种策略分配给 framework(由独立插拔模块 Allocator 管 理)。 2)Mesos-slave 负责接收并执行来自mesos-master 的命令、管理节点上的mesos-task,并为各个 task 分配资源。 mesos-slave 将自己的资源量发送给 mesos-master,由 mesos-master 中的 Allocator 模块决定将资源分配给哪个 framework, 前考虑的资源有 CPU 和内存两种,也就是说,mesos-slave 会将 CPU 个数和内存量发送给 mesos-master,而用 户提交作业时,需要指定每个任务需要的 CPU 个数和内存量,这样,当任务运行时,mesos-slave 会将任务放到包含固定资源 的 linux container 中运行,以达到资源隔离的效果。很明显,master 存在单点故障问题,为此,mesos 采用了 zookeeper 解决该问题。 3)Framework 是指外部的计算框架,如 Hadoop,Mesos 等,这些计算框架可通过注册的方式接入 mesos,以便 mesos 进行统一管理 和资源分配。Mesos 要求可接入的框架必须有一个调度器模块,该调度器负责框架内部的任务调度。 当一个 framework 想要接入 mesos 时,需要修 改自己的调度器,以便向 mesos 注册,并获取 mesos 分配给自己的资源, 这样再由自己的调度器将这些资源分配给框架中的任务,也就是说,整个 mesos 系统采用了双层调度框架: 第一层,由 mesos 将资源分配给框架;第二层, 框架自己的调度器将资源分配给自己内部的任务。当前 Mesos 支持三种语言编写的调度器,分别是 C++,java 和 python,为了向各种调度器提供统 一的接入方式,Mesos 内部采用 C++实现了一个 MesosSchedulerDriver(调度器驱动器),framework 的调度器可调用该 driver 中的接口与 Mesos-master 交互,完成一系列功能(如注册,资源分配等)。 4)Executor 主要用于启动框架内部的 task。由于不同的框架,启动 task 的接口或者方式不同,当一个新的框架要接入 mesos 时,需要编写 一个 executor,告诉 mesos 如何启动该框架中的 task。为了向各种框架提供统一的执行器编写方式, Mesos 内部采用 C++实现了一个 MesosExecutorDiver(执行器驱动器),framework 可通过该驱动器的相关接口告诉 mesos 启动 task 的方法。 |
先来看下 Mesos 的基础架构
首先 Mesos 是一个 Master/Agent 的架构方式,其中:
12345678 | 1)Master 负责资源的统一管理跟任务的分发 2)Agent 负责起停执行器,汇报主机资源、执行器状态等信息。 3)一般情况下,会启动 3 个以上 Master,以确保高可用,Master 的状态由Zookeeper维护。 4)Framework 是 Mesos 上的调度框架,Marathon Hadoop Chonous 都是比较常见的任务调度框架。 这样的架构给人的整体感受就清晰明朗了。另外: 1)每台机器上都会部署一个 Mesos-Agent,Agent 会把信息汇报给 Master。 2)调度器 scheduler 向 Mesos-Master 请求资源,Mesos-Master 把所有可用的资源都反馈给 Scheduler,Scheduler 根据自己的规则决定该部署到哪一台。大致就是这样一个流程。 |
Mesos 总体架构图如下:
上图展示了 mesos 的重要组成部分:
123456 | 1)mesoso 由一个 master 进程管理运行着每个客户端节点的 salve 进程和跑任务的 mesos 计算框架。master 进程通过计算框架可以很细致的管理 cpu 和内存等,从而提供资源。 每个资源提供与包含了一个清单(slave ID, resource1: amount1, resource2, amount2, …),master 会根据现有的政府决定提供每个计算框架多少资源,例如公平分享或者根据优先级分享。 为了支持不同种的政策,master 通过插件机制新增了一个 allocation 模块使之分配资源更简单方便。 2)一个计算框架运行在两个组件之上,一个是 scheduler,他是 master 提供资源的注册中心,另一个是 executor 程序,用来发起在 slave 节点上运行计算框架的任务。 master 决定给每个计算框架提供多少计算资源,计算框架的的调度去选择使用哪个资源。当一个计算框架接受了提供的资源,他会通过 mesos 的任务描述运行程序,mesos 也会在相应的 slave 上发起任务。 |
从上面图中可以看到,Mesos 有 Framework(Framework 里面有 Scheduler), Master(Master 里面有 Allocator)、Agent、Executor、Task 几部分组成。
这里面有两层的 Scheduler,一层在 Master 里面,Allocator 会将资源公平的分给每一个 Framework,二层在 Framework 里面,Framework 的 Scheduler 将资源按规则分配给 Task。
Mesos 的这几个角色在一个任务运行的生命周期中,相互关系如下:
Agent 会将资源汇报给 Master,Master 会根据 Allocator 的策略将资源 offer 给 Framework 的 Scheduler。Scheduler 可以 accept 这个资源,运行一个 Task,Master 将 Task 交给 Agent,Agent 交给 Executor 去真正的运行这个 Task。
Mesos 资源提供的例子
简单梳理下以上图中的流程步骤:
12345 | 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。 除此之外,当任务完成,新的资源成为空闲时,这个资源提供程序将会重复。 |
Mesos 框架是一个在 Mesos 上运行分布式应用的应用程序,它有两个组件:
12 | 1)调度器 : 与 Mesos 交互,订阅资源,然后在 mesos 从服务器中加载任务。 2)执行器 : 从框架的环境变量 配置中获得信息,在 mesos 从服务器中运行任务。 |
下面看看其是如何实现资源调用?Mesos 通过”resources offers” 分配资源,资源其实是当前可用资源的一个快照,调度器将使用这些资源在 mesos 从服务器上运行任务。
Mesos 主从服务器调度资源的顺序图如下:
首先由 Mesos 主服务器查询可用资源给调度器,第二步调度器向主服务器发出加载任务,主服务器再传达给从服务器,从服务器向执行器命令加载任务执行,执行器执行任务以后,将状态反馈上报给从服务器,最终告知调度器 。
从服务器下管理多个执行器,每个执行器是一个容器,以前可以使用 Linux 容器 LXC,现在使用 Docker 容器。
Mesos 失败恢复和高可用性
12 | Mesos 主服务器使用Zookeeper进行服务选举和发现。它有一个注册器记录了所有运行任何和从服务器信息,使用 MultiPaxos 进行日志复制实现一致性。 Mesos 有一个从服务器恢复机制,无论什么时候一个从服务器死机了,用户的任务还是能够继续运行,从服务器会将一些关键点信息如任务信息状态更新持久化到本地磁盘上,重新启动时可以从磁盘上恢复运行这些任务(类似 Java 中的钝化和唤醒) |
二、 Zookeeper是什么?
ZooKeeper 是用来给集群服务维护配置信息,域名服务,提供分布式同步和提供组服务。所有这些类型的服务都使用某种形式的分布式应用程序。ZooKeeper 是一个分布式的,开放源码的协调服务,是的 Chubby 一个的实现,是 Hadoop 和 Hbase 的重要组件。
ZooKeeper 角色
1234 | 领导者(leader):领导者负责投票发起和决议,更新系统状态 跟随者(follwoer):follower 用于接收客户请求并向客户端返回结果,在选主过程中参与投票 观察者:ObServer 可以接受客户端连接,将写请求转发给 leader 节点,但 ObServer 不参加投票过程,只同步 leader 的状态,ObServer 的目的是为了拓展系统,提高读取速度。 客户端:请求发起方 |
ZooKeeper 的工作原理
123456 | Zookeeper的核心是原子广播,这个机制保证了各个 Server 之间的同步。实现这个机制的协议叫做 Zab 协议。Zab 协议有两种模式,它们分别是恢复模式(选主)和广播模式(同步)。当服务启动或者在领导者崩溃后,Zab 就进入了恢复模式,当领导者被选举出来,且大多数 Server 完成了和 leader 的状态同步以后,恢复模式就结束了。状态同步保证了 leader 和 Server 具有相同的系统状态。 为了保证事务的顺序一致性,zookeeper 采用了递增的事务 id 号(zxid)来标识事务。所有的提议(proposal)都在被提出的时候加上了 zxid。实现中 zxid 是一个 64 位的数字,它高 32 位是 epoch 用来标识 leader 关系是否改变,每次一个 leader 被选出来,它都会有一个新的 epoch,标识当前属于那个 leader 的统治时期。低 32 位用于递增计数。 每个 Server 在工作过程中有三种状态: 1)LOOKING:当前 Server 不知道 leader 是谁,正在搜寻 2)LEADING:当前 Server 即为选举出来的 leader 3)FOLLOWING:leader 已经选举出来,当前 Server 与之同步 |
ZooKeeper 选主流程
123456789 | 当 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。其流程图如下所示:
ZooKeeper 同步流程
123456 | 选完 leader 以后,zookeeper 就进入状态同步过程。 1)leader 等待 server 连接; 2)Follower 连接 leader,将最大的 zxid 发送给 leader; 3)Leader 根据 follower 的 zxid 确定同步点; 4)完成同步后通知 follower 已经成为 uptodate 状态; 5)Follower 收到 uptodate 消息后,又可以重新接受 client 的请求进行服务了。 |
流程图如下所示:
ZooKeeper 工作流程
1)Leader 工作流程
123456 | Leader 主要有三个功能: 1)恢复数据; 2)维持与 Learner 的心跳,接收 Learner 请求并判断 Learner 的请求消息类型; 3)Learner 的消息类型主要有 PING 消息、REQUEST 消息、ACK 消息、REVALIDATE 消息,根据不同的消息类型,进行不同的处理。 PING 消息是指 Learner 的心跳信息;REQUEST 消息是 Follower 发送的提议信息,包括写请求及同步请求;ACK 消息是 Follower 的对提议的回复,超过半数的 Follower 通过,则 commit 该提议;REVALIDATE 消息是用来延长 SESSION 有效时间。 |
Leader 的工作流程简图如下所示,在实际实现中,流程要比下图复杂得多,启动了三个线程来实现功能。
2)Follower 工作流程
123456789101112 | 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是一个成熟的,轻量级的,扩展性很强的 Apache Mesos 的容器编排框架,它主要用来调度和运行常驻服务(long-running service),提供了友好的界面和 Rest API 来创建和管理应用。marathon 是一个 mesos 框架,能够支持运行长服务,比如 web 应用等,它是集群的分布式 Init.d,能够原样运行任何 Linux 二进制发布版本,如 Tomcat Play 等等,可以集群的多进程管理。也是一种私有的 Pass,实现服务的发现,为部署提供提供 REST API 服务,有授权和 SSL、配置约束,通过 HAProxy 实现服务发现和负载平衡。
这样,我们可以如同一台 Linux 主机一样管理数千台服务器,它们的对应原理如下图,使用Marathon类似 Linux 主机内的 init Systemd 等外壳管理,而 Mesos 则不只包含一个 Linux 核,可以调度数千台服务器的 Linux 核,实际是一个数据中心的内核:
Marathon中重要的概念介绍
1)Application 是 Marathon 中一个重要的核心概念,它代表了一个长服务。
2)Application definition 表示一个长服务的定义,规定了一个 Application 启动和运行时的所有行为。Marathon 提供了两种方式让你来定义你的长服务,第一种通过 Portal 来定义,它方便终端用户的理解和使用,另一种是通过 JSON 格式的文件来定义,并通过 RestAPI 的方式来创建和管理这个 Application,这种方式方便和第三方的系统进行集成,提供了再次的可编程接口。
3)Application instance 表示一个 Application 的实例,也称作 Mesos 的一个 task。Marathon 可以为一个 Application 创建和管理多个实例,并可以动态的增大和减小某个 Application 实例的个数,并且通过 Marathon-lb 实现服务发现和负载均衡。
4)Application Group:Marathon 可以把多个 Application 组织成一棵树的结构,Group 称为这个树的树枝,Application 称为这个树的叶子。同一个 Group 中的 Application 可以被 Marathon 统一管理。
5)Deployments:对 Application 或者 Group 的 definition 的一次修改的提交称为一次 deployment。它包括创建,销毁,扩容缩容 Application 或者 Group 等。多个 deployments 可以同时进行,但是对于一个应用的 deployments 必须是串行的,如果前一个 deployment 没有结束就执行下一个 deployment,那么它将会被拒绝。
————————————————————————————————————————————–
四、Mesos+Zookeeper+Marathon 的 Docker管理平台部署过程记录
1)服务器架构
机器信息如下:
12345 | 这里部署的机器为 3 个 Mastser 控制节点,3 个 Slave 运行节点,其中: zookeeper、Mesos-master、marathon 运行在 Master 端;Mesos-slave 和docker运行在 Slave 端;需要修改 zk 的内容来保证 slave 能够被 master 发现和管理 这里为了测试方便,全部采用 centos7 版本系统。当然,在实际生产环境中,也不一定非要要求 master 和 slave 端的服务器版本一致,不一样的版本系统也可以。 (当机器数量没有这么多比如只有两台机器的情况下,可以将一台机器即作为 Mesos-Master 也作为 Mesos-Slave,另一台作为 Mesos-Slave,也就是一主两从的结构) |
为了直观的理解,简单的画了一张架构图:
2)配置 mesos-master(3 台 master 节点都要操作)
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138 | 1)关闭防火墙和 selinux 关闭 selinux [root@master-1 ~] # vim /etc/sysconfig/selinux SELINUX=disabled [root@master-1 ~] # setenforce 0 #临时关闭。reboot 重启机器后,使得上面配置生效,就永久关闭 selinux 了 [root@master-1 ~] # getenforce Permissive 关闭 iptables 防火墙。 如果不关闭,需要开启 2181,5050,8080 端口 [root@master-1 ~] # vim /etc/sysconfig/iptables ....... -A INPUT -p tcp -m state --state NEW -m tcp --dport 2181 -j ACCEPT -A INPUT -p tcp -m state --state NEW -m tcp --dport 5050 -j ACCEPT -A INPUT -p tcp -m state --state NEW -m tcp --dport 8080 -j ACCEPT [root@master-1 local ] # systemctl restart iptables.service 2)添加 mesos 的 yum 源 [root@master-1 ~] # rpm -Uvh http://repos.mesosphere.io/el/7/noarch/RPMS/mesosphere-el-repo-7-1.noarch.rpm 3)安装 mesos,marathon,zookeeper [root@master-1 ~] # yum install -y java-1.8.0-openjdk-devel java-1.8.0-openjdk #安装依赖的 JDK 环境 [root@master-1 ~] # yum -y install mesos marathon mesosphere-zookeeper 4)配置 zookeeper 设置文件 /var/lib/zookeeper/myid 为当前 mesos master 节点的 id , id 必须为 1-255 之中的整数. master-1 机器设置 id 为 "1" [root@master-1 ~] # echo 1 > /var/lib/zookeeper/myid master-2 机器设置 id 为 "2" [root@master-2 ~] # echo 2 > /var/lib/zookeeper/myid master-3 机器设置 id 为 "3" [root@master-3 ~] # echo 3 > /var/lib/zookeeper/myid [root@master-1 ~] # cp /etc/zookeeper/conf/zoo.cfg /etc/zookeeper/conf/zoo.cfg.bak [root@master-1 ~] # vim /etc/zookeeper/conf/zoo.cfg maxClientCnxns=50 #单个客户端与单台服务器之间的连接数的限制,是 ip 级别的,默认是 50,如果设置为 0,那么表明不作任何限制。请注意这个限制的使用范围,仅仅是单台客户端机器与单台 ZK 服务器之间的连接数限制,不是针对指定客户端 IP,也不是 ZK 集群的连接数限制,也不是单台 ZK 对所有客户端的连接数限制。 tickTime=2000 #Zookeeper 服务器之间或客户端与服务器之间维持心跳的时间间隔,也就是每个 tickTime 时间就会发送一个心跳 initLimit=10 #Zookeeper 的 Leader 接受客户端(Follower)初始化连接时最长能忍受多少个心跳时间间隔数。当已经超过 5 个心跳的时间(也就是 tickTime)长度后 Zookeeper 服务器还没有收到客户端的返回信息,那么表明这个客户端连接失败。总的时间长度就是 5*2000=10 秒 syncLimit=5 #表示 Leader 与 Follower 之间发送消息时请求和应答时间长度,最长不能超过多少个 tickTime 的时间长度,总的时间长度就是 2*2000=4 秒 dataDir= /var/lib/zookeeper #zookeeper 数据文件存放目录 clientPort=2181 #客户端连接端口 server.1=182.48.115.233:2888:3888 #数字 1,2,3 表示这个是第几号服务器(是上面 myid 文件里对应的数字);中间的是 master 主节点的 ip 地址 server.2=182.48.115.235:2888:3888 #第一个端口 2888(这个端口可以自己定义)表示的是这个服务器与集群中的 Leader 服务器交换信息的端口 server.3=182.48.115.236:2888:3888 #第二个端口 3888 表示的是万一集群中的 Leader 服务器挂了,需要一个端口来重新进行选举,选出一个新的 Leader,而这个端口就是用来执行选举时服务器相互通信的端口。 [root@master-1 ~] # vim /etc/mesos/zk #完全替换原来内容 zk: //182 .48.115.233:2181,182.48.115.235:2181,182.48.115.236:2181 /mesos 设置文件 /etc/master-/quorum 内容为一个大于(master 节点数除以 2)的整数。即采用四舍五入,比如这里有 3 个 master 节点,那么 3 /2 =1.5,四舍五入为 2 [root@master-1 ~] # echo 2 >/etc/mesos-master/quorum [root@master-1 ~] # cat /etc/mesos-master/quorum 2 5)配置 mesos 和 marathon 主机名和 ip 要在 hosts 中写入,最好不要使用 localhost,否则会出现 slave 不能识别,以及 marathon 任务下发不正常等现象。 master-1 机器 [root@master-1 ~] # mkdir -p /etc/marathon/conf [root@master-1 ~] # echo 182.48.115.233 > /etc/mesos-master/hostname [root@master-1 ~] # echo 182.48.115.233 > /etc/marathon/conf/hostname [root@master-1 ~] # hostnamectl --static set-hostname master-1.com [root@master-1 ~] # echo "182.48.115.233 master-1 master-1.com" >/etc/hosts [root@master-1 ~] # cat /etc/hosts 182.48.115.233 master-1 master-1.com master-2 机器 [root@master-2 ~] # mkdir -p /etc/marathon/conf [root@master-2 ~] # echo 182.48.115.235 > /etc/mesos-master/hostname [root@master-2 ~] # echo 182.48.115.235 > /etc/marathon/conf/hostname [root@master-2 ~] # hostnamectl --static set-hostname master-2.com [root@master-2 ~] # echo "182.48.115.235 master-2 master-2.com" >/etc/hosts [root@master-2 ~] # cat /etc/hosts 182.48.115.235 master-2 master-2.com master-3 机器 [root@master-3 ~] # mkdir -p /etc/marathon/conf [root@master-3 ~] # echo 182.48.115.236 > /etc/mesos-master/hostname [root@master-3 ~] # echo 182.48.115.236 > /etc/marathon/conf/hostname [root@master-3 ~] # hostnamectl --static set-hostname master-3.com [root@master-3 ~] # echo "182.48.115.236 master-3 master-3.com" >/etc/hosts [root@master-3 ~] # cat /etc/hosts 182.48.115.236 master-3 master-3.com [root@master-1 ~] # cp /etc/mesos/zk /etc/marathon/conf/master [root@master-1 ~] # cp /etc/mesos/zk /etc/marathon/conf/zk [root@master-1 ~] # sed -i 's|mesos|marathon|g' /etc/marathon/conf/zk 6)启动 mesos,marathon,zookeeper [root@master-1 ~] # systemctl enable zookeeper && systemctl enable mesos-master && systemctl enable marathon [root@master-1 ~] # systemctl start zookeeper && systemctl start mesos-master && systemctl start marathon [root@master-1 ~] # systemctl disable mesos-slave 查看进程状态 [root@master-1 ~] # systemctl status zookeeper [root@master-1 ~] # systemctl status mesos-master [root@master-1 ~] # systemctl status marathon [root@master-1 ~] # lsof -i:2181 [root@master-1 ~] # lsof -i:5050 [root@master-1 ~] # lsof -i:8080 7)检查配置 配置过程中出错,为了方便检查对比各 master 配置,直接执行如下命令。 [root@master-1 ~] # cat /var/lib/zookeeper/myid && tail -6 /etc/zookeeper/conf/zoo.cfg && cat /etc/mesos/zk && cat /etc/mesos-master/quorum && cat /etc/mesos-master/hostname&& cat /etc/marathon/conf/hostname&& cat /etc/marathon/conf/master&&cat /etc/marathon/conf/zk 1 syncLimit=5 dataDir= /var/lib/zookeeper clientPort=2181 server.1=182.48.115.233:2888:3888 server.2=182.48.115.235:2888:3888 server.3=182.48.115.236:2888:3888 zk: //182 .48.115.233:2181,182.48.115.235:2181,182.48.115.236:2181 /mesos 2 182.48.115.233 182.48.115.233 zk: //182 .48.115.233:2181,182.48.115.235:2181,182.48.115.236:2181 /mesos zk: //182 .48.115.233:2181,182.48.115.235:2181,182.48.115.236:2181 /marathon -------------------------------------------------------------------------------------------------------- 温馨提示: 1) 还可以创建 /etc/mesos-master/cluster 文件,写入集群的别名。 2)主机名最好不要轻易更换,否则会导致 mesos 启动失败!更换主机名后,最好彻底卸载并删除源数据,然后重新部署 # yum remove mesos marathon mesosphere-zookeeper # rm -rf /etc/mesos* # rm -rf /etc/marathon* # rm -rf /var/lib/zookeeper* # rm -rf /etc/zookeeper* # rm -rf /var/lib/mesos* #源数据目录 # yum -y install mesos marathon mesosphere-zookeeper 3)以上操作后,master 节点机不能 ping 通外网,是因为 DNS 解析文件被改变了,执行下面命令即可: [root@master-1 local ] # echo "nameserver 8.8.8.8" >> /etc/resolv.conf [root@master-1 local ] # ping www.baidu.com PING www.a.shifen.com (14.215.177.38) 56(84) bytes of data. 64 bytes from 14.215.177.38: icmp_seq=1 ttl=53 time =38.3 ms ................ |
3)配置 slave 节点(3 台 slave 节点都要操作)
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384 | 1)关闭 selinux 和 iptables 防火墙 关闭 selinux [root@slave-1 ~] # vim /etc/sysconfig/selinux SELINUX=disabled [root@slave-1 ~] # setenforce 0 #临时关闭。reboot 重启机器后,使得上面配置生效,就永久关闭 selinux 了 [root@slave-1 ~] # getenforce Permissive 关闭 iptables 防火墙。 如果不关闭,需要开启 5051 端口 [root@slave-1 ~] # vim /etc/sysconfig/iptables ....... -A INPUT -p tcp -m state --state NEW -m tcp --dport 5051 -j ACCEPTT [root@slave-1 ~] # systemctl restart iptables.service 2)安装docker,安装后启动docker [root@slave-1 ~] # yum install -y docker [root@slave-1 ~] # systemctl enable docker [root@slave-1 ~] # systemctl start docker 拉取镜像(三台 slave 节点机都需要下载镜像,因为在 marathon 界面里创建 docker 容器,是随机在 slave 节点机上读取镜像创建的) [root@slave-1 ~] # docker pull nginx [root@slave-1 ~] # docker pull tomcat [root@slave-1 ~] # docker images REPOSITORY TAG IMAGE ID CREATED SIZE docker.io /tomcat latest 08f8166740f8 4 days ago 366.7 MB docker.io /nginx latest 46102226f2fd 2 weeks ago 109.4 MB 3)添加 mesos 的 yum 源 [root@slave-1 ~] # rpm -Uvh http://repos.mesosphere.io/el/7/noarch/RPMS/mesosphere-el-repo-7-1.noarch.rpm 4)安装 mesos [root@slave-1 ~] # yum -y install mesos 5)配置 master 信息 slave-1 机器 [root@slave-1 ~] # echo 182.48.115.237 > /etc/mesos-slave/hostname [root@slave-1 ~] # hostnamectl --static set-hostname slave-1.com [root@slave-1 ~] # echo "182.48.115.237 slave-1 slave-1.com" >/etc/hosts [root@slave-1 ~] # cat /etc/hosts 182.48.115.237 slave-1 slave-1.com slave-2 机器 [root@slave-2 ~] # echo 182.48.115.238 > /etc/mesos-slave/hostname [root@slave-2 ~] # hostnamectl --static set-hostname slave-2.com [root@slave-2 ~] # echo "182.48.115.238 slave-2 slave-2.com" >/etc/hosts [root@slave-2 ~] # cat /etc/hosts 182.48.115.238 slave-2 slave-2.com slave-3 机器 [root@slave-3 ~] # echo 182.48.115.239 > /etc/mesos-slave/hostname [root@slave-3 ~] # hostnamectl --static set-hostname slave-3.com [root@slave-3 ~] # echo "182.48.115.239 slave-3 slave-3.com" >/etc/hosts [root@slave-3 ~] # cat /etc/hosts 182.48.115.239 slave-3 slave-3.com [root@slave-1 ~] # vim /etc/mesos/zk zk: //182 .48.115.233:2181,182.48.115.235:2181,182.48.115.236:2181 /mesos 配置 marathon 调用 mesos 运行 docker 容器 [root@slave-1 ~] # echo 'docker,mesos' > /etc/mesos-slave/containerizers 6)启动 slave(要保证 mesos-slave 启动后,读取的 zk 信息是那三个 mesos-master 的连接信息,否则 mesos 访问页面里就不会出现这个 slave 节点信息。 ps -ef| grep mesos-slave) [root@slave-1 ~] # systemctl start mesos-slave && systemctl enable mesos-slave [root@slave-1 ~] # systemctl disable mesos-master ------------------------------------------------------------------------------------------------------- 温馨提示: 1)以上操作后,master 节点机不能 ping 通外网,是因为 DNS 解析文件被改变了,执行下面命令即可: [root@slave-1 ~] #echo "nameserver 8.8.8.8" >> /etc/resolv.conf [root@slave-1 ~] # ping www.baidu.com PING www.a.shifen.com (14.215.177.38) 56(84) bytes of data. 64 bytes from 14.215.177.38: icmp_seq=1 ttl=53 time =38.3 ms ....... 2)如果 mesos-slave 启动失败,可以如下检查: [root@slave-1 ~] # journalctl -f -u mesos-slave #journalctl -f -u mesos-master 可以检查 master 端的 mesos-slave 启动失败(比如主机名改变导致),可以删除源数据,卸载干净,然后重新安装部署 # yum remove mesos # rm -rf /etc/mesos* # rm -rf /var/lib/mesos* #源数据目录是/var/lib/mesos/meta # yum install mesos |
4)访问 web 管理页面
访问 mesos 的管理页面,即访问 http://master_ip:5050
注意:master_ip 是这 3 个 master 中的任意一个就行,经过 zookeeper 选主,会自动跳到了 leader 的页面,如图 mesos 的 leader 为 182.48.115.236(即 master3 被选为 leader master)
在 Frameworks 中已经能够识别 marathon,此时 marathon 的 leader 为 182.48.115.236.
注意:mesos 和 marathon 都是有 zookeeper 来选举 leader,但是选主过程彼此独立,就是 mesos 的 leader 和 marathon 的 leader 可以不一样。如图这里二者通过 zookeeper 选出的 leader 是同一台机器(即都是 master3:182.48.115.236)
点击”Agents”,发现已经能够识别出三个 slave。
注意:这里访问 mesos 显示的是”Agents”选项,老版本的 mesos 显示的是”Salve“选项
点击上面 3 个 slave 中的任意一个,也能看出它的 master 是 182.48.115.236
访问 marathon 的管理页面,http://master_ip:8080
这里的 master_ip 就是在上面访问 mesos 页面 Frameworks 中识别出的 marathon,即 http://182.48.115.236:8080
或者直接点击 mesos 访问页面 Frameworks 中识别出的 marathon 也可以。
或者点击下图标红的 marathon(即 zookeeper 选出的主 marathon),可以出现 marathon 的管理界面
5)通过 Mesos 调度,使用 marathon 来创建容器
比如创建一个 nginx 镜像的 Docker 容器,Marathon 启动时会读取/etc/mesos/zk 配置文件,Marathon 通过 Zookeeper 来找到 Mesos Master。
Marathon 有自己的 REST API,我们通过 API 的方式来创建一个 Nginx 的 Docker 容器。
首先创建一个 json 文件(这个要在 master 节点机器上创建,任意一台 master 节点机上都可以):
12345678910111213141516171819202122232425262728293031323334 | [root@master-1 ~] # vim nginx.json #nginx 的 docker 镜像要提前创建或下载 { "id" : "nginx" , "cpus" :0.2, "mem" :32.0, "instances" : 1, "constraints" : [[ "hostname" , "UNIQUE" , "" ]], "container" : { "type" : "DOCKER" , "docker" : { "image" : "docker.io/nginx" , #这个 nginx 镜像是在 slave 节点机上通过"docker images"查看到的,镜像名不能写错 "network" : "BRIDGE" , "portMappings" : [ { "containerPort" : 80, "hostPort" : 0, "servicePort" : 0, "protocol" : "tcp" } ] } } } |
接着使用 curl 的方式调用。注意上面的 nginx.json 文件是在/root 路径下的(注意下面命令中 json 文件路径)。
1 | [root@master-1 ~] # curl -X POST http://182.48.115.233:8080/v2/apps -d @/root/nginx.json -H "Content-type: application/json" |
登陆 marathon 界面查看是在哪一台 slave 机器上创建的 docker 容器实例(这个是随机的),点击”running”。(如果容器创建失败,即非”running”状态,可以尝试重启 slave 节点的 docker 服务)
如上截图中可知,这个 nginx 容器是在 slave3 节点机(182.48.115.239)上创建的(注意:如果 slave3 节点机宕机或 docker 服务重启,那么这个 nginx 容器就会自动漂移到其他的 slave 节点机上;另外,通过上面方式创建好的容器,在单个 slave 节点机上删除后,容器也会自动转移到其他 slave 节点机器上,这样就实现了在 slave 节点出现故障时容器自动转移的高可用功能)。可以登陆 slave3 机器查看所创建的容器,如下可知:访问 Docker 随机启动的端口是 31782
123 | [root@slave-3 ~] # docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES b35fff88051e docker.io /nginx "nginx -g 'daemon off" 14 minutes ago Up 14 minutes 0.0.0.0:31782->80 /tcp mesos-6bc17bcc-433c-425e-b85e-232ffa42fe4f-S5.f1a121be-2e79-4856-bd5c-576db3497fba |
访问所创建的 nginx 容器。(marathon ui 界面里创建的 docker 容器映射到宿主机的访问端口默认都是随机分配的(BRIDGE 模式))、可以自己制作应用的 docker 镜像,或者自定义构建容器并提交为新镜像(自己设定应用容器结构),然后根据自己制作的镜像在 Marathon 上创建应用。
接着访问 mesos 页面,可以看到”Active Tasks”有刚才创建的 nginx 任务了。(注意:只有当 mesos 访问界面”Active Tasks”里有容器创建任务时,才说明此容器真正创建成功了)
删除 marathon 创建的 docker 实例。如下图,点击”Destory”即可删除。
然后登陆 slave3 机器,发现在服务器上,这个容器只是被关闭了(docker ps -a),可以选择删除。如果再次在机器上启动这个 nginx 容器,那么在 marathon 上是不会显示的。注意:在节点机器上手动创建的 docker 容器,这些容器信息是不会在 marathon 和 mesos 里展示的。
1234567 | [root@slave-3 ~] # docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES [root@slave-3 ~] # docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES b35fff88051e docker.io /nginx "nginx -g 'daemon off" 30 minutes ago Exited (0) About a minute ago mesos-6bc17bcc-433c-425e-b85e-232ffa42fe4f-S5.f1a121be-2e79-4856-bd5c-576db3497fba [root@slave-3 ~] # docker rm b35fff88051e b35fff88051e |
如上在 marathon 界面里”Destory”删除对应的 application 后,在 mesos 界面的”Active Tasks”里的对应任务也会删除
另外要注意:在 marathon 界面里通过调用 mesos 创建 docker 容器,只能创建应用容器(Application),如 nginx、tomcat、mysql、redis 等,需要映射端口,这里是映射的是宿主机的随机端口。不能创建基本 centos,ubuntu 的系统容器!
—————————————————————————————————————————————-
可以直接在 marathon 界面里手动创建 docker 应用容器:
首先点击 marathon 界面里右上角的”Create Application”
然后填写创建容器的配置信息,如下图,可以点击”New Application”创建页面右上角的”JSON Mode”模式,将上面创建 nginx 容器的 json 文件复制到这里
这样,就可以直接创建一个 docker 应用容器了。(复制写好的 json 文件到这里后,可以再次关闭”JSON Mode”模式,然后对比下所选用的配置)
下面我关闭”JSON mode”模式,手动选择配置信息去创建 tomcat 容器:
Marathon 还可以对 App 应用实现手动扩缩的功能,选择”Scale Application”进行快速扩容。如下图,对上面已创建的 tomcat 应用容器进行扩展到 2 个 Task(注意:这里有 3 个 slave 节点,那么扩展的 Task 实例最好是 2 个,3/2=1.5,即 2 个 Instances;如果扩展多个 Task,会发现多余的创建失败,这时候可以点击”Configuration”修改,修改成 2 个)
——————————————————————————————————
12345678910111213141516171819202122232425262728293031323334353637383940 | 当然也可以手动编写 json 文件进行创建 [root@master-1 ~] # cat tomcat.json { "id" : "tomcat" , "cpus" :1, "mem" :128, "instances" : 1, "constraints" : [[ "hostname" , "UNIQUE" , "" ]], "container" : { "type" : "DOCKER" , "docker" : { "image" : "docker.io/tomcat" , "network" : "BRIDGE" , "portMappings" : [ { "containerPort" : 8080, "hostPort" : 0, "servicePort" : 0, "protocol" : "tcp" } ] } } } [root@master-1 ~] # curl -X POST http://182.48.115.233:8080/v2/apps -d @/root/tomcat.json -H "Content-type: application/json" 也可以将上面的 tomcat.json 文件内容直接复制到 marathon 创建应用容器的 "JSON Mode" 模式里,然后直接点击创建 |
查看容器创建的日志,可以在 marathon 界面里下载,也可以到 mesos 页面里查看或下载。如下图:
点击下面的日志”stderr”和”stdout”就会下载到本地。
也可以到 mesos 页面查看或下载。点击下面 mesos 页面对应容器任务后面的”Sandbox”
—————————————————————————————————————————————
具体配置可以参考 marathon 官方文档:https://mesosphere.github.io/marathon/docs/persistent-volumes.html
里面有关于 json 文件的配置
————————————————–marathon 创建应用使用 volumes—————————————————
在 marathon 界面里创建应用,可以使用 volumes,即映射容器目录到宿主机上,JSON 文件内容如下:
123456789101112131415161718192021222324252627282930 | { "id" : "nginx" , "cmd" : null, "cpus" : 1, "mem" : 128, "disk" : 0, "instances" : 1, "container" : { "docker" : { "image" : "docker.io/nginx" , "network" : "BRIDGE" , "portMappings" : [ { "containerPort" : 80, "protocol" : "tcp" , "name" : null, "labels" : null } ] }, "type" : "DOCKER" , "volumes" : [ { "containerPath" : "/usr/share/nginx/html" , "hostPath" : "/opt/web/www" , "mode" : "RW" } ] } } |
在 marathon 界面里创建 nginx 容器应用时,将上面的 JSON 文件复制到”JSON Mode”模式下,然后创建即可!非”JSON Mode”模式下手动填写,Volumes 选项填写如下
点击”Configuration”,就可以看到容器创建的配置信息,并可以”Edit”修改
注意事项:
123456789 | 1)映射到宿主机的目录 /opt/web/www 要在每个 slave 节点机器上都要创建,并且里面的文件要在每个 slave 节点机上都有,因为容器重启后会在各个 slave 节点之间随机漂移。 2)上面映射的是 nginx 容器应用的站点目录,默认创建后, /usr/share/nginx/html 是空的( /opt/web/www 目录也是空的),所以容器默认访问会出现 403 报错。 只需在 slave 节点的 /opt/web/www 目录下编写 html 文件(如 index.html)即可访问。 3)marathon 里创建好的容器应用,你可以在对应的 slave 机器上登陆容器内修改,但是这个容器应用一旦在 marathon 界面里 restart,那么你之前的修改就没有了。 因为重启应用,就是再次使用初始镜像进行构建了。 4)可以自己制作应用镜像,在镜像里设定好应用的配置文件;或者将自己创建的容器提交为新的镜像。然后在 marathon 界面里根据自己定义的镜像创建应用。 |
—————————————————marathon 创建应用指定访问端口———————————————–
12345678910111213141516171819 | 默认情况下,marathon 创建的应用访问端口是随机分配的,因为 hostPort 默认配置的是 0,具体看下面说明: marathon 创建应用后,会涉及到三个端口:containerPort:、hostPort、servicePort,其中: 1)containerPort:用来指定容器内部的一个端口。当使用 BRIDGE 或 USER 网络模式连接 Docker 容器时,必须将这个属性设置为 port mapping 的一部分。 2)hostPort:用来指定绑定到主机上的一个端口。当使用 BRIDGE 或 USER 网络模式,你可以指定一个 port mapping 将一个主机端口映射到容器端口。在 HOST 网络模式下,默认的请求端口就是主机的端口。 请注意,主机端口只可以通过环境变量提供给一个任务。 3)servicePort:当您在 Marathon 上(不管是通过 REST API 或界面)创建一个新的应用程序,你可以指定一个或多个服务端口给它。 可以指定所有有效的端口号为服务端口,也可以用 0 表示 Marathon 应该自动分配的可用服务端口给应用程序使用。如果你选择自己的服务端口,你必须自己确保,这个端口在所有应用程序中是唯一的。 portMapping:在 Docker BRIDGE 模式下,在容器外部可被访问到的端口都需要做端口映射。端口映射是一个包含 host port, container port, service port 和协议的元组。可以为 Marathon 应用指定多个端口映射; 未指定 hostPort,则其默认值为 0(意味着 Marathon 将随机分配一个)。在 Docker USER 模式下,hostPort 的语义为稍有点变化:USER 模式不需要指定 hostPort,如果未指定 Marathon 不会自动分配一个随机的。这允许在 USER 网络模式下部署容器,包括 containerPort 和发现信息,但不暴露主机网络上的这些端口(意味着将不消耗主机端口资源)。 marathon 创建应用的网络模式介绍: 1)BRIDGE 网络模式:指定 Docker 应用程序使用 BRIDGE 网络模式。在这种模式下,容器端口(容器内部的端口)被映射到主机端口(主机上的端口)。在这种模式下,应用程序被绑定到容器内的指定端口,容器的端口被绑定到主机上的指定端口。 2)USER 网络模式:指定 Docker 应用程序使用 USER 网络模式。在这种模式下,容器端口(容器内部的端口)被映射到主机端口(主机上的端口)。在这种模式下,应用程序被绑定到容器内的指定端口,容器的端口被绑定到主机上的指定端口。在与“用户自定义”Docker 网络集成时,USER 网络模式将会非常有用。在 Mesos 世界,这种网络通常是通过使用与 Mesos CNI 网络隔离的 CNI 插件访问。 3)HOST 网络模式:该种模式在 Marathon 应用为非容器化而其它应用为容器化的情况下使用。在这种模式下,应用程序直接绑定到主机上的一个或多个端口。 |
如下 JSON 文件内容,注意一下:如果 hostport 端口指定了,那么 serviceport 端口也要指定(最好使用大端口),否则会导致应用容器创建失败
123456789101112131415161718192021222324252627282930313233 | { "id" : "nginx" , "cpus" :0.2, "mem" :32.0, "instances" : 1, "constraints" : [[ "hostname" , "UNIQUE" , "" ]], "container" : { "type" : "DOCKER" , "docker" : { "image" : "docker.io/nginx" , "network" : "BRIDGE" , "portMappings" : [ { "containerPort" : 80, "hostPort" : 31030, "servicePort" : 33180, "protocol" : "tcp" } ] } } } |
在 marathon 界面里创建应用,将上面的 JSON 文件内容复制到”JSON Mode”模式下。构建成功后,就会发现该应用容器的访问端口就是上面自己定义的 31030 端口了(如下)
—————————————————其他—————————————————————————–
在 marathon 中,应用是一个完整的概念。每个应用是一个典型的长运行的服务,这个服务有很多实例,并且是运行在多个 slave 节点机上。下面通过一个小示例说明下:
一个内嵌的 shell 脚步
如下通过内嵌的 shell 脚步,编写一个简单的 app,即:
打印 Hello world 到 slave 节点的/mnt/test 文件中,然后 sleep 5 秒,周而复始。可以使用下面的应用定义文件(json 格式)来描述应用(注意:cmd 是要执行的命令。它的值会以/bin/sh -c ${cmd}的方式执行。):
1234567 | { "id" : "basic-0" , "cmd" : "while [ true ] ; do echo 'Hello hello' >> /mnt/test ; sleep 5 ; done" , "cpus" : 0.1, "mem" : 10.0, "instances" : 1 } |
在 marathon 界面里添加应用,采用”JSON Mode “模式,如下:
不采用”JSON Mode”模式,即将上面的 json 文件内容粘贴进去后,去掉右上方的”JSON Mode”模式,也就是只配置”General”选向,其他选项都不配置。注意:marathon 里的应用是一个长运行服务,所以 shell 脚本里要配置长运行动作。
然后到 182.48.115.239 这台 slave 节点机上检查,发现每隔 5 秒钟,就会输出”hello world”到/mnt/test 文件中。如果这台节点机出现故障,就会输出到其他节点机上。
123456789 | [root@slave-3 mnt] # cat /mnt/test Hello hello Hello hello Hello hello Hello hello Hello hello Hello hello Hello hello ....... |
***************当你发现自己的才华撑不起野心时,就请安静下来学习吧***************