参考文档:
mesos:
mesosphere社区版:
mesosphere仓库:
marathon:
chronos:
consul:
docker安装:
一、系统说明
mesos 集群资源管理框架(以集群的形式出现,主决定资源的分配,从负责执行executor),分配资源,提供offer给framework,不负责调度资源,千言万语都在这里了。
marathon 是mesos的framework,容器编排系统,保证长时间的运行任务,类似后台执行或者supervisor。
zooKeeper是一个的,开放源码的协调服务,是的Chubby一个的实现,是Hadoop和Hbase的重要组件。它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置管理维护、域名服务、分布式同步、组服务、健康检查,HA等。
Chronos是一个运行在Mesos之上的具有分布式容错特性的作业调度器。在Airbnb公司,它是cron的替代品。与cron相比,Chronos在很多方面具备优势。比如,它支持ISO8601标准,允许更灵活地定义调度时间;Chronos也支持任务依赖,即一个作业的开始依赖于一些任务的完成,和marathon一样都是听从mesos的指令,给mesos搬砖的。
consul经常拿来和etcd、 zookeeper来对比,他有和etcd一样的服务发现、服务注册功能,也有和etcd、zookeeper一样的配置存储功能,详细的对比在此不再列出。
Registrator是一个独立于服务注册表的自动服务注册/注销组件,一般以容器的方式进行部署。会自动侦测它所在的宿主机上的所有 容器状态(启用/销毁),并根据容器状态到对应的服务注册列表注册/注销服务。去除了需要手动管理Consul服务条目的复杂性,它监视容器的启动和停止,根据容器暴露的端口和环境变量自动注册服务。
事实上, 通过读取同一台宿主机的其他容器 的环境变量进行服务注册、健康检查定义等操作,支持可插拔式的服务注册表配置。
架构图看起来像这样:
mesos架构:
架构图可以看出mesos主要两部分主和从 ,主集群依靠zookeeper
架构图展示了Mesos的重要组成部分,Mesos由一个master进程管理运行着每个客户端节点的slave进程和跑任务的Mesos计算框架。
Mesos进程通过计算框架可以很细致的管理cpu和内存等,从而提供资源。每个资源提供都包含了一个清单(slave ID,resource1:amount1,resource2,amount2,…)master会根据现有的资源决定提供每个计算框架多少资源。例如公平分享或者根据优先级分享。
为了支持不同种的政策,master通过插件机制新增额一个allocation模块使之分配资源更简单方便。
一个计算框架运行在两个组建之上,一个是Scheduler,他是master提供资源的注册中心,另一个是Executor程序,用来发起在slave节点上运行计算框架的任务。master决定给每个计算框架提供多少计算资源,计算框架的调度去选择使用哪种资源。当一个计算框架接受了提供的资源,他会通过Mesos的任务描述运行程序。Mesos也会在相应的slave上发起任务。
Mesos是Apache下的开源分布式资源管理框架,它被称为分布式系统的内核。Mesos最初是由加州大学伯克利分校的AMPLab开发,后在Twitter得到广泛使用。
Mesos-Master:主要负责管理各个framework和slave,并将slave上的资源分配给各个framework。
Mesos-Slave:负责管理本节点上的各个mesos-task,比如:为各个executor分配资源。
Framework:计算框架,如:Hadoop、Spark、Kafaka、ElasticSerach等,通过MesosSchedulerDiver接入Mesos
Executor:执行器,就是安装到每个机器节点的软件,这里就是利用docker的容器来担任执行器的角色。具有启动销毁快,隔离性高,环境一致等特点。
Mesos-Master是整个系统的核心,负责管理接入Mesos的各个framework(由frameworks_manager管理)和slave(由slaves_manager管理),并将slave上的资源按照某种策略分配给framework(由独立插拔模块Allocator管理)。
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解决该问题。
Framework是指外部的计算框架,如果Hadoop、Mesos等,这些计算框架可通过注册的方式接入Mesos,以便Mesos进行统一管理和资源分配。Mesos要求可接入的框架必须有一个调度模块,该调度器负责框架内部的任务调度。当一个framework想要接入Mesos时,需要修改自己的调度器,以便向Mesos注册,并获取Mesos分配给自己的资源,这样再由自己的调度器将这些资源分配给框架中的任务,也就是说,整个Mesos系统采用了双层调度框架:第一层,由Mesos将资源分配给框架。第二层,框架自己的调度器将资源分配给自己内部的任务。当前Mesos支持三中语言编写的调度器,分别是C++、Java、Python。为了向各种调度器提供统一的接入方式,Mesos内部采用C++实现了一个MesosSchedulerDriver(调度驱动器),framework的调度器可调用该driver中的接口与Mesos-master交互,完成一系列功能(如注册,资源分配等。)
Executor主要用于启动框架内部的task。由于不同的框架,启动task的接口或者方式不同,当一个新的框架要接入mesos时,需要编写一个Executor,告诉Mesos如何启动该框架中的task。为了向各种框架提供统一的执行器编写方式,Mesos内部采用C++实现了一个MesosExecutorDiver(执行器驱动器),framework可通过该驱动器的相关接口告诉Mesos启动task的方式。
mesos运行流程:
流程步骤:
1、slave1报告给master他拥有4核cpu和4G剩余内存,Marathon调用allocation政策模块,告诉slave1计算框架1应该被提供可用的资源。
2、master给计算框架1发送一个在slave上可用的资源描述。
3、计算框架的调度器回复给master运行在slave上两个任务相关信息,任务1需要使用2个CPU,内存1G,任务2需使用1个CPU,2G内存。
4、最后,master发送任务给slave,分配适当的给计算框架执行器,继续发起两个任务(图1.1-2虚线处),因为任有1个CPU和1G内存未分配,allocation模块现在或许提供剩下的资源给计算框架2。
除此之外,当任务完成,新的资源成为空闲时,这个资源提供程序将会重复。
二、环境
说明:
主机名 | IP | OS | 安装服务 |
mesos-master1 | 192.168.8.131 | CentOS-7.5 | mesos-master, marathon,zookeeper, consul-server, chronos, consul-template |
mesos-master2 | 192.168.8.132 | CentOS-7.5 | mesos-master, marathon,zookeeper, consul-server, chronos |
mesos-master3 | 192.168.8.133 | CentOS-7.5 | mesos-master, marathon,zookeeper, consul-server, chronos |
mesos-slave1 | 192.168.8.134 | CentOS-7.5 | mesos-slave, docker, registrator |
mesos-slave2 | 192.168.8.135 | CentOS-7.5 | mesos-slave, docker, registrator |
软件版本:
服务 | 版本 | 作用 |
zookeeper | 3.4.12 | 保持各master之间的通信,选举leader、HA |
mesos-master | 1.6.0 | 管理接入mesos的各个framework & slave,并将slave上的资源按照相应策略分配给framework |
mesos-slave | 1.6.0 | 任务执行节点 |
marathon | 1.6.352 | 调度器,用于下发任务,可保持长应用 |
docker | 1.13.1 | 具体执行docker下发任务 |
chronos | 3.0+ | cron-on-mesos,用来运行基于容器的定时任务的Mesos框架 |
consul/ registrator | 1.1.0/ latest | 提供服务自动注册、发现功能 |
consul-template | 0.19.4 | Consul template 搭配consul使用,支持多种负载均衡接入层,如Nginx、Haproxy,LVS |
三、Master节点部署
以节点zk-node1为例,zk-node2/3根据情况调整。
1、准备工作
# systemctl stop firewalld
# setenforce 0
# systemctl disable firewalld
# cat /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.8.131 mesos-master1
192.168.8.132 mesos-master2
192.168.8.133 mesos-master3
192.168.8.134 mesos-slave1
192.168.8.135 mesos-slave2
# yum groupinstall -y "Development Tools"
# yum install -y tar wget git lrzsz lsof
2、zookeeper安装及HA
ZooKeeper运行在java环境下,文档中建议安装jdk 1.7以上版本(含)。
# yum -y install java java-devel
# java -version
openjdk version "1.8.0_171"
OpenJDK Runtime Environment (build 1.8.0_171-b10)
OpenJDK 64-Bit Server VM (build 25.171-b10, mixed mode)
# tar xf zookeeper-3.4.12.tar.gz -C /usr/local
# chown -R root.root /usr/local/zookeeper-3.4.12
# ln -s /usr/local/zookeeper-3.4.12/ /usr/local/zk
# cp /usr/local/zk/conf/zoo_sample.cfg /usr/local/zk/conf/zoo.cfg
zookeeper配置文件详解:
下面就是zoo.cfg配置文件的修改了,那么我们首先要熟悉下zookeeper配置文件。
# cat /usr/local/zk/conf/zoo.cfgdataDir:数据目录dataLogDir:日志目录clientPort:客户端连接端口tickTime:Zookeeper 服务器之间或客户端与服务器之间维持心跳的时间间隔,也就是每隔tickTime 时间就会发送一个心跳。initLimit:Zookeeper的Leader 接受客户端(Follower)初始化连接时最长能忍受多少个心跳时间间隔数。当已经超过 5个心跳的时间(也就是tickTime)长度后 Zookeeper 服务器还没有收到客户端的返回信息,那么表明这个客户端连接失败。总的时间长度就是 5*2000=10 秒syncLimit:表示 Leader 与 Follower 之间发送消息时请求和应答时间长度,最长不能超过多少个tickTime 的时间长度,总的时间长度就是 2*2000=4 秒。server.A=B:C:D:A 是一个数字,表示这个是第几号服务器;B 是这个服务器的 ip 地址;C 表示的是这个服务器与集群中的 Leader 服务器交换信息的端口;D 表示的是万一集群中的 Leader 服务器挂了,需要一个端口来重新进行选举,选出一个新的 Leader,而这个端口就是用来执行选举时服务器相互通信的端口。# grep -Ev "#|^$" /usr/local/zk/conf/zoo.cfg
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/usr/local/zk/data/zk1
dataLogDir=/usr/local/zk/logs
clientPort=2181
maxClientCnxns=60
server.1=192.168.8.131:2888:3888
server.2=192.168.8.132:2888:3888
server.3=192.168.8.133:2888:3888
# mkdir /usr/local/zk/data/zk1 -p
# mkdir /usr/local/zk/logs -p
# echo "1" > /usr/local/zk/data/zk1/myid
# scp -p /usr/local/zk/conf/zoo.cfg root@192.168.8.132:/usr/local/zk/conf/zoo.cfg
# scp -p /usr/local/zk/conf/zoo.cfg root@192.168.8.133:/usr/local/zk/conf/zoo.cfg
# mesos-master2的zk配置,同样需要创建dataDir,dataLogDir目录和myid文件,文件内容2
# sed -i 's/zk1/zk2/g' /usr/local/zk/conf/zoo.cfg
# mkdir /usr/local/zk/data/zk2 -p# mkdir /usr/local/zk/logs -p
# echo "2" > /usr/local/zk/data/zk2/myid
# grep -Ev "#|^$" /usr/local/zk/conf/zoo.cfg
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/usr/local/zk/data/zk2
dataLogDir=/usr/local/zk/logs
clientPort=2181
maxClientCnxns=60
server.1=192.168.8.131:2888:3888
server.2=192.168.8.132:2888:3888
server.3=192.168.8.133:2888:3888
# mesos-master3的zk配置,同样需要创建dataDir,dataLogDir目录和myid文件,文件内容3
# sed -i 's/zk1/zk3/g' /usr/local/zk/conf/zoo.cfg
# mkdir /usr/local/zk/data/zk3 -p# mkdir /usr/local/zk/logs -p
# echo "3" > /usr/local/zk/data/zk3/myid
# grep -Ev "#|^$" /usr/local/zk/conf/zoo.cfg
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/usr/local/zk/data/zk3
dataLogDir=/usr/local/zk/logs
clientPort=2181
maxClientCnxns=60
server.1=192.168.8.131:2888:3888
server.2=192.168.8.132:2888:3888
server.3=192.168.8.133:2888:3888
启动zk服务,查看状态:
# /usr/local/zk/bin/zkServer.sh start
# /usr/local/zk/bin/zkServer.sh status
zk集群各节点状态:
zk各节点端口:
由此可见,集群已经正常运行。
客户端可以通过nc或telnet连接ZooKeeper Server提交指令。
ZooKeeper Client 简单操作:
9个基本操作指令:
3、安装mesos-master&marathon
Mesos 集群部署
Mesos集群有MesosMaster和Mesos Slave两个角色。mesosphere仓库
需要在Mesos Master和MesosSlave节点均安装。# 添加mesosphere repository,根据github mesosphere社区版获取最新repository
# rpm -Uvh http://repos.mesosphere.io/el/7/noarch/RPMS/mesosphere-el-repo-7-2.noarch.rpm
# hostnamectl --static set-hostname mesos-master1 //修改主机名
# yum -y install mesos marathon
4、mesos-master&marathon配置
mesos-master增加zookeeper配置,选主并增加HA:
# vi /etc/mesos/zk
zk://192.168.8.131:2181,192.168.8.132:2181,192.168.8.133:2181/mesos
# scp /etc/mesos/zk root@192.168.8.132:/etc/mesos/zk
# scp /etc/mesos/zk root@192.168.8.133:/etc/mesos/zk
设置文件/etc/master-/quorum内容为一个大于(master节点数除以2)的整数。即采用四舍五入,比如这里有3个master节点,那么3/2=1.5,四舍五入为2。
# echo "2" >/etc/mesos-master/quorum
# cat /etc/mesos-master/quorum
2
# scp /etc/mesos-master/quorum root@192.168.8.132:/etc/mesos-master/quorum
# scp /etc/mesos-master/quorum root@192.168.8.133:/etc/mesos-master/quorum
#
主机名和ip要在hosts中写入,最好不要使用localhost,否则会出现slave不能识别,以及marathon任务下发不正常等现象。
# 默认marathon无相关配置目录/文件
# mkdir -p /etc/marathon/conf
mesos-master1:
# echo "192.168.8.131" >/etc/mesos-master/hostname
# echo "192.168.8.131" >/etc/mesos-master/ip
# echo "192.168.8.131" >/etc/marathon/conf/hostname
# echo "192.168.8.131" >/etc/marathon/conf/ip
mesos-master2:
# echo "192.168.8.132" >/etc/mesos-master/hostname
# echo "192.168.8.132" >/etc/mesos-master/ip
# echo "192.168.8.132" >/etc/marathon/conf/hostname
# echo "192.168.8.132" >/etc/marathon/conf/ip
mesos-master3:
# echo "192.168.8.133" >/etc/mesos-master/hostname
# echo "192.168.8.133" >/etc/mesos-master/ip
# echo "192.168.8.133" >/etc/marathon/conf/hostname
# echo "192.168.8.133" >/etc/marathon/conf/ip
marathon连接mesos-master及HA:
# cp /etc/mesos/zk /etc/marathon/conf/master
# cp /etc/mesos/zk /etc/marathon/conf/zk
# sed -i 's|mesos|marathon|g' /etc/marathon/conf/zk
# cat /etc/marathon/conf/master
zk://192.168.8.131:2181,192.168.8.132:2181,192.168.8.133:2181/mesos
# cat /etc/marathon/conf/zk
zk://192.168.8.131:2181,192.168.8.132:2181,192.168.8.133:2181/marathon
# scp /etc/marathon/conf/master root@192.168.8.132:/etc/marathon/conf/
# scp /etc/marathon/conf/master root@192.168.8.133:/etc/marathon/conf/
# scp /etc/marathon/conf/zk root@192.168.8.132:/etc/marathon/conf/
# scp /etc/marathon/conf/zk root@192.168.8.133:/etc/marathon/conf/
5、启动mesos,marathon
# systemctl enable mesos-master marathon
# systemctl start mesos-master marathon
# systemctl disable mesos-slave
# systemctl status mesos-master marathon
# systemctl status marathon #marathon启动报错
● marathon.service - Scheduler for Apache Mesos
Loaded: loaded (/usr/lib/systemd/system/marathon.service; enabled; vendor preset: disabled)
Active: activating (auto-restart) (Result: exit-code) since Mon 2018-05-14 21:13:32 CST; 37s ago
Process: 25368 ExecStart=/usr/share/marathon/bin/marathon (code=exited, status=1/FAILURE)
……
Main PID: 25368 (code=exited, status=1/FAILURE)
May 14 21:13:32 mesos-master1 systemd[1]: marathon.service: main process exited, code=exited, status=1...LURE
……
Hint: Some lines were ellipsized, use -l to show in full.
用以下命令 [journalctl -o verbose _PID=24962] 查看marathon进程的详细信息。
# journalctl -o verbose _PID=25368
-- Logs begin at Sun 2018-05-13 03:47:48 CST, end at Mon 2018-05-14 21:08:12 CST. --
Mon 2018-05-14 21:07:04.849490 CST [s=2f8e0393e2dc4d639f4d5bf76a4e9b6f;i=ec5;b=4a9ee33c3e074eb987230b0202c47a
PRIORITY=6
_SYSTEMD_SLICE=system.slice
_BOOT_ID=4a9ee33c3e074eb987230b0202c47a39
_MACHINE_ID=74bb4614536844d798b123d0cc927d4e
SYSLOG_FACILITY=3
_TRANSPORT=stdout
_SELINUX_CONTEXT=system_u:system_r:init_t:s0
_EXE=/usr/bin/bash
_CAP_EFFECTIVE=0
_COMM=bash
_HOSTNAME=mesos-master1
SYSLOG_IDENTIFIER=marathon
MESSAGE=No start hook file found ($HOOK_MARATHON_START). Proceeding with the start script.
_UID=998
_GID=996
_CMDLINE=bash /usr/share/marathon/bin/marathon
_SYSTEMD_CGROUP=/system.slice/marathon.service
_SYSTEMD_UNIT=marathon.service
_STREAM_ID=bd3ee42018a94236baeab1e5f653171f
_PID=24962
Mon 2018-05-14 21:07:08.496043 CST [s=2f8e0393e2dc4d639f4d5bf76a4e9b6f;i=ec6;b=4a9ee33c3e074eb987230b0202c47a
PRIORITY=6
_SYSTEMD_SLICE=system.slice
_BOOT_ID=4a9ee33c3e074eb987230b0202c47a39
_MACHINE_ID=74bb4614536844d798b123d0cc927d4e
SYSLOG_FACILITY=3
_TRANSPORT=stdout
_SELINUX_CONTEXT=system_u:system_r:init_t:s0
_CAP_EFFECTIVE=0
_HOSTNAME=mesos-master1
SYSLOG_IDENTIFIER=marathon
_UID=998
_GID=996
_SYSTEMD_CGROUP=/system.slice/marathon.service
_SYSTEMD_UNIT=marathon.service
MESSAGE=[scallop] Error: Required option 'master' not found
_COMM=java
_EXE=/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.171-7.b10.el7.x86_64/jre/bin/java
_CMDLINE=java -cp /usr/share/marathon/lib/mesosphere.marathon.marathon-1.6.352.jar:/usr/share/marathon/li
_STREAM_ID=bd3ee42018a94236baeab1e5f653171f
_PID=24962
通过上述日志可以看出,是找不到master导致启动失败。检查了下以上关于marathon的所有配置,确认没有问题。可以根据如下办法直接带master参数启动marathon,最终成功!
# which marathon
/usr/bin/marathon
# nohup marathon --master zk://192.168.8.131:2181,192.168.8.132:2181,192.168.8.133:2181/mesos --zk zk://192.168.8.131:2181,192.168.8.132:2181,192.168.8.133:2181/marathon & >>nohup.out
# ss -tunlp|grep 8080 #8080端口为marathon的进程监听端口
tcp LISTEN 0 50 :::8080 :::* users:(("java",pid=17946,fd=179))
6、查看mesos application的信息
查看application的metric
# curl http://192.168.8.131:8080/metrics | python -m json.tool | less
查看运行的app
# curl http://192.168.8.131:8080/v2/apps | python -m json.tool
查看ID为nginx-test的app
# curl http://192.168.8.131:8080/v2/apps/nginx-test | python -m json.tool
删除ID为nginx-test的app
# curl -X DELETE http://192.168.8.131:8080/v2/apps/nginx-test | python -m json.tool
四、Slave节点部署
以slave-node1为例,slave-node2配置根据环境微调。
1、安装mesos-slave
# yum install mesos docker –y
2、mesos-slave关联zookeeper
# vi /etc/mesos/zk
zk://192.168.8.131:2181,192.168.8.132:2181,192.168.8.133:2181/mesos
3、配置marathon调用mesos运行docker
# echo "docker,mesos" >/etc/mesos-slave/containerizers
4、mesos-slave配置ip&hostname
# echo "192.168.8.134">/etc/mesos-slave/ip
# echo "192.168.8.134" >/etc/mesos-slave/hostname
5、启动服务并增加开机启动
# systemctl stop mesos-master
# systemctl disable mesos-master
# systemctl enable mesos-slave docker
# systemctl start mesos-slave docker
# systemctl status docker
报错:Unit dockergetenforce.service could not be found.
解决方法:
重启服务
# systemctl status mesos-slave
五、验证
登陆mesos web:http://192.168.8.131:5050/#/
1、mesos-homepage
1. 从首页可以看到mesos-agent:activated状态的agent有2个;
2. mesos-master管理的2个agent的资源已汇总。
2、mesos-Frameworks
1. 在mesos框架中,marathon框架已经被识别,marathon的leader是:mesos-master2;
2. 虽然mesos-master与marathon的leader相同,但两者的leader是zookeeper独立选举的,并没有直接关系,是可以不同的。
3、mesos-Agents
1.在Agnets中能看到2个agent;
2.同时能看到每个agent的资源;
点击上面2个slave中的任意一个,也能看出它的master是mesos-master2
访问marathon的管理页面,
这里的master_ip就是在上面访问mesos页面Frameworks中识别出的marathon,即192.168.8.132:8080
或者直接点击mesos访问页面Frameworks中识别出的marathon也可以。
4、mesos state
浏览器访问:
5、通过Mesos调度,使用marathon来创建容器
比如创建一个nginx镜像的Docker容器,Marathon启动时会读取/etc/mesos/zk配置文件,Marathon通过Zookeeper来找到Mesos Master。1)Marathon有自己的REST API,我们通过API的方式来创建一个 tomcat 的Docker容器
首先创建一个json文件(这个要在master节点机器上创建,任意一台master节点机上都可以):
# docker pull nginx
# docker pull tomcat
nginx-example:
{
"id":"nginx", #容器名,只在marathon生效
"cpus":0.2, #cpu用量
"mem":32.0, #mem用量
"instances": 1, #容器数量
"constraints": [["hostname", "UNIQUE",""]], #限制
"container": {
"type":"DOCKER", #应用类型
"docker": { #docker具体配置
"image": "docker.io/nginx", #采用的image
"network": "BRIDGE", #网络模式
"portMappings": [
{"containerPort": 80, "hostPort": 0,"servicePort": 0, "protocol": "tcp" }
] #端口映射,”0”表示任意端口,"servicePort"服务端口
}
}
}
# vi tomcat.json # tomcat
的docker镜像要提前创建或下载
{
"id":"tomcat-1",
"cpus":0.5,
"mem":64,
"instances": 1,
"constraints": [["hostname", "CLUSTER",""]],
"container": {
"type":"DOCKER",
"docker": {
"image": "docker.io/tomcat",
"network": "BRIDGE",
"portMappings": [
{"containerPort": 8080, "hostPort": 0,"servicePort": 0, "protocol": "tcp" }
]
}
}
}
注意:json文件中的每一行内容的开头和结尾一定不能有空格,但可以有空行,否则手动通过curl的方式创建容器实例,会有各种各样的报错!!!
接着使用curl的方式调用,注意上面的tomcat.json
文件是在/root路径下的(注意下面命令中json文件路径)。
# curl -X POST http://192.168.8.131:8080/v2/apps -d @/root/tomcat.json -H "Content-type: application/json"
{"id":"/tomcat-1","backoffFactor":1.15,"backoffSeconds":1,"constraints":[["hostname","CLUSTER",""]],"container":{"type":"DOCKER","docker":{"forcePullImage":false,"image":"docker.io/tomcat","parameters":[],"privileged":false},"volumes":[],"portMappings":[{"containerPort":8080,"hostPort":0,"labels":{},"protocol":"tcp","servicePort":0}]},"cpus":0.5,"disk":0,"executor":"","instances":1,"labels":{},"maxLaunchDelaySeconds":3600,"mem":64,"gpus":0,"networks":[{"mode":"container/bridge"}],"requirePorts":false,"upgradeStrategy":{"maximumOverCapacity":1,"minimumHealthCapacity":1},"version":"2018-05-20T09:20:37.589Z","killSelection":"YOUNGEST_FIRST","unreachableStrategy":{"inactiveAfterSeconds":0,"expungeAfterSeconds":0},"tasksStaged":0,"tasksRunning":0,"tasksHealthy":0,"tasksUnhealthy":0,"deployments":[{"id":"8035fe3f-44a7-4c8d-9f8f-22ecf66ea24f"}],"tasks":[]}
也可以将上面的tomcat.json文件内容直接复制到marathon创建应用容器的"JSON Mode"模式里,然后直接点击创建。
登陆marathon界面查看是在哪一台slave机器上创建的docker容器实例(这个是随机的),点击"running"。(如果容器创建失败,即非"running"状态,可以尝试重启slave节点的docker服务)
然后登陆mesos-slave1机器,发现在服务器上,这个容器只是被关闭了(docker ps -a),可以选择删除。如果再次在机器上启动这个nginx容器,那么在marathon上是不会显示的。
注意:在节点机器上手动创建的docker容器,这些容器信息是不会在marathon和mesos里展示的。
在marathon界面里"Destory"删除对应的application后,在mesos界面的"Active Tasks"里的对应任务也会删除。
另外要注意:在marathon界面里通过调用mesos创建docker容器,只能创建应用容器(Application),如nginx、tomcat、mysql、redis等,需要映射端口,这里是映射的是宿主机的随机端口。不能创建基本centos,ubuntu的系统容器!
2)nginx实例扩容
点击marathon首页正在运行的nginx实例最后面的"…",选择"Scale",在弹出来的实例扩容对话框中,输入所要扩容的实例个数,确定后进行扩容。很快会看到原来正在运行的nginx单实例由一个变为多个。Marathon的实例扩容同时也有相应的API,也可以在bash下通过api进行扩容。
访问所创建的nginx容器。(marathon ui界面里创建的docker容器映射到宿主机的访问端口默认都是随机分配的(BRIDGE模式))、可以自己制作应用的docker镜像,或者自定义构建容器并提交为新镜像(自己设定应用容器结构),然后根据自己制作的镜像在Marathon上创建应用。
如以上截图中可知,这个nginx容器是在mesos-slave1节点机(192.168.8.134)上创建的
注意:如果mesos-slave1节点机宕机或docker服务重启,那么这个nginx容器就会自动漂移到其他的slave节点机上;另外,通过上面方式创建好的容器,在单个slave节点机上删除后,容器也会自动转移到其他slave节点机器上,这样就实现了在slave节点出现故障时容器自动转移的高可用功能。
可以登陆mesos-slave1机器查看所创建的容器,如上可知:访问Docker随机启动的端口是31725。
接着访问mesos页面,可以看到"Active Tasks"有刚才创建的nginx任务了。(注意:只有当mesos访问界面"Active Tasks"里有容器创建任务时,才说明此容器真正创建成功了)
3)图形化创建并运行容器
然后填写创建容器的配置信息,如下图,可以点击"New Application"创建页面右上角的"JSON Mode"模式,将上面创建nginx容器的json文件复制到这里。
剩下以上红框中的配置选项暂时先不配置,待以后测试。
4)删除marathon创建的docker实例。如下图,点击"Destory"即可删除
Marathon还可以对App应用实现手动扩缩的功能,选择"Scale Application"进行快速扩容。如下图,对上面已创建的tomcat应用容器进行扩展到2个Task(注意:这里有2个slave节点,那么扩展的Task实例最好是2个,即2个Instances;如果扩展多个Task,会发现多余的创建失败,这时候可以点击"Configuration"修改,修改成2个)。
点击下面的日志"stderr"和"stdout"就会下载到本地。
也可以到mesos页面查看或下载。点击下面mesos页面对应容器任务后面的"Sandbox"
具体配置可以参考marathon官方文档:里面有关于json文件的配置
6、marathon创建应用使用volumes
在marathon界面里创建应用,可以使用volumes,即映射容器目录到宿主机上,JSON文件内容如下:
{
"id": "nginx-1",
"cmd": null,
"cpus": 0.5,
"mem": 32,
"disk": 2048,
"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"
}
]
}
}
# mkdir -p /opt/web/www //如上图在192.168.8.135(mesos-slave2)节点上创建使用的卷目录(volumes,即映射的宿主机目录)
# echo "test" > /opt/web/www/index.html //映射的宿主机目录下创建测试文件
注意事项:
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界面里根据自己定义的镜像创建应用。 |
7、marathon创建应用指定访问端口
默认情况下,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端口也要指定(最好使用大端口),否则会导致应用容器创建失败。
{
"id":"nginx-2",
"cpus":0.2,
"mem":32.0,
"instances": 1,
"constraints": [["hostname", "CLUSTER",""]],
"container": {
"type":"DOCKER",
"docker": {
"image": "docker.io/nginx",
"network": "BRIDGE",
"portMappings": [
{"containerPort": 80, "hostPort": 31030,"servicePort": 33180, "protocol": "tcp" }
]
}
}
}
在marathon界面里创建应用,将上面的JSON文件内容复制到"JSON Mode"模式下。构建成功后,就会发现该应用容器的访问端口就是上面自己定义的31030端口了(如下)
8、其他
在marathon中,应用是一个完整的概念。每个应用是一个典型的长运行的服务,这个服务有很多实例,并且是运行在多个slave节点机上。下面通过一个小示例说明下:
一个内嵌的shell脚步:
如下通过内嵌的shell脚步,编写一个简单的app,即:打印Hello world到slave节点的/mnt/test文件中,然后sleep 5秒,周而复始。可以使用下面的应用定义文件(json格式)来描述应用(注意:cmd是要执行的命令。它的值会以/bin/sh -c ${cmd}的方式执行。):{ "id": "basic-0", "cmd": "while [ true ] ; do echo 'Hello world' >> /mnt/test ; sleep 5 ; done", "cpus": 0.1, "mem": 10.0, "instances": 1 } |
在marathon界面里添加应用,采用"JSON Mode "模式,如下:
不采用"JSON Mode"模式,即将上面的json文件内容粘贴进去后,去掉右上方的"JSON Mode"模式,也就是只配置"General"选向,其他选项都不配置。注意:marathon里的应用是一个长运行服务,所以shell脚本里要配置长运行动作。
然后到192.168.8.135这台slave节点机上检查,发现每隔5秒钟,就会输出"hello world"到/mnt/test文件中。如果这台节点机出现故障,就会输出到其他节点机上。
# tail -f /mnt/test
Hello world
Hello world
Hello world
Hello world
***************当你发现自己的才华撑不起野心时,就请安静下来学习吧!**************
六、分布式作业调度chronos
下图是chronos任务调度系统的基本结构图:
整体上来看,该系统由业务队列、业务调度器、Chronos和Mesos组成。每个组成部分的说明如下:
业务队列:实际存放任务的队列,队列中的任务可以是按照优先级排序,也可以是FIFO. 多个业务队列表示不同的业务,或者同一业务的不同队列。
业务调度器:根据一定的调度算法从多个业务队列中选择任务来调度。业务调度器接受Chronos的资源汇报,然后给这些资源分配任务。
Chronos:向业务调度器汇报剩余资源,接受业务调度器提交的任务然后在Mesos集群上面运行。
Mesos:运行各个Docker容器的载体。每个任务都在Docker容器中执行。
有一点需要解释的是,在这个任务调度系统中,存在多个调度器:
Mesos中的调度器:一种通用的集群资源分配算法,也就是DRF
Chronos中的调度器:在我们这个场景中,不需要定时调度任务。我们只需使用Chronos的Rest API提交一个Docker任务就可以了,这个Docker任务然后由Chronos调度到Mesos集群上面运行。为什么不绕过Chronos直接提交任务到Mesos呢?Mesos本身是个两级调度架构,如果绕过Chronos,那么业务调度器就需要实现Mesos的上级调度接口,增加了复杂性。
业务调度器:这就是和业务联系最紧密的地方了,此处必须考虑各种业务特性,比如各个业务队列的任务总量、到达速率、优先级等等。
系统的核心在于业务调度器。经过调研各种调度算法,觉得YARN资源管理系统中的容量调度(Capacity Scheduler)适合多业务多队列的场景。
以两级队列为例来说明容量调度算法。下图是Chronos资源的容量配置示例:
在该示意图中,Chronos资源容量的20%分配给了业务1,80%分配给了业务2. 接着,20%容量中的40%分配给了业务队列11,60%分配给了业务队列12. 业务1和业务2是业务层次的队列,业务队列11、业务队列12和业务队列21是具体业务下的子队列。
1、master节点上安装配置chronos
拉取docker官方chronos镜像
# docker pull mesosphere/chronos
# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
docker.io/mesosphere/chronos latest ec8accd8eb53 15 months ago 511 MB
# docker run -itd --net=host -e PORT0=18080 -e PORT1=8081 docker.io/mesosphere/chronos:latest --zk_hosts zk://192.168.8.131:2181,192.168.8.132:2181,192.168.8.133:2181 --master zk://192.168.8.131:2181,192.168.8.132:2181,192.168.8.133:2181/mesos
# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a6f9ecd25d38 docker.io/mesosphere/chronos:latest "/chronos/bin/star..." 2 minutes ago Up 2 minutes gallant_wescoff
2、登录chronos的web管理页面
3、在Chronos页面,点击“ADD JOB”创建任务
注意:时间是UTC时间
Name: 作业名称
Command: 实际需要执行的命令
Schedule: 作业的调度规则,遵循ISO8601规范。由三部分组成,通过”/“符号分割。例如”R10/2012-10-01T05:52:00Z/PT2S”的三部分内容如下:
1> 重复执行作业务次数,如果只有一个R,则代表无限次执行。
2> 开始启动作业的时间,如果为空,则表示立即执行,其遵循ISO8601规范。
3> 执行频率(即间隔多长时间执行一次),其定义方式如下:
P10M=10 months
PT10M=10 minutes
P1Y12M12D=1 years plus 12 months plus 12 days
P12DT12M=12 days plus 12 minutes
P1Y2M3DT4H5M6S=P(eriod) 1Y(ear) 2M(onth) 3D(ay) T(ime) 4H(our) 5M(inute) 6S(econd)
其中,P是必选字段,T是可选字段,用来区分M(inute)和M(onth)。
ScheduleTimeZone: 用来设置作业调度的时区。
Epsilon: 指因某些原因Chronos丢失了运行作业的下一次时间时,采用的固定运行周期。
Owner: 作业责任人的邮件地址。
Async: 作业是否在后台运行。
chronos任务如果正常调度并执行的话,在mesos的web页面上的“Active Tasks”下会有任务执行相关的信息,如下图:
也可以在Chronos的任务页面,点击「Run」强制执行。
4、测试通过Chronos执行Docker任务
启动Docker,抓取nginx镜像,启动chronos-nginx容器
A、创建json文件
# vi chronos-test.json
{
"container": {
"type": "DOCKER",
"image": "docker.io/nginx",
"network": "HOST"
},
"schedule": "R/2018-05-30T14:00:00.000Z/PT24H",
"name": "chronos-nginx",
"cpus": "0.3",
"mem": "32",
"uris": [],
"command": "/usr/sbin/nginx -g 'daemon off;' -c /etc/nginx/nginx.conf"
}
network": "BRIDGE",因为Docker默认的网络模式是桥接,不指定默认也是BRIDGE,此处指定为“HOST”。
B、通过BASH调用chronos的RestfulAPI调度接口运行并启动chronos-nginx容器
# curl -L -H 'Content-Type: application/json' -X POST -d @/root/chronos-test.json
在chronos的web管理界面上查看chronos-nginx容器运行的状态如下图:
在Mesos页面确认任务的详细信息,如下图:
在节点上确认容器启动,如下图:
# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
db3165da2284 docker.io/nginx "/bin/sh -c '/usr/..." 9 minutes ago Up 9 minutes 80/tcp mesos-97cce9bb-a884-454e-aed7-dea10d68737e
5、确认nginx网页可以访问
七、服务自动注册与发现consul
consul的架构图如下所示:
启动consul后默认会监听5个端口:
8300: replication、leader farwarding的端口8301: lan gossip的端口8302: wan gossip的端口8500: web ui界面的端口8600: 使用dns协议查看节点信息的端口集群角色:
上图是官方的consul cluster的架构,Consul Cluster有Server和Client两种角色。不管是Server还是Client,统称为Agent,Consul Client是相对无状态的,只负责转发RPC到Server,资源开销很少。Server是一个有一组扩展功能的代理,这些功能包括参与Raft选举,维护集群状态,响应RPC查询,与其他数据中心交互WAN gossip和转发查询给leader或者远程数据中心。
在每个数据中心,client和server是混合的。一般建议有3-5台server。这是基于有故障情况下的可用性和性能之间的权衡结果,因为越多的机器加入达成共识越慢,Server之间会选举出一个leader。然而,并不限制client的数量,它们可以很容易的扩展到数千或者数万台。
consul更像一个“全栈”解决方案,内置了服务注册与发现,具有健康检查、Key/Value存储、多数据中心的功能。个人比较偏爱他有三点:
1、开箱即用,方便运维:安装包仅包含一个可执行文件,方便部署,无需其他依赖,与Docker等轻量级容器可无缝配合;
2、自带ui界面,可以通过web界面直接看到注册的服务,更新K/V;
3、采用GOSSIP协议进行集群内成员的管理和消息的传播,使用和etcd一样的raft协议保证数据的一致性。
Consul提供的四个关键特性:
1、服务发现:提供HTTP和DNS两种发现方式。
2、健康监测: 支持多种方式,HTTP、TCP、Docker、Shell脚本定制化监控。
3、K/V存储: Key、Value的存储方式。
4、多数据中心:Consul支持多数据中心。
当然Consul还有很多锦上添花的特性,比如:可视化Web界面、配置模板“consul-template”等。
通过registrator的服务自动注册,配合consul服务,在docker容器中能够自动识别服务的域名,以便在mesos+marathon中部署docker实例能够通过域名互通,也就是consul在docker容器中的自动发现。如果是线上consul server最少3台做集群,consul client是每个mesos-slave上跑一个,mesos-master也最少3台集群,marathon和zookeeper都应该是集群的模式。
consul经常拿来和etcd、zookeeper来对比,他有和etcd一样的服务发现、服务注册功能,也有和etcd、zookeeper一样的配置存储功能,详细的比对这里就不描述了。下面是consul集群的服务注册,服务发现,健康检查,和模板使用。
registrator服务注册 | | consul服务端 | |nginx代理 | |应用服务
做健康检查 | |接收客户端发送的健康 | | 如果nginx的模板 | |
确定本地服务是否正常 | |检查信息做服务的注册 | |更改,则 | |
通报给consul服务端 | |如果客户端有变动,则 | |nginx reload | |
| |更新代理的配置 | | | |
1、consul集群服务安装配置
# unzip consul_1.1.0_linux_amd64.zip -d /usr/local
# ln -s /usr/local/consul /usr/local/bin/consul
# mkdir -p /etc/consul.d //在每个consul节点上配置
command方式创建consul集群:
# consul agent -server -bootstrap-expect=3 -data-dir=/tmp/consul -node=192.168.8.131 -config-dir=/etc/consul.d -client 0.0.0.0
==> Multiple private IPv4 addresses found. Please configure one with 'bind' and/or 'advertise'.
报错:Multiple private IPv4 addresses found. Please configure one with 'bind' and/or 'advertise'.
意思是:找到多个私有IPv4地址。请用“bind”绑定配置一个,就可以解决,根据提示.
[root@mesos-master1 ~]# nohup consul agent -server -bootstrap-expect=3 -data-dir=/tmp/consul -node=mesos-master1 -config-dir=/etc/consul.d -bind=192.168.8.131 -client 0.0.0.0 -ui &
bootstrap_expect > 0: expecting 3 servers
==> Starting Consul agent...
==> Consul agent running!
Version: 'v1.1.0'
Node ID: 'cc8eebd0-6f84-6eee-f8cc-92ae7bf44494'
Node name: 'mesos-master1'
。。。。。。
2018/06/03 15:00:21 [INFO] agent: Started DNS server 0.0.0.0:8600 (tcp)
2018/06/03 15:00:21 [INFO] agent: Started HTTP server on [::]:8500 (tcp)
2018/06/03 15:00:21 [INFO] agent: started state syncer
2018/06/03 15:00:28 [ERR] agent: failed to sync remote state: No cluster leader
2018/06/03 15:00:30 [WARN] raft: no known peers, aborting election
2018/06/03 15:00:51 [ERR] agent: Coordinate update error: No cluster leader
2018/06/03 15:00:54 [ERR] agent: failed to sync remote state: No cluster leader
报错:No cluster leader,是因为其它两台consul的server端还没有启动!
启动参数说明:
agent: 运行一个consul代理。-server: 切换代理到服务器模式。-bootstrap: 当consulserver-node1节点启动之后,等待另外两个节点的加入,3个节点聚齐后,之后才开始选举leader。-ui: 启用内置的静态web UI服务器。-data-dir: 路径到数据目录存储代理状态。-bind: 设置集群通信的绑定地址。-client: 设置用于绑定客户端访问的地址。这包括RPC、DNS、HTTP和HTTPS(如果配置)。-node: 此节点的名称。 在集群中必须是唯一的,如果你运行第2台consul,可以写server02、server03等。-advertise:如果要让节点在WAN网络中被发现,就要配置这个参数,暴露出外网ip
[root@mesos-master2 ~]# nohup consul agent -server -bootstrap-expect=3 -data-dir=/tmp/consul -node=mesos-master2 -config-dir=/etc/consul.d -bind=192.168.8.132 -client 0.0.0.0 -join 192.168.8.131 & //注意:此处的-join启动选项,后面跟mesos-master1的IP地址,或者也可以在mesos-master1上执行consul join 192.168.8.132/133,否则同样还是会报以上错误!
[root@mesos-master3 ~]# nohup consul agent -server -bootstrap-expect=3 -data-dir=/tmp/consul -node=mesos-master3 -config-dir=/etc/consul.d -bind=192.168.8.133 -client 0.0.0.0 -join 192.168.8.131 &
很×××台mesos-master上的consul都会打印:
consul: New leader elected: mesos-master1
证明此时leader已经选出,集群可以正常工作。
[root@mesos-slave1 ~]# nohup consul agent -client 192.168.8.134 -data-dir=/tmp/consul -config-dir=/etc/consul.d -node=mesos-slave1 -bind=192.168.8.134 -join 192.168.8.131 &
[root@mesos-slave2 ~]# nohup consul agent -client 192.168.8.135 -data-dir=/tmp/consul -config-dir=/etc/consul.d -node=mesos-slave2 -bind=192.168.8.135 -join 192.168.8.131 &
[root@mesos-master1 ~]# consul info consul
集群参数put/get测试:
[root@mesos-slave1 ~]# consul kv put key value
Success! Data written to: key
[root@mesos-master2 ~]# consul kv get key
value
5台机器获取key的值均为value,如此可知key的值已经在集群中同步。
[root@mesos-master1 ~]# consul members
Node Address Status Type Build Protocol DC Segment
mesos-master1 192.168.8.131:8301 alive server 1.1.0 2 dc <all>
mesos-master2 192.168.8.132:8301 alive server 1.1.0 2 dc <all>
mesos-master3 192.168.8.133:8301 alive server 1.1.0 2 dc <all>
mesos-slave1 192.168.8.134:8301 alive client 1.1.0 2 dc <default>
mesos-slave2 192.168.8.135:8301 alive client 1.1.0 2 dc <default>
[root@mesos-master1 ~]# consul operator raft list-peers
Node ID Address State Voter RaftProtocol
mesos-master1 f0522384-3554-61e7-57ce-607a583a179f 192.168.8.131:8300 leader true 3
mesos-master2 b5ffff40-f993-0f9e-7877-4e0bffdabb3d 192.168.8.132:8300 follower true 3
mesos-master3 fc42ff3f-617f-9524-090b-b8c5584b3cac 192.168.8.133:8300 follower true 3
可以看出集群中mesos-master1是leader,mesos-master2和mesos-master3都是follower
[root@mesos-master1 ~]# consul info |grep leader
leader = false
leader_addr = 192.168.8.132:8300
[root@mesos-master1 ~]# consul catalog services
consul
mesos
配置文件方式创建consul集群:
在其中一个mesos master节点上配置bootstrap配置,该节点就是consul集群中的bootstrap节点(192.168.8.131)。
# cat > /etc/consul.d/bootstrap/config.json <<EOF
{
"bootstrap": true,
"server": true,
"datacenter": "dc",
"data_dir": "/var/consul",
"log_level": "INFO",
"enable_syslog": true,
"disable_update_check": true,
"ui": true
}
EOF
在其他的mesos master 节点上配置server配置,这些节点就是consul集群中的server节点(192.168.8.132/192.168.8.133)。
# cat > /etc/consul.d/server/config.json <<EOF
{
"bootstrap": false,
"server": true,
"datacenter": "dc",
"data_dir": "/var/consul",
"log_level": "INFO",
"enable_syslog": true,
"disable_update_check": true,
"start_join": ["192.168.8.131", "192.168.8.133"],
"ui": true
}
EOF
注意: start_join: 记录了其他consul server节点的IP。
在所有的mesos agent 节点上配置client配置,这些节点也就是consul集群中的client节点# cat > /etc/consul.d/client/config.json <<EOF
{
"server": false,
"datacenter": "dc",
"data_dir": "/var/consul",
"log_level": "INFO",
"enable_syslog": true,
"disable_update_check": true,
"start_join": ["192.168.8.131", "192.168.8.132", "192.168.8.133"],
"ui": true
}
EOF
注意:start_join: 记录了所有的consul server的IP。
启动Consul集群:在consul bootstrap节点启动:# consul agent -config-dir /etc/consul.d/bootstrap/ -bind=192.168.8.131 -client=0.0.0.0 >> /var/log/consul.log 2>&1 &
在所有consul server节点启动:
# consul agent -config-dir /etc/consul.d/server/ -bind=192.168.8.132 -client=0.0.0.0 >> /var/log/consul.log 2>&1 &
在所有consul client节点启动:
consul agent -config-dir /etc/consul.d/client/ -bind=192.168.8.134 -client=0.0.0.0 >> /var/log/consul.log 2>&1 &
注意: self_ip是本机的IP。
检查consul集群状态: 在consul集群中任意一个节点执行2、consul的DNS服务发现
consul支持dns的服务注册:
# dig @127.0.0.1 8600 mesos-master1.node.consul +short
192.168.8.131
# dig @127.0.0.1 8600 mesos-master2.node.consul +short
192.168.8.132
# dig @127.0.0.1 8600 mesos-master3.node.consul +short
192.168.8.133
3、consul的常用http api
对consul来说一个重要的接口就是RESTful HTTP API,http api可用于操作nodes, services, checks, configuration等等的CRUD(create, read, update and delete),详见,下面是几个例子?说明
http api可以通过链接请求:
查看当前consul节点的服务
# curl mesos-master1:8500/v1/agent/checks |python -m json.tool
查看当前consul集群的leader
# curl mesos-master1:8500/v1/status/leader
查看当前节点的信息
# curl mesos-master1:8500/v1/operator/raft/configuration |python -m json.tool
查看mesos-slave1节点的健康检查信息
# curl mesos-master1:8500/v1/health/node/mesos-slave1 |python -m json.tool
查看webserver服务的信息
# curl -s http://mesos-master1:8500/v1/catalog/service/webserver | python -m json.tool
# 集群server成员
#curl 127.0.0.1:8500/v1/status/peers
# 集群Raft leader
#curl 127.0.0.1:8500/v1/status/leader
# 注册的所有服务
#curl 127.0.0.1:8500/v1/catalog/services
# 服务信息
#curl 127.0.0.1:8500/v1/catalog/services/nginx
# 集群节点详细信息
#curl 127.0.0.1:8500/v1/catalog/nodes
4、registrator容器实现服务自动注册
服务发现与注册
1. 具体流程
服务注册中心:作为整个架构中的核心,要支持分布式、持久化存储,注册信息变动实时通知消费者。
服务提供者:服务以容器化方式部署(实现服务端口的动态生成),可以通过 的方式来管理。通过 检测到 进程信息以完成服务的自动注册。
服务消费者:要使用服务提供者提供的服务,和服务提供者往往是动态相互转位置的。
一个较为完整的服务注册与发现流程如下:
注册服务:服务提供者到注册中心注册;
订阅服务:服务消费者到注册中心订阅服务信息,对其进行监听;
缓存服务列表:本地缓存服务列表,减少与注册中心的网络通信;
调用服务:先查找本地缓存,找不到再去注册中心拉取服务地址,然后发送服务请求;
变更通知:服务节点变动时 (新增、删除等),注册中心将通知监听节点,更新服务信息。
2. 相关组件
一个服务发现系统主要由三部分组成:
注册器(registrator):根据服务运行状态,注册/注销服务。主要要解决的问题是,何时发起注册/注销动作。
注册表(registry):存储服务信息。常见的解决方案有zookeeper、etcd、cousul等。
发现机制(discovery):从注册表读取服务信息,给用户封装访问接口。
通过Registrator收集需要注册到Consul作为Nginx后端服务器信息然后注册到Consul key/value.Consul-template去Consul key/value中读取信息,然后自动修改Nginx配置文件并平滑重启Nginx,不需要修改nginx.conf。
分别在mesos-slave1 和mesos-slave2 上都创建:
利用chronos的任务调度下载registrator:
利用chronos的任务调度在所有的mesos-slave上运行registrator:
Command: docker run -d --name registrator --network=host -v /var/run/docker.sock:/tmp/docker.sock --restart=always gliderlabs/registrator:latest --ip 192.168.8.134 consul://192.168.8.131:8500
参数说明:
--network:把运行的docker容器设定为host网络模式;-v /var/run/docker.sock:把宿主机的Docker守护进程(Docker daemon)默认监听的Unix域套接字挂载到容器中;--ip : 刚才把network指定了host模式,所以我们指定下IP为宿主机的IP;consul: 最后这个选项是配置consul服务器的IP和端口。服务注册前:
通过marathon启动tomcat服务:
[root@mesos-master1 ~]# curl -X POST http://192.168.8.131:8080/v2/apps -d @/root/tomcat.json -H "Content-type: application/json"
{"id":"/tomcat-1","backoffFactor":1.15,"backoffSeconds":1,"constraints":[["hostname","CLUSTER",""]],"container":{"type":"DOCKER","docker":{"forcePullImage":false,"image":"docker.io/tomcat","parameters":[],"privileged":false},"volumes":[],"portMappings":[{"containerPort":8080,"hostPort":0,"labels":{},"protocol":"tcp","servicePort":0}]},"cpus":0.5,"disk":0,"executor":"","instances":1,"labels":{},"maxLaunchDelaySeconds":3600,"mem":64,"gpus":0,"networks":[{"mode":"container/bridge"}],"requirePorts":false,"upgradeStrategy":{"maximumOverCapacity":1,"minimumHealthCapacity":1},"version":"2018-06-10T08:34:47.600Z","killSelection":"YOUNGEST_FIRST","unreachableStrategy":{"inactiveAfterSeconds":0,"expungeAfterSeconds":0},"tasksStaged":0,"tasksRunning":0,"tasksHealthy":0,"tasksUnhealthy":0,"deployments":[{"id":"346444ac-978b-42d6-8975-6b01fd6869ab"}],"tasks":[]}
服务注册后:
从上图可以看出,刚才创建的marathon应用tomcat容器服务已经注册到了 consul中。
[root@mesos-master1 ~]# curl 127.0.0.1:8500/v1/catalog/services
{"consul":[],"mesos":["master","leader"],"tomcat":[]}
八、负载均衡
服务被调整后,负载均衡要想动态重新分配负载,就需要修改相应的配置文件,consul-template就是解决这个问题的应用,通过监听consul的注册信息,来自动完成负载均衡相应的配置更新。
安装nginx,此处略过。。。
安装配置consul-template
安装consul-template非常简单,下载二进制包即可使用。
1、下载consul-template
下载地址:# wget https://releases.hashicorp.com/consul-template/0.19.4/consul-template_0.19.4_linux_amd64.zip
2、解压并安装到/usr/bin目录
# unzip consul-template_0.19.4_linux_amd64.zip
# mv consul-template /usr/bin/
# consul-template -v
consul-template v0.19.4 (68b1da2)
3、创建nginx模板
# cd /usr/local/nginx
# mkdir consul
# cd consul/
# vi nginx.ctmpl
upstream http_backend {
{
{range service "nginx"}}server {
{ .Address }}:{ { .Port }} max_fails=3 fail_timeout=90;{
{ end }}}
server {
listen 8085;
server_name localhost;
location / {
proxy_pass http://http_backend;
}
}
4、修改nginx.conf
# grep "consul" nginx.conf
include /usr/local/nginx/consul/*.conf; //添加这一行在http模块
# /usr/local/nginx/sbin/nginx //启动nginx服务
5、启动consul-template
# ln -s /usr/local/nginx/sbin/nginx /usr/bin/nginx
# cd /usr/local/nginx/consul/
# consul-template --consul-addr 192.168.8.131:8500 --template /usr/local/nginx/consul/nginx.ctmpl:/usr/local/nginx/consul/vhost.conf:"nginx -s reload" --log-level=info
2018/06/18 13:15:45.719503 [INFO] consul-template v0.19.4 (68b1da2)
2018/06/18 13:15:45.720675 [INFO] (runner) creating new runner (dry: false, once: false)
2018/06/18 13:15:45.721967 [INFO] (runner) creating watcher
2018/06/18 13:15:45.723542 [INFO] (runner) starting
2018/06/18 13:15:45.724051 [INFO] (runner) initiating run
2018/06/18 13:15:45.728395 [INFO] (runner) initiating run
2018/06/18 13:15:45.731084 [INFO] (runner) rendered "/usr/local/nginx/consul/nginx.ctmpl" => "/usr/local/nginx/consul/vhost.conf"
2018/06/18 13:15:45.732215 [INFO] (runner) executing command "nginx -s reload" from "/usr/local/nginx/consul/nginx.ctmpl" => "/usr/local/nginx/consul/vhost.conf"
2018/06/18 13:15:45.733669 [INFO] (child) spawning: nginx -s reload
--consul-addr:指定consul服务的ip和端口;./nginx.ctmpl:这是用nginx.ctmpl这个模板来启动进程,这是写的相对路径,也可以写绝对路径;vhost.conf:nginx.ctmpl模板生成后的文件名,这也可以写绝对路径,如果不写绝对路径,这个文件就在当前目录生成(/usr/local/nginx/consul/)
由于consul-template在前台运行,所以我们在打开一个终端验证。
[root@mesos-master1 ~]# ps -ef | grep consul-template
root 41543 16705 0 19:33 pts/2 00:00:00 consul-template --consul-addr 192.168.8.131:8500 --template ./nginx.ctmpl:vhost.conf --log-level=info
root 41758 38089 0 19:35 pts/1 00:00:00 grep --color=auto consul-template
[root@mesos-master1 ~]# ll /usr/local/nginx/consul/
total 8
-rw-r--r-- 1 root root 333 Jun 10 18:26 nginx.ctmpl
-rw-r--r-- 1 root root 255 Jun 10 19:33 vhost.conf
在consul目录下,是不是发现多了一个文件vhost.conf,就是刚才启consul-template时生成的。查看下vhost.conf的内容,目前upstraem的server配置为空,还没有docker主机加入进来:
[root@mesos-master1 ~]# cat /usr/local/nginx/consul/vhost.conf
upstream http_backend {
server {
{ .Address }}:{ { .Port }} max_fails=3 fail_timeout=90;}
server {
listen 8085;
server_name localhost;
location / {
proxy_pass http://http_backend;
}
}
通过marathon创建nginx容器实例:
[root@mesos-master1 ~]# curl -X POST http://192.168.8.132:8080/v2/apps -d @/root/nginx.json -H "Content-type: application/json"
{"id":"/nginx-1","backoffFactor":1.15,"backoffSeconds":1,"container":{"type":"DOCKER","docker":{"forcePullImage":false,"image":"docker.io/nginx","parameters":[],"privileged":false},"volumes":[{"containerPath":"/usr/share/nginx/html","hostPath":"/opt/web/www","mode":"RW"}],"portMappings":[{"containerPort":80,"hostPort":0,"labels":{},"protocol":"tcp","servicePort":0}]},"cpus":0.5,"disk":2048,"executor":"","instances":1,"labels":{},"maxLaunchDelaySeconds":3600,"mem":32,"gpus":0,"networks":[{"mode":"container/bridge"}],"requirePorts":false,"upgradeStrategy":{"maximumOverCapacity":1,"minimumHealthCapacity":1},"version":"2018-06-18T13:12:27.037Z","killSelection":"YOUNGEST_FIRST","unreachableStrategy":{"inactiveAfterSeconds":0,"expungeAfterSeconds":0},"tasksStaged":0,"tasksRunning":0,"tasksHealthy":0,"tasksUnhealthy":0,"deployments":[{"id":"0b2969ac-a65d-4ff9-b7b9-f2c5cc29312f"}],"tasks":[]}
[root@mesos-master1 ~]# cat /usr/local/nginx/consul/vhost.conf
upstream http_backend {
server 192.168.8.134:31581 max_fails=3 fail_timeout=90;
server 192.168.8.134:31818 max_fails=3 fail_timeout=90;
server 192.168.8.135:31814 max_fails=3 fail_timeout=90;
}
server {
listen 8085;
server_name localhost;
location / {
proxy_pass http://http_backend;
}
}
[root@mesos-slave1 ~]# echo "mesos-slave1" >/opt/web/www/index.html
[root@mesos-slave2 ~]# echo "mesos-slave2" >/opt/web/www/index.html
可以看到,在通过marathon创建了3个nginx的容器实例后,nginx的虚拟主机配置文件已经被consul-template动态修改。然后访问一下nginx服务器的IP地址,http://192.168.8.131:8085,从下图可以看出是可以访问的:
可以看到nginx的8085负载均衡是可以正常轮询的!!!