由Docker引領的容器技術最近一年在生產環境叫囂的比較厲害,因爲Docker自己擁有的一些特性,使得愈來愈多的人願意而且想嘗試在生產環境構建Docker,有關docker相關的介紹能夠看我去年發佈的文章(http://my.oschina.net/xxbAndy/blog/493184 )。然而隨着業務的規模不斷擴大,對docker的管理和維護也對運維人員有一些挑戰,使用一些開源的框架和服務知足互聯網公司的基本需求是一種常見而高效的方式,本篇文章就簡單介紹一下使用Mesos+Marathon來對docker集羣進行管理和維護。java
1、Mesos簡介linux
Mesos是Apache下的開源分佈式資源管理框架,它被稱爲是分佈式系統的內核,提供了有效的、跨分佈式應用或框架的資源隔離和共享,能夠運行Hadoop、MPI、Hypertable、Spark、docker等。nginx
上圖是mesos的管理服務的架構流程圖,主要進程包括一個 主控 守護進程,用來管理子節點的 被控 守護進程,也即Mesos-master和Mesos-slave。web
能夠看到整個mesos架構會有如下幾個角色:docker
Mesos master,主要負責管理各個framework和slave,並將slave上的資源分配給各個framework
Mesos slave,負責管理本節點上的各個mesos-task,好比:爲各個executor分配資源
Framwork,計算框架,如:Hadoop,Spark,Docker等,經過MesosSchedulerDiver接入Mesos
Excutor,執行器,安裝到mesos-slave上,用於啓動計算框架中的task。apache
主控(Mesos-master)負責決定給每一個應用分配多少資源,而應用框架(部署在mesos-slave上的服務)的調度器纔會真正選擇使用哪些被分配到的資源。當應用框架接收了分配的資源,它會向Mesos發送一個它但願運行任務的描述信息。而後,Mesos會負責在相應的被控節點上啓動任務。json
資源調度流程:vim
詳細mesos教程請查看官方文檔:http://mesos.mydoc.io/centos
2、Marathon基礎知識api
Marathon(馬拉松)是一個全新的框架,它將Mesos變成一個更有活力的工具,進而能夠在單一的集羣上運行不一樣的應用程序。
它的設計宗旨就是讓用戶在同一組服務器之上,更智能地運行多種應用程序和服務——Hadoop、Storm,甚至一個標準的Web應用。Marathon出自於一家初創公司 Mesosphere之手,這家公司主要就是想構建一個數據中心操做系統,不過這個系統是運行在Apache Mesos集羣管理軟件之上,這也是 Twitter基礎設施的重要組成部分。
Mesos僅僅是適用於集羣的管理,這意味着它能夠隔離不一樣的任務負載。可是仍然須要額外的工具來幫助工程師查看不一樣系統上運行的工做負載。否則的話,若是某些工做負載消耗了全部資源,那麼重要的工做負載可能就難以及時地得到資源。
想要理解mesos和marathon之間的關係,簡單粗暴的能夠理解爲mesos就是集羣的內核,負責資源調度,而marathon則是集羣的進程管理器(init.d/systemd),用來管理應用的狀態信息。
3、Zookeeper基礎知識
因爲mesos組件之間的調度須要使用zk來共享配置信息,所以這裏講對zookeeper進行簡單的介紹。
ZooKeeper是用來給集羣服務維護配置信息,域名服務,提供分佈式同步和提供組服務。全部這些類型的服務都使用某種形式的分佈式應用程序。是一個分佈式的,開放源碼的協調服務,是的Chubby一個的實現,是Hadoop和Hbase的重要組件。
Zookeeper分爲如下幾個角色:
領導者(leader):領導者負責投票發起和決議,更新系統狀態
跟隨者(follwoer):follower用於接收客戶請求並向客戶端返回結果,在選主過程當中參與投票
觀察者:ObServer能夠接受客戶端鏈接,將寫請求轉發給leader節點,但ObServer不參加投票過程,只同步leader的狀態,ObServer的目的是爲了拓展系統,提升讀取速度。
客戶端:請求發起方
Zookeeper工做原理:
Zookeeper的核心是原子廣播,這個機制保證了各個Server之間的同步。實現這個機制的協議叫作Zab協議。Zab協議有兩種模式,它們分別是恢復模式(選主)和廣播模式(同步)。當服務啓動或者在領導者崩潰後,Zab就進入了恢復模式,當領導者被選舉出來,且大多數Server完成了和leader的狀態同步之後,恢復模式就結束了。狀態同步保證了leader和Server具備相同的系統狀態。
爲了保證事務的順序一致性,zookeeper採用了遞增的事務id號(zxid)來標識事務。全部的提議(proposal)都在被提出的時候加上了zxid。實現中zxid是一個64位的數字,它高32位是epoch用來標識leader關係是否改變,每次一個leader被選出來,它都會有一個新的epoch,標識當前屬於那個leader的統治時期。低32位用於遞增計數。
每一個Server在工做過程當中有三種狀態:
LOOKING:當前Server不知道leader是誰,正在搜尋
LEADING:當前Server即爲選舉出來的leader
FOLLOWING:leader已經選舉出來,當前Server與之同步
4、Mesos+Marathon+Docker集羣部署
(一)系統環境
#uname -r
3.10.0-327.4.5.el7.x86_64
#cat /etc/redhat-release
CentOS Linux release 7.2.1511 (Core)
(二)架構
兩臺主機:
10.13.18.23 mesos-master,mesos-slave,marathon,docker,zk僞分佈式
10.13.18.22 mesos-slave,docker
注意,兩臺主機必須能夠相互解析到。所以須要在/etc/hosts下進行配置
#cat /etc/hosts
docker1 10.13.18.23
docker2 10.13.18.22
#hostnamectl set-hostname docker1
#hostnamectl set-hostname docker2
(三)組件部署
1.安裝docker
#yum install docker
#sysctmctl start docker
#docker --version 查看docker的當前版本
centos7默認自帶的是1.10.3
注意:docker須要libcgroup支持
#docker pull nginx #先下載一個最新版本的nginx鏡像
#docker images #查看docker當前鏡像文件
#docker run -itd -h nginx --name nginx -p 80:80 docker.io/nginx
#curl localhost:80 #測試nginx容器是否正常
2.mesos+mathron+zookeeper集羣搭建
2.1 zookeeper搭建:
因爲zk是進行配置發現的,所以也須要配置成集羣模式,在這裏我將使用docker1主機進行搭建zk僞分佈式
#wget http://mirrors.cnnic.cn/apache/zookeeper/stable/zookeeper-3.4.8.tar.gz -P /export/zookeeper
也可使用cdh的源
#rpm -Uvh http://archive.cloudera.com/cdh4/one-click-install/redhat/6/x86_64/cloudera-cdh-4-0.x86_64.rpm
固然了運行zk是須要java環境的
#tar zxf zookeeper-3.4.8.tar.gz
編輯僞分佈式zk配置模板,以下:
[root@docker1 conf]# cat /export/zookeeper/zookeeper-3.4.8/conf/zoo.cfg
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/export/zookeeper/zk1
clientPort=2181
server.1=10.13.18.23:3181:4181
server.2=10.13.18.23:3182:4182
server.3=10.13.18.23:3183:4183
[root@docker1 conf]# cp zoo.cfg zk1.cfg
[root@docker1 conf]# cp zoo.cfg zk2.cfg
[root@docker1 conf]# cp zoo.cfg zk3.cfg
[root@docker1 conf]# sed -i 's/2181/2182/' zk2.cfg
[root@docker1 conf]# sed -i 's/2181/2183/' zk3.cfg
[root@docker1 conf]# sed -i 's/zk1/zk3/' zk3.cfg
[root@docker1 conf]# sed -i 's/zk1/zk2/' zk2.cfg
[root@docker1 conf]# for i in 1 2 3;do mkdir -p /export/zookeeper/zk$i;done
[root@docker1 conf]# for i in 1 2 3;do echo $i > /export/zookeeper/zk$i/myid;done
啓動zk:
[root@docker1 conf]# /export/zookeeper/zookeeper-3.4.8/bin/zkServer.sh start /export/zookeeper/zookeeper-3.4.8/conf/zk1.cfg
[root@docker1 conf]# /export/zookeeper/zookeeper-3.4.8/bin/zkServer.sh start /export/zookeeper/zookeeper-3.4.8/conf/zk2.cfg
[root@docker1 conf]# /export/zookeeper/zookeeper-3.4.8/bin/zkServer.sh start /export/zookeeper/zookeeper-3.4.8/conf/zk3.cfg
啓動完成後查看下狀態,通常zk集羣個數爲3個會比較好些,所以有一些節點是Mode: leader ;Mode: follower
[root@docker1 conf]# /export/zookeeper/zookeeper-3.4.8/bin/zkServer.sh status /export/zookeeper/zookeeper-3.4.8/conf/zk3.cfg
zk啓動異常
查看日誌文件:
zookeeper.out
2016-07-10 14:58:24,367 [myid:1] - INFO [QuorumPeer[myid=1]/0:0:0:0:0:0:0:0:2181:FastLeaderElection@818] - New election. My id = 1, proposed zxid=0x0
2016-07-10 14:58:24,368 [myid:1] - INFO [WorkerReceiver[myid=1]:FastLeaderElection@600] - Notification: 1 (message format version), 1 (n.leader), 0x0 (n.zxid), 0x1 (n.round), LOOKING (n.state), 1 (n.sid), 0x0 (n.peerEpoch) LOOKING (my state)
2016-07-10 14:58:24,373 [myid:1] - WARN [WorkerSender[myid=1]:QuorumCnxManager@400] - Cannot open channel to 2 at election address /10.81.152.47:4182
java.net.ConnectException: Connection refused
at java.net.PlainSocketImpl.socketConnect(Native Method)
at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
at java.net.Socket.connect(Socket.java:589)
at org.apache.zookeeper.server.quorum.QuorumCnxManager.connectOne(QuorumCnxManager.java:381)
at org.apache.zookeeper.server.quorum.QuorumCnxManager.toSend(QuorumCnxManager.java:354)
at org.apache.zookeeper.server.quorum.FastLeaderElection$Messenger$WorkerSender.process(FastLeaderElection.java:452)
at org.apache.zookeeper.server.quorum.FastLeaderElection$Messenger$WorkerSender.run(FastLeaderElection.java:433)
at java.lang.Thread.run(Thread.java:745)
修改內核配置:
net.ipv4.ip_local_port_range = 1024 65535
2.2 mesos+marthon搭建:
配置mesosphere源:
由於docker節點是須要裝mesos-slave的,所以在全部的docker節點都應該安裝
[root@docker1 zookeeper]# rpm -Uvh http://repos.mesosphere.com/el/7/noarch/RPMS/mesosphere-el-repo-7-1.noarch.rpm
[root@docker2 ~]# rpm -Uvh http://repos.mesosphere.com/el/7/noarch/RPMS/mesosphere-el-repo-7-1.noarch.rpm
安裝mesos和marthon:
[root@docker1 conf]# yum -y install mesos marathon
[root@docker2 conf]# yum -y install mesos marathon
配置mesos:
[root@docker1 zookeeper]# cat /etc/mesos/zk
zk://10.13.18.23:2181,10.13.18.23:2182,10.13.18.23:2183/mesos
啓動mesos:
[root@docker1 zookeeper]# systemctl start mesos-master
[root@docker1 zookeeper]# systemctl start mesos-slave
[root@docker1 zookeeper]# systemctl start marathon
docker2只是一個應用節點,所以啓動slave就行:
須要注意的是由於其實marathon就相似init.d,所以針對mesos來講,他也是一個應用,因此須要用marathon去管理mesos-slave
[root@docker2 ~]# systemctl start mesos-slave
[root@docker2 zookeeper]# systemctl start marathon
Mesos-master啓動以後會默認開啓5050一個web端口,用來進行資源協調。(linux kernel)
marathon 啓動會默認開啓一個8080端口,進行任務調度(init.d)
訪問http://10.13.18.23:5050 能夠查看mesos相關信息:
此時點擊slave會發現當前mesos集羣管理着兩個資源節點,即docker1和docker2主機。
訪問http://10.13.18.23:8080 能夠查看marathon的相關信息:
看到mesos和marathon的相關信息以後,我就能夠任務mesos+marathon架構已經基本搭建完成。
(四)mesos+marathon架構的簡單應用
4.1 建立tst_task任務
默認的mesos管控任務裏其實沒有任務進程的,可使用如下的命令簡單建立任務:
#MASTER=$(mesos-resolve `cat /etc/mesos/zk`)
#mesos-execute --master=$MASTER --name="cluster-test" --command="sleep 60"
此時就會發如今mesos的web界面上出現一個新的任務:
4.2 使用marathon建立nginx的docker容器,使用mesos進行調度。
注意:marathon啓動的時候會根據mesos的信息連接zk。
配置Mesos運行Docker容器:
再全部mesos-slave上增長配置參數,並重啓
#echo 'docker,mesos' | tee /etc/mesos-slave/containerizers
#systemctl restart mesos-slave
首先,咱們建立一個json文件,用來經過marathon的api進行建立容器:
#vim nginx.json
{
"id":"nginx",
"cpus":0.2,
"mem":20.0,
"instances": 1,
"constraints": [["hostname", "UNIQUE",""]],
"container": {
"type":"DOCKER",
"docker": {
"image": "nginx",
"network": "BRIDGE",
"portMappings": [
{"containerPort": 80, "hostPort": 0,"servicePort": 0, "protocol": "tcp" }
]
}
}
}
建立容器,成功建立後會返回json串
[root@docker1 ~]# curl -X POST http://10.81.152.47:8080/v2/apps -d @nginx.json -H "Content-type: application/json"
[root@docker1 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0d5c10207f04 nginx "nginx -g 'daemon off" About a minute ago Up About a minute 443/tcp, 0.0.0.0:31975->80/tcp mesos-ce041d30-c4bc-437d-829c-4fb09b0ce682-S0.b99a86b5-3b6f-4c58-b3db-e6ff0d2c6bcf
此時就能夠看到使用marathon的api建立的nginx容器了,能夠訪問本地的31975端口來測試nginx的正常與否。
成功的使用marathon建立了一個docker容器!