设为首页 收藏本站
查看: 859|回复: 0

[经验分享] Mesos+Marathon+zk+docker构建PaaS平台

[复制链接]

尚未签到

发表于 2019-2-21 10:40:28 | 显示全部楼层 |阅读模式
  参考文档:

  •   mesos:http://mesos.apache.org/documentation/latest/
  •   mesosphere社区版:https://github.com/mesosphere/open-docs
  •   mesosphere仓库:https://github.com/mesosphere/open-docs/blob/master/downloads/mesos.md
  •   marathon: https://mesosphere.github.io/marathon/docs/
  •   chronos: https://mesos.github.io/chronos/docs/
  •   consul:https://www.consul.io/ https://releases.hashicorp.com/consul/
  •   docker安装:https://docs.docker.com/engine/installation/linux/docker-ce/centos/
一、系统说明
  mesos 集群资源管理框架(以集群的形式出现,主决定资源的分配,从负责执行executor),分配资源,提供offer给framework,不负责调度资源,千言万语都在这里了mesos的设计结构
  
  
marathon 是mesos的framework,容器编排系统,保证长时间的运行任务,类似后台执行或者supervisor。
  zooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的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.cfg
dataDir:数据目录
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)的整数。即采用四舍五入,比如这里有3master节点,那么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-masterHA
  # 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的管理页面,http://master_ip:8080
  这里的master_ip就是在上面访问mesos页面Frameworks中识别出的marathon,即192.168.8.132:8080
或者直接点击mesos访问页面Frameworks中识别出的marathon也可以。

4、mesos state
  浏览器访问:http://192.168.8.132:5050/master/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官方文档:https://mesosphere.github.io/marathon/docs/persistent-volumes.html里面有关于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管理页面
  http://192.168.8.131:18080

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 http://192.168.8.131:18080/v1/scheduler/iso8601
  在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-master1IP地址,或者也可以在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
  mesos-master2 192.168.8.132:8301 alive server 1.1.0 2 dc
  mesos-master3 192.168.8.133:8301 alive server 1.1.0 2 dc
  mesos-slave1 192.168.8.134:8301 alive client 1.1.0 2 dc
  mesos-slave2 192.168.8.135:8301 alive client 1.1.0 2 dc
  [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 > /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 +short192.168.8.131# dig @127.0.0.1 8600 mesos-master2.node.consul +short192.168.8.132# dig @127.0.0.1 8600 mesos-master3.node.consul +short192.168.8.1333、consul的常用http api
  对consul来说一个重要的接口就是RESTful HTTP API,http api可用于操作nodes, services, checks, configuration等等的CRUD(create, read, update and delete)详见Consul Http Api,下面是几个例子?说明
  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
下载地址:https://releases.hashicorp.com/consul-template/0.19.4/consul-template_0.19.4_linux_amd64.zip
  # 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=info2018/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 watcher2018/06/18 13:15:45.723542 [INFO] (runner) starting2018/06/18 13:15:45.724051 [INFO] (runner) initiating run2018/06/18 13:15:45.728395 [INFO] (runner) initiating run2018/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负载均衡是可以正常轮询的!!!




运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-675240-1-1.html 上篇帖子: SELinux 引起的docker启动失败 下篇帖子: Docker镜像构建的优化总结
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表