另外一篇 https://www.sohu.com/a/157185937_287582
Docker
Docker是一個主流容器管理工具,它是第一個基於Linux容器(LXC)的[2],但是現在被runC[46]所取代了(runC是是一個由Open Containers Initiative開發的CLI工具,它能夠創建和運行容器[36])。Docker容器支持分層的文件系統,因此它能夠和宿主機共享系統內核。這個特性意味着即便一個Docker鏡像基於一個1GB的操作系統,在同一個主機上運行10個容器實例並不需要消耗10GB的空間,相比之下,每一台虛擬機都需要一個完整的1GB操作系統。
Docker的鏡像可以理解為一個操作系統的快照。如果你想要創建一個新的鏡像,你需要啟動一個基礎鏡像,然后做一些修改,最后提交修改,形成新的鏡像。這些鏡像能夠發布在私有或者公有的庫上[10]供其他開發者使用,開發者只需要將鏡像pull下來即可。
使用鏡像可以非常方便的創建操作系統的快照,並且使用它們來創建新的容器,這些功能非常的輕量和易用,這些都是Docer CLI和商業模式的核心。[12]
容器包含了所有運行所需要的東西(代碼,運行時,系統工具,庫),因此Docker給予開發者一個輕量的,穩定的環境來快速地進行創建和運行作業。
容器調度簡介(Description of container schedulers)
容器調度工具的主要任務就是負責在最合適的主機上啟動容器,並且將它們關聯起來。它必須能夠通過自動的故障轉移(fail-overs)來處理錯誤,並且當一個實例不足以處理/計算數據時,它能夠擴展容器來解決問題。
這篇文章比較了三個主流容器調度框架:Docker Swarm ,Apache Mesos (running the Marathon framework) 和 Google Kubernetes]
1.Docker Swarm
Docker Swarm是一個由Docker開發的調度框架。由Docker自身開發的好處之一就是標准Docker API的使用[17]。Swarm的架構由兩部分組成:
Docker Swarm architecture, ©Alexandre Beslic (Docker Inc.) [14]
其中一個機器運行了一個Swarm的鏡像(就像運行其他Docker鏡像一樣),它負責調度容器[4],在圖片上鯨魚代表這個機器。Swarm使用了和Docker標准API一致的API,這意味着在Swarm上運行一個容器和在單一主機上運行容器使用相同的命令。盡管有新的flags可用,但是開發者在使用Swarm的同時並不需要改變他的工作流程。
Swarm由多個代理(agent)組成,把這些代理稱之為節點(node)。這些節點就是主機,這些主機在啟動Docker daemon的時候就會打開相應的端口,以此支持Docker遠程API[5]。其中三個節點顯示在了圖上。這些機器會根據Swarm調度器分配給它們的任務,拉取和運行不同的鏡像。
當啟動Docker daemon時,每一個節點都能夠被貼上一些標簽(label),這些標簽以鍵值對的形式存在,通過標簽就能夠給予每個節點對應的細節信息。當運行一個新的容器時,這些標簽就能夠被用來過濾集群,具體的細節在后面的部分詳談。
策略(Strategies)
Swarm采用了三個策略(比如說,策略可以是如何選擇一個節點來運行容器)[22]:
策略名:節點選擇
- spread:最少的容器,並且忽視它們的狀態
- binpack:最擁擠(比如說,擁有最少數量的CPU/RAM)
- random:隨機選擇
如果多個節點被選中,調度器會從中隨機選擇一個。在啟動管理器(manager)時,策略需要被定義好,否則“spread”策略會被默認使用。
過濾器(Filters)
為了在節點子集中調度容器,Swarm提供了兩個節點過濾器(constraint和health),還有三個容器配置過濾器(affinity,dependency和port)。
約束過濾器(Constraint filter)
每一個節點都關聯有鍵值對。為了找都某一個關聯多個鍵值對的節點,你需要在docker daemon啟動的時候,輸入一系列的參數選項。當你在實際的生產環境中運行容器時,你可以指定約束來完成查找,比如說一個容器只會在帶有環境變量key=prod的節點上運行。如果沒有節點滿足要求,這個容器將不會運行。
一系列的標准約束已經被設置,比如說節點的操作系統,在啟動節點時,用戶並不需要設置它們。
健康過濾器(Health filter)
健康過濾器用來防止調度不健康的節點。在翻看了Swarm的源代碼后,只有少量關於這個概念的信息是可用的。
吸引力過濾器(Affinity filter)
吸引力過濾器是為了在運行一個新的容器時,創建“吸引力”。涉及到容器、鏡像和標簽的吸引力存在有三類。
對容器來說,當你想要運行一個新的容器時,你只需要指定你想要鏈接的容器的名字(或者容器的ID),然后這些容器就會互相鏈接。如果其中一個容器停止運行了,剩下的容器都會停止運行。
鏡像吸引力將會把想要運行的容器調度到已經擁有該鏡像的節點上。
標簽吸引力會和容器的標簽一起工作。如果想要將某一個新的容器緊挨着指定的容器,用戶只需要指定一個key為container,value為<container_name>的吸引力就可以了。
吸引力和約束的語法接受否定和軟強制(soft enforcement),即便容器不可能滿足所有的需求。[18]
依賴過濾器(Dependency filter)
依賴過濾器能夠用來運行一個依賴於其他容器的容器。依賴意味着和其他容器共享磁盤卷,或者是鏈接到其他容器,亦或者和其他容器在同一個網絡棧上。
端口過濾器(Port filter)
如果你想要在具有特定開發端口的節點上運行容器,你就可以使用端口過濾器了。如果集群中沒有任何一個節點該端口可用的話,系統就會給出一個錯誤的提示信息。
2.Apache Mesos & Mesosphere Marathon
Mesos的目的就是建立一個高效可擴展的系統,並且這個系統能夠支持很多各種各樣的框架,不管是現在的還是未來的框架,它都能支持。這也是現今一個比較大的問題:類似Hadoop和MPI這些框架都是獨立開的,這導致想要在框架之間做一些細粒度的分享是不可能的。[35]
因此Mesos的提出就是為了在底部添加一個輕量的資源共享層(resource-sharing layer),這個層使得各個框架能夠適用一個統一的接口來訪問集群資源。Mesos並不負責調度而是負責委派授權,畢竟很多框架都已經實現了復雜的調度。
取決於用戶想要在集群上運行的作業類型,共有四種類型的框架可供使用[52]。其中有一些支持原生的Docker,比如說Marathon[39]。Docker容器的支持自從Mesos 0.20.0就已經被加入到Mesos中了[51]。
我們接下來將會重點關注如何在讓Mesos和Marathon一起工作,畢竟Marathon主要是由Mesosphere維護[41],並且提供了很多關於調度的功能,比如說約束(constraints)[38],健康檢查(health checks)[40],服務發現(service discovery)和負載均衡(load balancing)[42]。
Apache Mesos architecture using Marathon, © Adrian Mouat [49]
我們可以從圖上看到,集群中一共出現了4個模塊。ZooKeeper幫助Marathon查找Mesos master的地址[53],同時它具有多個實例可用,以此應付故障的發生。Marathon負責啟動,監控,擴展容器。Mesos maser則給節點分配任務,同時如果某一個節點有空閑的CPU/RAM,它就會通知Marathon。Mesos slave運行容器,並且報告當前可用的資源。
約束(Constraints)
約束使得操作人員能夠操控應用在哪些節點上運行,它主要由三個部分組成:一個字段名(field name)(可以是slavve的hostname或者任何Mesos slave屬性),一個操作符和一個可選的值。5個操作符如下:
操作符:角色(role)
- UNIQUE:使得屬性唯一,比如說越蘇[“hostname”,”UNIQUE”]使得每個host上只有一個應用在運行。
- CLUSTER:使得運行應用的slaves必須共享同一個特定屬性。比如說約束 [“rack id”, “CLUSTER”, “rack-1”] 強制應用必須運行在rack-1上,或者處於掛起狀態知道rack-1有了空余的CPU/RAM。
- GROUP_BY:根據某個特性的屬性,將應用平均分配到節點上,比如說特定的host或者rack。
- LIKE:使得應用只運行在擁有特定屬性的slaves上。盡管只有CLUSTER可用,但由於參數是一個正則表達式,因此很多的值都能夠被匹配到。
- UNLIKE:和LIKE相反。
健康檢查(Health checks)
健康檢查是應用依賴的,需要被手動實現。這是因為只有開發者知道他們自己的應用如何判斷健康狀態。(這是一個Swarm和Mesos之間的不同點)
Mesos提供了很多選項來聲明每個健康檢查之間需要等待多少秒,或者多少次連續的健康檢查失敗后,這個不健康的任務需要被終結。
服務發現和負載均衡(Service discovery and load balancing)
為了能夠發送數據到正在運行的應用,我們需要服務發現。Apache Mesos提供了基於DNS的服務發現,稱之為Mesos-DNS[44],它能夠在多個框架(不僅僅是Marathon)組成的集群中很好的工作。
如果一個集群只由運行容器的節點組成,Marathon足以承當起管理的任務。在這種情況下,主機可以運行一個TCP的代理,將靜態服務端口的連接轉發到獨立的應用實例上。Marathon確保所有動態分配的服務端口都是唯一的,這種方式比手動來做好的多,畢竟多個擁有同樣鏡像的容器需要同一個端口,而這些容器可以運行在同一個主機上。
Marathon提供了兩個TCP/HTTP代理。一個簡單的shell腳本[37]還有一個更復雜的腳本,稱之為marathon-ld,它擁有更多的功能[43]。
3.Google Kubernetes
Kubernetes是一個Docker容器的編排系統,它使用label和pod的概念來將容器換分為邏輯單元。Pods是同地協作(co-located)容器的集合,這些容器被共同部署和調度,形成了一個服務[28],這是Kubernetes和其他兩個框架的主要區別。相比於基於相似度的容器調度方式(就像Swarm和Mesos),這個方法簡化了對集群的管理.
Kubernetes調度器的任務就是尋找那些PodSpec.NodeName為空的pods,然后通過對它們賦值來調度對應集群中的容器[32]。相比於Swarm和Mesos,Kubernetes允許開發者通過定義PodSpec.NodeName來繞過調度器[29]。調度器使用謂詞(predicates)[29]和優先級(priorites)[30]來決定一個pod應該運行在哪一個節點上。通過使用一個新的調度策略配置可以覆蓋掉這些參數的默認值[33]。
命令行參數plicy-config-file可以指定一個JSON文件(見附錄A)來描述哪些predicates和priorities在啟動Kubernetes時會被使用,通過這個參數,調度就能夠使用管理者定義的策略了。
Kubernetes architecture (containers in grey, pods in color), © Google Inc. [31]
謂詞(Predicates)
謂詞是強制性的規則,它能夠用來調度集群上一個新的pod。如果沒有任何機器滿足該謂詞,則該pod會處於掛起狀態,知道有機器能夠滿足條件。可用的謂詞如下所示:
- Predicate:節點的需求
- PodFitPorts:沒有任何端口沖突
- PodFitsResurce:有足夠的資源運行pod
- NoDiskConflict:有足夠的空間來滿足pod和鏈接的數據卷
- MatchNodeSelector:能夠匹配pod中的選擇器查找參數。
- HostName:能夠匹配pod中的host參數
優先級(Priorities)
如果調度器發現有多個機器滿足謂詞的條件,那么優先級就可以用來判別哪一個才是最適合運行pod的機器。優先級是一個鍵值對,key表示優先級的名字,value就是該優先級的權重。可用的優先級如下:
- Priority:尋找最佳節點
- LeastRequestdPriority:計算pods需要的CPU和內存在當前節點可用資源的百分比,具有最小百分比的節點就是最優的。
- BalanceResourceAllocation:擁有類似內存和CPU使用的節點。
- ServicesSpreadingPriority:優先選擇擁有不同pods的節點。
- EqualPriority:給所有集群的節點同樣的優先級,僅僅是為了做測試。
結論
以上三種框架提供了不同的功能和歸來來自定義調度器的邏輯。從這節來看,顯而易見,由於Swarm的原生API,Swarm是三個中最容易使用的。
以Docker的方式來運行容器[15]意味着一個容器是短暫存在的,並且每一個容器只運行一個進程。根據這條原則,多個容器提供一個服務或者代表一個應用是極度正常的。
因此編排和調度容器成為了最應當解決的問題,這也解釋了為什么,即便這項技術不是很成熟,但仍有那么多的調度器被開發出來,並且提供了不同的功能和選項。