为Docker Swarm添加调度策略
Swarm簡介
Swarm是Docker的一個集群管理工具,最開始僅僅是用作集群管理以及簡單的調(diào)度,就像下面的圖所示的,為Docker Client提供與Docker Engine一樣的Docker API,客戶端操作Swarm就好像在操作一臺機器,實際上后面連了好多Docker Engine,容器都跑在后面的Docker Engine上。Swarm負(fù)責(zé)將客戶端的請求分配到后端的Docker Engine,比如客戶端要求啟動一個容器,Swarm找一個目前資源使用最少的Docker Engine。?
因此早期的Swarm比較底層,有點像虛擬機管理器,抽象程度低。而Kubernetes(Google開源的容器管理工具)抽象了很多概念,比如Service,Pod等,更上層,稍微一封裝就可以做成一個PaaS了。為了對抗Kubernetes,Docker也對Swarm做了升級改造,先是SwarmKit,抽象了Service,Task等,然后又把Swarmkit集成到了Docker Engine中,可以使用docker命令把一個結(jié)點設(shè)為swarm mode,然后這個結(jié)點就成了swarm集群的一個結(jié)點。因此最新的Swarm不再是一個工具,而是一個集群,我們把集群稱作Swarm,然后這個集群里面有manager和worker兩種角色,manager中有一個leader,通過Raft算法實現(xiàn)數(shù)據(jù)一致性。總之很多方面都抄了Kubernetes。
可以在Swarm集群中創(chuàng)建Service,而一個Service有多個實例,比如我創(chuàng)建一個tomcat的Service,名字是tomcat_service,使用的鏡像是tomcat,然后創(chuàng)建3個實例,也就是啟動3個容器,用下面的命令:
docker service create --name tomcat_service ?--replicas 3 tomcat
在manager上執(zhí)行這個命令,manager會把3個容器按調(diào)度策略分配到不同的worker上(manager也可以當(dāng)做worker)。
swarm的調(diào)度策略是:在滿足constraint的worker中找一個task(也就是容器數(shù))最少的結(jié)點,這種策略叫做spread策略,就是盡可能的把task平均分布到不同結(jié)點。constraint是指一些必須滿足的條件,比如某個task要求分配2G內(nèi)存。
spread策略是沒問題的,但是swarm在調(diào)度的時候沒有把一項很重要的內(nèi)容加進去,那就是實例的容災(zāi)。
我搭了一個3個結(jié)點的Swarm集群,manager1,worker1和worker2,創(chuàng)建了一個hello服務(wù),有4個replica,一個world服務(wù),有2個replica,如下:
看上去3個結(jié)點每個結(jié)點兩個replica,挺好的,但是有一個嚴(yán)重的問題,world服務(wù)的兩個replica被調(diào)度到同一臺主機上,那么這臺主機掛了,整個服務(wù)就掛了。其實replica的概念就是要在多個地方存放,以防止單主機出現(xiàn)問題導(dǎo)致服務(wù)不可用。比如HDFS的3個replica一般要放到不同機器上,甚至還要考慮不同機柜,不同機房。 Kubernetes在調(diào)度的時候也考慮了多個replica放到多臺主機上的策略。 docker的開發(fā)人員目前只忙著出產(chǎn)品,沒功夫去精雕細(xì)琢細(xì)節(jié)到地方,不過多個replica放到不同主機之后肯定是會加進去的。
本文介紹如何修改Docker 1.12的代碼把replica容災(zāi)的策略加到Swarm調(diào)度策略中。
Swarm調(diào)度算法介紹
老的Swarm調(diào)度算法可以用下面的圖表示:
1.一個調(diào)度請求過來,里面包含很多constraint,比如需要分配4G內(nèi)存,或者要求必須調(diào)度上含有production標(biāo)簽的結(jié)點上,或者要求某個結(jié)點沒有被占用。?
2.所有的結(jié)點作為一個List傳到一個filter鏈里,這個filter會過濾掉不符合條件的結(jié)點,比如內(nèi)存不夠,輸出一個符合條件的結(jié)點List
3.按照策略進行排序,排名最高的就是要調(diào)度的結(jié)點
策略有三個:
spread: 默認(rèn)策略,盡量均勻分布,找容器數(shù)少的結(jié)點調(diào)度
binpack: 和spread相反,盡量把一個結(jié)點占滿再用其他結(jié)點
random: 隨機
老的Swarm沒有replica的概念,每個實例都是獨立的個體,所以不需要在調(diào)度的時候考慮多副本部署到不同主機。 新的Swarm調(diào)度算法和老Swarm差不多,不過不再提供策略選擇,只提供了spread策略。
新的Swarm把結(jié)點信息放到一個堆里(堆排序的堆),以當(dāng)前結(jié)點上的容器數(shù)為建堆的標(biāo)準(zhǔn)建一個最小堆,這樣查找起來就特別快了。
代碼改造
改造策略
最優(yōu)解:對于一個task,找到的結(jié)點應(yīng)該不含與這個task屬于同一個service的task,同時這個結(jié)點在符合這個條件的結(jié)點中task數(shù)最少。
次優(yōu)解:所有滿足硬性constraint的結(jié)點都啟動了與這個task屬于同一個service的task,只能在這其中找一個task數(shù)最少的了。
代碼修改
修改兩個源文件就可以
修改代碼docker/vendor/src/github.com/docker/swarmkit/manager/scheduler/indexed_node_heap.go
1.添加一個函數(shù),定義一個constraint稱為multihostConstraint,意思是同一個service的不同副本要落到不同主機上,與其它強制性的constraint不一樣,這個是盡量滿足的constraint
| 1 2 3 4 5 6 7 8 9 10 | //檢查某個結(jié)點是否已經(jīng)存在屬于同一個service的task func?meetMultihosConstraint(nodeInfo?*NodeInfo,?serviceID?string)?bool?{ ????for?_,?task?:=?range?nodeInfo.Tasks?{ ????????sID?=?task.ServiceID ????????if?sID?==?serviceID?{ ????????????return?false ????????} ????} ????return?true } |
2.修改搜索nodeHeap的函數(shù)searchHeapToFindMin,加一個參數(shù)serviceID
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | func?(nh?*nodeHeap)?searchHeapToFindMin( ????meetsConstraints?func(*NodeInfo)?bool,? ????serviceID?string)? ????????????(*api.Node,?int)?{ ????var?bestNode?*api.Node???//滿足multihostConstraint同時task最少的結(jié)點 ????var?secondBestNode?*api.Node?//沒有滿足multihostConstraint的,只能選一個task最少的結(jié)點 ????minTasks?:=?int(^uint(0)?>>?1)?//?max?int ????secondMinTasks?:=?minTasks ????if?nh?==?nil?||?len(nh.heap)?==?0?{ ????????return?bestNode,?minTasks ????} ????//?push?root?to?stack?for?search ????stack?:=?[]int{0} ????for?len(stack)?!=?0?{ ????????//?pop?an?element ????????idx?:=?stack[len(stack)-1] ????????stack?=?stack[0?:?len(stack)-1] ????????heapEntry?:=?&nh.heap[idx] ????????if?len(heapEntry.Tasks)?>=?minTasks?{ ????????????continue ????????} ????????if?meetsConstraints(heapEntry)?{ ????????????//滿足強制性constraint,再檢查是否滿足multihostConstraint ????????????if?meetMultihosConstraint(heapEntry,?serviceID)?==?true?{ ????????????????bestNode?=?heapEntry.Node ????????????????minTasks?=?len(heapEntry.Tasks) ????????????}?else?{ ????????????????if(len(heapEntry.Tasks)?<?secondMinTasks)?{ ????????????????????secondBestNode?=?heapEntry.Node ????????????????????secondMinTasks?=?len(heapEntry.Tasks) ????????????????} ????????????} ????????}?else?{ ????????????//?otherwise,?push?2?children?to?stack?for?further?search ????????????if?2*idx+1?<?len(nh.heap)?{ ????????????????stack?=?append(stack,?2*idx+1) ????????????} ????????????if?2*idx+2?<?len(nh.heap)?{ ????????????????stack?=?append(stack,?2*idx+2) ????????????} ????????} ????} ????if?bestNode?==?nil?{ ????????bestNode?=?secondBestNode ????????minTasks?=?secondMinTasks ????} ????return?bestNode,?minTasks } |
修改代碼docker/vendor/src/github.com/docker/swarmkit/manager/scheduler/scheduler.go里的scheduleTask函數(shù)
| 1 2 3 4 5 6 7 | //?scheduleTask?schedules?a?single?task. func?(s?*Scheduler)?scheduleTask(ctx?context.Context,?t?*api.Task)?*api.Task?{ ?s.pipeline.SetTask(t) ?//這個函數(shù)直接改成searchHeapToFindMin ?//s.scanAllNodes是是否掃描全部結(jié)點的標(biāo)志,直接改成false ?//n,?_?:=?s.nodeHeap.findMin(s.pipeline.Process,?s.scanAllNodes) ?n,_??:=?s.nodeHeap.searchHeapToFindMin(s.pipeline.Process,?false,?t.ServiceID) |
本文轉(zhuǎn)自nxlhero 51CTO博客,原文鏈接:http://blog.51cto.com/nxlhero/1841726,如需轉(zhuǎn)載請自行聯(lián)系原作者
總結(jié)
以上是生活随笔為你收集整理的为Docker Swarm添加调度策略的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: nagios监控mysql主从复制
- 下一篇: 注意啦!10 个你需要了解的 Linux