前面我们了解了docker常见的操作和部署方法,在企业中,如果要大规模使用docker就不能通过纯手工的方式去维护和部署了。目前比较流行的有两种解决方案,一种是使用 Mesos+Marathon+docker的方式对集群中的容器进行管理,另一种方式是使用Kubernetes,就目前Kubernetes有引领行业的趋势,但是对于小型的集群管理,mesos符合传统主从架构,更加简单。
Mesos介绍
Mesos容器管理的理念个人觉得类似于OpenStack, 通过master将整个集群的资源搜集起来,当需要创建容器,或执行某个task时,会根据当前集群中的资源情况进行调度,对集群中运行的应用进行统一的资源管理。创建的容器在节点上是随机分配的(前提是资源足够的情况下),当某个容器或任务因故障终止后,在其它节点会自动创建一个新的容器来实现高可用。
在 Mesos 上运行的 framework 由两部分组成:一个是 scheduler ,通过注册到 master 来获取集群资源。另一个是在 slave 节点上运行的 executor 进程,它可以执行 framework 的 task 。 Master 决定为每个 framework 提供多少资源, framework 的 scheduler 来选择其中提供的资源。当 framework 同意了提供的资源,它通过 master 将 task发送到提供资源的 slaves 上运行。
配置mesos集群
本次示例使用6台CentOS7.2主机,3台作为mesos-master集群,另外3台作为mesos-slave。slave上运行容器执行task.
1、系统初始化:
对这六台机器配置hosts解析,并添加yum源:
1
2
3
4
5
6
7
8
<code>cat</code> <code>>></code><code>/etc/hosts</code> <code><<EOF</code>
<code>192.168.20.41 mesos1 </code><code># master</code>
<code>192.168.20.42 mesos2 </code><code># master</code>
<code>192.168.20.43 mesos3 </code><code># master</code>
<code>192.168.20.44 mesos4 </code><code># slave</code>
<code>192.168.20.45 mesos5 </code><code># slave</code>
<code>192.168.20.46 mesos6 </code><code># slave</code>
<code>EOF</code>
<code>setenforce 0</code>
<code>sed</code> <code>-i </code><code>'s#SELINUX=enforcing#SELINUX=disabled#g'</code> <code>/etc/sysconfig/selinux</code>
<code>systemctl stop firewalld</code>
<code>systemctl disable firewalld</code>
<code>rpm -Uvh http:</code><code>//repos</code><code>.mesosphere.io</code><code>/el/7/noarch/RPMS/mesosphere-el-repo-7-2</code><code>.noarch.rpm</code>
2、配置mesos-master
在mesos1,mesos2和mesos3上配置zookeeper集群:
<code>yum </code><code>install</code> <code>-y java-1.8.0-openjdk-devel java-1.8.0-openjdk</code>
<code>yum -y </code><code>install</code> <code>mesos marathon mesosphere-zookeeper</code>
配置zookeeper集群ID
mesos1:
<code>echo</code> <code>1 > </code><code>/var/lib/zookeeper/myid</code>
mesos2:
<code>echo</code> <code>2 > </code><code>/var/lib/zookeeper/myid</code>
mesos3:
<code>echo</code> <code>3 > </code><code>/var/lib/zookeeper/myid</code>
在3台master上, 配置zookeeper集群信息:
<code>vim </code><code>/etc/zookeeper/conf/zoo</code><code>.cfg</code>
9
<code>maxClientCnxns=50 </code><code>#单个客户端与单台服务器之间的连接数的限制,是ip级别的,默认是50,如果设置为0,那么表明不作任何限制。请注意这个限制的使用范围,仅仅是单台客户端机器与单台ZK服务器之间的连接数限制,不是针对指定客户端IP,也不是ZK集群的连接数限制,也不是单台ZK对所有客户端的连接数限制。</code>
<code>tickTime=2000 </code><code>#Zookeeper 服务器之间或客户端与服务器之间维持心跳的时间间隔,也就是每个 tickTime 时间就会发送一个心跳</code>
<code>initLimit=10 </code><code>#Zookeeper的Leader 接受客户端(Follower)初始化连接时最长能忍受多少个心跳时间间隔数。当已经超过 5个心跳的时间(也就是tickTime)长度后 Zookeeper 服务器还没有收到客户端的返回信息,那么表明这个客户端连接失败。总的时间长度就是 5*2000=10 秒</code>
<code>syncLimit=5 </code><code>#表示 Leader 与 Follower 之间发送消息时请求和应答时间长度,最长不能超过多少个tickTime 的时间长度,总的时间长度就是 2*2000=4 秒</code>
<code>dataDir=</code><code>/var/lib/zookeeper</code> <code>#zookeeper数据文件存放目录</code>
<code>clientPort=2181 </code><code>#客户端连接端口</code>
<code>server.1=192.168.20.41:3181:4181 </code><code>#数字1,2,3表示这个是第几号服务器(是上面myid文件里对应的数字);中间的是master主节点的ip地址</code>
<code>server.2=192.168.20.42:3181:4181 </code><code>#第一个端口2888(这个端口可以自己定义)表示的是这个服务器与集群中的 Leader 服务器交换信息的端口</code>
<code>server.3=192.168.20.43:3181:4181 </code><code>#第二个端口3888表示的是万一集群中的 Leader 服务器挂了,需要一个端口来重新进行选举,选出一个新的 Leader,而这个端口就是用来执行选举时服务器相互通信的端口。</code>
配置集群端口:
<code>vim </code><code>/etc/mesos/zk</code>
<code>zk:</code><code>//192</code><code>.168.20.41:2181,192.168.20.42:2181,192.168.20.43:2181</code><code>/mesos</code>
配置仲裁,此处使用的是3个节点,所以配置仲裁数目为2 (集群节点数目/2,四舍五入):
<code>cat</code> <code>/etc/mesos-master/quorum</code>
<code>2</code>
mesos集群是通过zookeeper来交互的,所以只需要配置zookeeper即可, 配置完成之后,启动mesos-master集群:
<code>systemctl </code><code>enable</code> <code>zookeeper && systemctl </code><code>enable</code> <code>mesos-master && systemctl </code><code>enable</code> <code>marathon</code>
<code>systemctl start zookeeper && systemctl start mesos-master && systemctl start marathon</code>
<code>systemctl disable mesos-slave</code>
查看zookeeper的状态:
<code>/opt/mesosphere/zookeeper/bin/zkServer</code><code>.sh status </code><code>/etc/zookeeper/conf/zoo</code><code>.cfg</code>
确认mesos-master 和marathon启动,并开放端口:
<code>systemctl status mesos-master </code>
<code>systemctl status marathon</code>
3. 配置各slave节点
安装docker 和mesos :
<code>yum </code><code>install</code> <code>docker -y</code>
<code>yum </code><code>install</code> <code>mesos -y</code>
配置slave的master信息以及运行方式:
<code>echo</code> <code>"zk://192.168.20.41:2181,192.168.20.42:2181,192.168.20.43:2181/mesos"</code> <code>> </code><code>/etc/mesos/zk</code>
<code>echo</code> <code>'docker,mesos'</code> <code>> </code><code>/etc/mesos-slave/containerizers</code>
启动服务:
<code>systemctl start docker && systemctl </code><code>enable</code> <code>docker</code>
<code>systemctl start mesos-slave && systemctl </code><code>enable</code> <code>mesos-slave</code>
<code>docker pull nginx</code>
<code>docker pull tomcat</code>
4. 登录master上的任意一台机器, 分别进入 mesos和marathon的管理界面:
<a href="http://192.168.20.41:5050/" target="_blank">http://192.168.20.41:5050</a>
在端口为5050的mesos 界面,angent栏中可以看到三台slave已经被添加进来:
<a href="https://s2.51cto.com/wyfs02/M01/9E/07/wKioL1mKadDB80-oAAGke7PhkmI864.jpg" target="_blank"></a>
使用8080端口访问的Marathon,由于还没有添加任务,所以显示的是“No Application”:
<a href="https://s2.51cto.com/wyfs02/M01/9E/07/wKioL1mKataCrBsjAAESE9FyFpk285.jpg" target="_blank"></a>
测试容器应用
1、marathon可以使用REST API的方式来处理任务需求,我们先测试通过API的方式来创建一个nginx的docker容器
在master上编辑nginx.json:
10
11
12
13
14
15
16
17
<code>{</code>
<code> </code><code>"id"</code><code>:</code><code>"nginx"</code><code>,</code>
<code> </code><code>"cpus"</code><code>:0.2,</code>
<code> </code><code>"mem"</code><code>:20.0,</code>
<code> </code><code>"instances"</code><code>: 1,</code>
<code> </code><code>"constraints"</code><code>: [[</code><code>"hostname"</code><code>, </code><code>"UNIQUE"</code><code>,</code><code>""</code><code>]],</code>
<code> </code><code>"container"</code><code>: {</code>
<code> </code><code>"type"</code><code>:</code><code>"DOCKER"</code><code>,</code>
<code> </code><code>"docker"</code><code>: {</code>
<code> </code><code>"image"</code><code>: </code><code>"nginx"</code><code>,</code>
<code> </code><code>"network"</code><code>: </code><code>"BRIDGE"</code><code>,</code>
<code> </code><code>"portMappings"</code><code>: [</code>
<code> </code><code>{</code><code>"containerPort"</code><code>: 80, </code><code>"hostPort"</code><code>: 0,</code><code>"servicePort"</code><code>: 0, </code><code>"protocol"</code><code>: </code><code>"tcp"</code> <code>}</code>
<code> </code><code>]</code>
<code> </code><code>}</code>
<code> </code><code>}</code>
<code>}</code>
使用POST 方法执行:
<code>curl -X POST http:</code><code>//192</code><code>.168.20.41:8080</code><code>/v2/apps</code> <code>-d @nginx.json -H </code><code>"Content-type: application/json"</code>
执行此命令后,会返回一串json的详细配置信息,在mesos界面可以看到已经有一个任务在运行:
<a href="https://s3.51cto.com/wyfs02/M02/9E/08/wKiom1mKcMHT0KdvAAIorY3iK3U321.jpg" target="_blank"></a>
在marathon界面,可以看到此容器对外开放的端口:
<a href="https://s4.51cto.com/wyfs02/M00/9E/08/wKiom1mKcZ7jbFKZAAFWDLQgbBI202.jpg" target="_blank"></a>
直接对此端口进行访问,就可以访问到我们熟悉的nginx初始界面。
我们可以查看在mesos5这台机器上的容器状态:
<code>[root@mesos5 ~]</code><code># docker ps -a</code>
<code>CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES</code>
<code>ee6639983450 nginx </code><code>"nginx -g 'daemon off"</code> <code>11 minutes ago Up 11 minutes 0.0.0.0:31495->80</code><code>/tcp</code> <code>mesos-398a0a16-fe13-48e6-9a9c-6932c6c58014-S1.525f7318-9bb7-486c-9c3a-13d5294f37ff</code>
查看端口:
<code>[root@mesos5 ~]</code><code># docker port ee6639983450 </code>
<code>80</code><code>/tcp</code> <code>-> 0.0.0.0:31495</code>
mesos上创建的容器映射的对外端口,默认会使用31000-32000之间的随机端口。
使用Marathon管理容器
在日常的操作中,为了更加方便快捷的使用docker,可以通过使用Marathon来管理容器。
在Marathon的创建应用界面,我们可以看到对应的配置选项:
<a href="https://s4.51cto.com/wyfs02/M02/9E/09/wKiom1mKd0Gz5p87AAEHySJl-8c245.jpg" target="_blank"></a>
在此界面,我们也可以直接使用json配置的方式,直接编写我们需要的配置:
<a href="https://s5.51cto.com/wyfs02/M01/9E/09/wKioL1mKeynBADYfAAEGp3tZsMs781.jpg" target="_blank"></a>
输入以下内容:
<code>{ </code>
<code>"id"</code><code>:</code><code>"tomcat"</code><code>, </code>
<code>"cpus"</code><code>:1, </code>
<code>"mem"</code><code>:128, </code>
<code>"instances"</code><code>: 1, </code>
<code>"constraints"</code><code>: [[</code><code>"hostname"</code><code>, </code><code>"UNIQUE"</code><code>,</code><code>""</code><code>]], </code>
<code>"container"</code><code>: { </code>
<code>"type"</code><code>:</code><code>"DOCKER"</code><code>, </code>
<code>"docker"</code><code>: { </code>
<code>"image"</code><code>: </code><code>"tomcat"</code><code>, </code>
<code>"network"</code><code>: </code><code>"BRIDGE"</code><code>, </code>
<code>"portMappings"</code><code>: [ </code>
<code>{</code><code>"containerPort"</code><code>: 8080, </code><code>"hostPort"</code><code>: 31001,</code><code>"servicePort"</code><code>: 31002, </code><code>"protocol"</code><code>: </code><code>"tcp"</code> <code>} </code>
<code>] </code>
<code> </code><code>} </code>
<code> </code><code>} </code>
<code> </code><code>}</code>
这里指定了容器端口和对外映射的端口,hostPort为主机上映射的端口,可指定的范围是31000到32000,如果设置为0 表示随机分配端口。当containerPort和hostPort都设置为0时,将随机分配一个相同的端口。
点击“Create Application”即可创建出一个tomcat容器:
<a href="https://s2.51cto.com/wyfs02/M00/9E/09/wKiom1mKe8ayPI0AAAEdLhgGuBA769.jpg" target="_blank"></a>
这里在配置json的时候,我们指定了默认的端口为31001:
如果当某个节点出现故障,或者docker 服务意外退出,mesos会自动掉度容器到其他可用的主机上,如果是指定了容器的对外端口,端口不会改变:
停止mesos6上的docker 服务,tomcat 容器将会漂移到其他slave节点
<code>[root@mesos6 ~]</code><code># systemctl stop docker</code>
查看Marathon上容器状态:
<a href="https://s1.51cto.com/wyfs02/M02/9E/09/wKiom1mKf2Hgp-XVAAD7uUTr1Uc086.jpg" target="_blank"></a>
容器从mesos6 漂移到了mesos4, 对外端口不变:
<code>[root@mesos4 ~]</code><code># docker ps </code>
<code>CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES</code>
<code>03b70cad8ad9 tomcat </code><code>"catalina.sh run"</code> <code>4 minutes ago Up 3 minutes 0.0.0.0:31001->8080</code><code>/tcp</code> <code>mesos-398a0a16-fe13-48e6-9a9c-6932c6c58014-S0.6b97951a-336e-47ab-84c9-38229e9ba132</code>
<code>[root@mesos4 ~]</code><code># docker port 03b70cad8ad9</code>
<code>8080</code><code>/tcp</code> <code>-> 0.0.0.0:31001</code>
mesos创建容器流程
目前,Docker Containerizer 作为任务启动时,需要执行以下操作:
将所有在 CommandInfo 中指定的文件放入一个隔离的沙盒中
从远程仓库拉取 docker 镜像
使用 Docker executor 来运行 docker 镜像,同时将沙盒目录映射到容器中环境变量 MESOS_SANDBOX 所指定的目录。 executor 也将容器的日志流重新定向到外部的 stdout/stderr 文件。
当退出容器或者销毁 containerizer 时,停止并移除 docker 容器实例。
Docker Containerizer 启动的容器的 ID 由 前缀" mesos- " 加上 slave ID( 如,mesos-slave1-abcdefghji )组成,并且假设所有以 " mesos- "为前缀的容器都由 slave 管理,slave 可以任意停止和销毁容器。
在创建容器的时候会出现容器创建不成功的情况,一般有如下几种原因:
1、环境资源不足。在mesos资源管理界面,可以看到当前资源的使用情况,如果容器的cpu,内存,磁盘等资源超出当前环境可以提供的范围,容器创建会失败。
2、当前环境中无可用的镜像。创建容器时,如果本地没有对应的镜像,docker默认会从官方下载,但是下载不一定会成功,可以查看系统进程,如果长时间卡在 docker pull等命令上,就是无法获取镜像。建议先在本地创建好镜像资源。
3、端口指定超出范围。在指定hostPort时,也需要指定servicePort, 且端口范围必须在31000-32000之间,否则创建容器的时候会出错。这个端口范围可以通过配置修改,在实际应用中一般使用marathon-lb来解决随机端口的问题。
参考资料:
本文转自 酥心糖 51CTO博客,原文链接:http://blog.51cto.com/tryingstuff/1954726