Docker网络和服务发现
【編者的話】 本文是《Docker網絡和服務發現》一書的全文,作者是Michael Hausenblas。本文介紹了Docker世界中的網絡和服務發現的工作原理,并提供了一系列解決方案。
?
前言
當你開始使用Docker構建應用的時候,對于Docker的能力和它帶來的機會,你會感到很興奮。它可以同時在開發環境和生產環境中運行,只需要將一切打包進一個Docker鏡像中,然后通過Docker Hub分發鏡像,這是很直接了當的。你會發現以下過程很令人滿意:你可以快速地將現有的應用(如Python應用)移植到Docker中,將該容器與另一個數據庫容器(如PostgreSQL)連接。但是,你不會想手動啟動一個Docker容器,也不會想自己去實現一個系統來監控運行中的容器和重啟未運行的容器。
此時,你會意識到兩個相互關聯的挑戰:網絡和服務發現。不幸的是,說得好聽一點,這兩個領域都是新興的課題;說得難聽一點,在這兩個領域里,還有很多不確定的內容,也缺乏最佳實踐。幸運的是,在海量的博客和文章中,分散著各種各樣的“秘方”。
?
?
本書
因此,我對自己說:如果有人寫本書,可以介紹這些主題,并提供一些基本的指導,對于每項技術給讀者指引正確的方向,那該多好啊。
那個“人”注定是我, 在本書里,我將介紹Docker容器網絡和服務發現領域中的挑戰和現有的解決方案。 我想讓大家了解以下三點:
?
?
- 服務發現和容器編排就像一枚硬幣的兩面。
- 對于Docker網絡,如果沒有正確的理解和完善的策略,那就糟糕了。
- 網絡和服務發現領域還很年輕。你會發現,剛開始你還在學習一套技術,過一段時間,就會“換擋”,嘗試另一套技術。不要緊張,這是很正常的。在我看來,在形成標準和市場穩定之前,還會有兩三年時間。
編排和調度
嚴格來講,編排是比調度更廣泛的一個概念:編排包含了調度,同時也包含其他內容。例如,容器的故障重啟(可能是由于容器本身不健康,也可能是宿主機出了故障)。而調度僅僅是指,決定哪個容器運行在哪個宿主機上的過程。在本書中,我會無差別地使用這兩個術語。
我這么做的原因是:第一,在IETF RFC和NIST標準中并沒有對這兩個概念的官方定義;第二,在不同公司的市場宣傳中,往往會故意混淆它們,因此我希望你能對此有所準備。然而,Joe Beda(前Google和Kubernetes的策劃者)對于該問題發表了一篇相當不錯的文章:?What Makes a Container Cluster?,你可以更深入地了解一下。
?
?
你
我希望,本書的讀者是:
?
?
- 開發者們,正在使用Docker;
- 網絡Ops,正在為熱情的開發者所帶來的沖擊做準備;
- (企業)軟件架構師,正在將現有負載遷移到Docker,或者使用Docker開始一項新項目;
- 最后但同樣重要的是,我相信,分布式應用的開發者、SRE和后端工程師們也能從其中獲取一些價值。
需要注意的是,本書不是一本動手實踐(hands-on)的書籍(除了第二章的Docker網絡部分),更像是一本指導。當你計劃實施一個基于Docker的部署時,你可以參考本書來做出一個明智合理的決定。閱讀本書的另一種方式是,添加大量注釋和書簽(a heavily annotated bookmark collection)。
?
?
我
我在一個很酷的創業公司Mesosphere, Inc.(Apache Mesos背后的商業公司)工作,主要的工作內容是幫助DevOps充分利用Mesos。雖然我有偏見地認為Mesos是目前進行大規模集群調度的最佳選擇,但是我仍然會盡我最大的努力來確保這種偏愛不會影響對于各項技術的介紹。
?
?
致謝
向Mesosphere同事們James DeFelice和Stefan Schimanski(來自Kubernetes組)致謝,他們很耐心地回答了我關于Kubernetes網絡的問題。向我的Mesosphere同事們Sebastien Pahl和Tim Fall(原Docker同事)致謝,我非常感謝你們關于Docker網絡的建議。也很感謝另一個Mesos同事Mohit Soni,在百忙之中他提供了很多反饋。
進一步地, 我要感謝Medallia的Thorvald Natvig,他的講話Velocity NYC 2015促使我深入地思考了網絡這一領域,他也很友善地和我討論Medallia生產環境中使用Docker/Mesos/Aurora的經驗和教訓。
很感謝Adrian Mouat(容器解決方案)和Diogo Mónica(Docker, Inc.)通過Twitter回答問題,尤其是在普通人睡覺的時候,花了數小時回答了我的問題。
我也很感謝來自Chris Swan的反饋,他提供了明確可操作的評論。通過解決他的問題,我相信本書變得更有針對性了。
在本書的寫作過程中,來自Google的Mandy Waite提供了很多有用的反饋,特別是Kubernetes,我很感謝這一點。我也很感激Tim Hockin(Google)的支持,他幫助我澄清了很多關于Docker網絡特性和Kubernetes的疑惑。
感謝Matthias Bauer對于本書的草稿提出的寶貴意見。
非常感謝我的O’Reilly編輯Brian Anderson。從我們討論草稿開始,你一直都非常支持我,很高效,也很有趣。非常榮幸和您一起工作。
最后重要的一點是,對于我的家庭要致以最深刻的謝意:我的“陽光”Saphira,我的“運動女孩”Ranya,我的兒子和“Minecraft大師”Iannis,以及一直支持我的妻子Anneliese。如果沒有你們的支持,我是不可能完成本書的。
?
?
動機
2012年2月,Randy Bias發表了一篇談話,名為開放和可擴展云架構,提出了pets和cattle兩種文化基因的碰撞。
?
?
- 基礎設施的pets方法(pets approach to infrastructure),每臺機器或虛擬機被當做一個個體,會分配一個名字,各個應用被靜態地部署在各個機器上。例如:?db-prod-2是生產環境中的一臺數據庫服務器。應用是手動部署的,當一臺機器出故障時,你需要修復它,并把應用手動部署到另一臺機器上。在非云原生應用時代(non-cloud-native era),這種方法通常占據著主導地位。
- 基礎設施的cattle方法(cattle approach to infrastructure),所有的機器都是無名的、完全類似的(modulo hardware upgrades),它們只有編號,沒有名字。應用是自動部署到機器群中的任意一臺。當其中一臺機器發生故障時,你不需要立刻處理它,只要在方便的時候更換故障機器(或者它的一部分,如一塊損壞的HDD)。
盡管這些文化基因(meme)最初是針對虛擬機的,但是我們這里會將cattle方法套用在容器的基礎架構上。
?
?
Go Cattle!
在基礎設施中,使用cattle方法的一大好處就是,你可以在商用硬件上進行水平擴展。
這樣一來,你就可以有很大的彈性來實施混合云。只要你愿意,一部分可以部署在premise環境中,一部分部署在公有云上,也可以部署在不同的云提供商的IaaS架構上。
更重要的是,從一名運維者的角度上來看,cattle方法可以保證一個相當好的睡眠質量。因為你再也不會像pets方法中那樣,凌晨3點被叫起來去更換一塊壞了的HDD或者將應用重新部署到另一臺服務器上。
然而,cattle方法也帶來了一些挑戰,主要包括以下兩個方面:
?
?
社交挑戰(Social challenges)
我敢說,大部分挑戰會來自于社交方面:我應該怎么說服我的老板呢?我怎么讓CTO買我的賬呢?我的同事們會反對這種新的做法嗎?這是不是意味著我們只需要更少的人來維護基礎架構?現在,對于這個問題,我還不能提供一個完整有效的解決方案。你可以買一本《鳳凰項目》,從中你可能可以找到答案。
?
技術挑戰(Technical challenges)
這個方面主要包括:機器的準備機制(provisioning mechanism)如何選擇(例如,使用Ansible來部署Mesos Agents);在容器之間、在容器和外界之間如何通信;如何保證容器的自動部署并能被尋址(consequently findable)。
?
Docker網絡和服務發現棧
我們在圖1-1中描述了整個技術棧,包括以下內容:
?
?
底層的網絡層(The low-level networking layer)
這一層包括一系列網絡工具:?iptables、路由、IPVLAN和Linux命名空間。你通常不需要知道其中的細節,除非你是在網絡組,但是你需要意識到這一點。關于這一課題的更多信息,可以參考Docker網絡基礎。
?
Docker網絡層
這一層封裝了底層的網絡層,提供各種抽象模型,例如單主機橋網絡模式、多主機的每個容器一個IP地址的解決方案。在第2章和第3章中有相關介紹。
?
服務發現層/容器編排層
這里,我們將容器調度定義為通過底層提供的基本原語(primitives)決定將容器放在哪里。第4章提到了服務發現的必要背景,第5章從容器編排的角度講解了網絡和服務發現。
軟件定義網絡(SDN)
SDN真的是一個市場術語(umbrella term或者marketing term),它可以提供VM帶來的網絡優勢,就像裸機服務器(bare-metal servers)一樣。網絡管理團隊會變得更加敏捷,對商業需求的變化反應更加迅速。另一種看法是:SDN是一種使用軟件來定義網絡的配置方式,可能是通過API構建、通過NFV構建,或者由Docker網絡來提供SDN。
如果你是一名開發者或架構師,我建議你看一下Cisco對于該課題的觀點和SDxCentral的文章What’s Software-Defined Networking (SDN)?。
?
圖 1-1
如果你在網絡運維組的話,你可能已經準備好進入下一章了。然而,如果你是架構師或者開發者的話,對于網絡知識可能有點生疏了,我建議你讀一下Linux Network Administrators Guide來復習一下相關知識。
?
我需要All-In嗎?
在各種會議和用戶組中,我經常遇到一些人,他們對于容器領域的機會非常興奮,同時他們也擔心在從容器中受益之前需要投入多少。以下的表格是對于我了解的各種部署的非正式的總結(按照階段不同排序)。
?
?
需要注意的是,不是所有的例子都使用Docker容器(顯而易見的是,Google并不使用Docker容器)。其中,某些正在著手使用Docker,例如,在ad-hoc階段;某些正在轉向full-down階段,例如Uber,請看ContainerSched 2015 London中的演講。最后重要的一點是,這些階段與部署的大小是沒有必然關系的。例如,Gutefrage.de只有六臺裸機服務器,仍然使用Apache Mesos來管理它們。?
在繼續之前,還有最后一點:到目前為止,你可能已經注意到了我們處理的是分布式系統。由于我們總是希望將容器部署到一個集群中,我強烈建議你讀一下分布式計算的謬論,以防你不熟悉這一主題。
現在言歸正傳,讓我們進入Docker網絡這一主題。
?
Docker網絡基礎
在我們進入網絡細節之前,我們先來看一看在單主機上發生了什么。Docker容器需要運行在一臺宿主機上,可以是一臺物理機(on-premise數據中心中的裸機服務器),也可以是on-prem或云上的一臺虛擬機。就像圖2-1中描述的那樣,宿主機上運行了Docker的daemon進程和客戶端,一方面可以與Docker registry交互,另一方面可以啟動、關閉和審查容器。
?
?
圖 2-1
宿主機和容器的關系是1:N,這以為這一臺宿主機上可以運行多個容器。例如,從Facebook的報告來看,取決于機器的能力,每臺宿主機上平均可以運行10到40個容器。另一個數據是:在Mesosphere,我們發現,在裸機服務器上的各種負載測試中,每臺宿主機上不超過250個容器是可能的。
無論你是在單主機上進行部署,還是在集群上部署,你總得和網絡打交道:
?
- 對于大多數單主機部署來說,問題歸結于是使用共享卷進行數據交換,還是使用網絡(基于HTTP或者其他的)進行數據交換。盡管Docker數據卷很容易使用,它也引入了緊耦合,這意味著很難將單主機部署轉化為多主機部署。自然地,共享卷的優勢是速度。
- 在多主機部署中,你需要考慮兩個方面:單主機上的容器之間如何通信和多主機之間的通信路徑是怎樣的。性能考量和安全方面都有可能影響你的設計決定。多主機部署通常是很有必要的,原因是單主機的能力有限(請看前面關于宿主機上容器的平均數量和最大數量的討論),也可能是因為需要部署分布式系統,例如Apache Spark、HDFS和Cassandra。
分布式系統和數據本地化(Distributed Systems and Data Locality)
使用分布式系統(計算或存儲)的基本想法是想從并行處理中獲利,通常伴隨著數據本地化。數據本地化,我指的是將代碼轉移到數據所在地的原則,而不是傳統的、其他的方式。考慮下以下的場景:如果你的數據集是TB級的,而代碼是MB級的,那么在集群中移動代碼比傳輸TB級數據更高效。除了可以并行處理數據之外,分布式系統還可以提供容錯性,因為系統中的一部分可以相對獨立地工作。
本章主要討論單主機中的網絡,在第3章中,我們將介紹多主機場景。
簡單地說,Docker網絡是原生的容器SDN解決方案。總而言之,Docker網絡有四種模式:橋模式,主機模式,容器模式和無網絡模式。我們會詳細地討論單主機上的各種網絡模式,在本章的最后,我們還會討論一些常規主題,比如安全。
?
?
bridge模式網絡
在該模式(見圖2-2)中,Docker守護進程創建了一個虛擬以太網橋docker0,附加在其上的任何網卡之間都能自動轉發數據包。默認情況下,守護進程會創建一對對等接口,將其中一個接口設置為容器的eth0接口,另一個接口放置在宿主機的命名空間中,從而將宿主機上的所有容器都連接到這個內部網絡上。同時,守護進程還會從網橋的私有地址空間中分配一個IP地址和子網給該容器。
例2-1
?
?
$?docker?run?-d?-P?--net=bridge?nginx:1.9.1 $?docker?ps CONTAINER?ID???IMAGE??????????????????COMMAND????CREATED STATUS?????????PORTS??????????????????NAMES 17d447b7425d???nginx:1.9.1????????????nginx?-g???19?seconds?ago Up?18?seconds??0.0.0.0:49153->443/tcp,0.0.0.0:49154->80/tcp??trusting_feynman?
?
注意:因為bridge模式是Docker的默認設置,所以你也可以使用docker run -d -P nginx:1.9.1。如果你沒有使用-P(發布該容器暴露的所有端口)或者-p host_port:container_port(發布某個特定端口),IP數據包就不能從宿主機之外路由到容器中。
?
?
圖 2-2
?
?
小技巧:在生產環境中,我建議使用Docker的host模式(將會在下一小節Host模式網路中討論),并輔以第3章中的某個SDN解決方案。進一步地,為了控制容器間的網絡通信,你可以使用flags參數:--iptables和-icc。
?
?
Host模式網絡
該模式將禁用Docker容器的網絡隔離。因為容器共享了宿主機的網絡命名空間,直接暴露在公共網絡中。因此,你需要通過端口映射(port mapping)來進行協調。
?
例2-2 $?docker?run?-d?--net=host?ubuntu:14.04?tail?-f?/dev/null $?ip?addr?|?grep?-A?2?eth0: 2:?eth0:?<BROADCAST,MULTICAST,UP,LOWER_UP>?mtu?9001?qdisc?mq?state?UP?group?default?qlen?1000 link/ether?06:58:2b:07:d5:f3?brd?ff:ff:ff:ff:ff:ff inet?**10.0.7.197**/22?brd?10.0.7.255?scope?global?dynamic?eth0$?docker?ps CONTAINER?ID??IMAGE?????????COMMAND??CREATED STATUS????????PORTS?????????NAMES b44d7d5d3903??ubuntu:14.04??tail?-f??2?seconds?ago Up?2?seconds????????????????jovial_blackwell $?docker?exec?-it?b44d7d5d3903?ip?addr 2:?eth0:?<BROADCAST,MULTICAST,UP,LOWER_UP>?mtu?9001?qdisc?mq?state?UP?group?default?qlen?1000 link/ether?06:58:2b:07:d5:f3?brd?ff:ff:ff:ff:ff:ff inet?**10.0.7.197**/22?brd?10.0.7.255?scope?global?dynamic?eth0
我們可以從例2-2中看到:容器和宿主機具有相同的IP地址10.0.7.197。
在圖2-3中,我們可以看到:當使用host模式網絡時,容器實際上繼承了宿主機的IP地址。該模式比bridge模式更快(因為沒有路由開銷),但是它將容器直接暴露在公共網絡中,是有安全隱患的。
?
圖 2-3
?
Container模式網絡
該模式會重用另一個容器的網絡命名空間。通常來說,當你想要自定義網絡棧時,該模式是很有用的。實際上,該模式也是Kubernetes使用的網絡模式,你可以在這里了解更多內容。
例2-3
?
?
$?docker?run?-d?-P?--net=bridge?nginx:1.9.1 $?docker?ps CONTAINER?ID??IMAGE????????COMMAND???CREATED?????????STATUS PORTS??????????????????????NAMES eb19088be8a0??nginx:1.9.1??nginx?-g??3?minutes?ago???Up?3?minutes 0.0.0.0:32769->80/tcp, 0.0.0.0:32768->443/tcp?????admiring_engelbart $?docker?exec?-it?admiring_engelbart?ip?addr 8:?eth0@if9:?<BROADCAST,MULTICAST,UP,LOWER_UP>?mtu?9001?qdisc?noqueue?state?UP?group?default link/ether?02:42:ac:11:00:03?brd?ff:ff:ff:ff:ff:ff inet?**172.17.0.3**/16?scope?global?eth0$?docker?run?-it?--net=container:admiring_engelbart?ubuntu:14.04?ip?addr ... 8:?eth0@if9:?<BROADCAST,MULTICAST,UP,LOWER_UP>?mtu?9001?qdisc?noqueue?state?UP?group?default link/ether?02:42:ac:11:00:03?brd?ff:ff:ff:ff:ff:ff inet?**172.17.0.3**/16?scope?global?eth0
結果(例2-3)顯示:第二個容器使用了--net=container參數,因此和第一個容器admiring_engelbart具有相同的IP地址172.17.0.3。
?
None模式網絡
該模式將容器放置在它自己的網絡棧中,但是并不進行任何配置。實際上,該模式關閉了容器的網絡功能,在以下兩種情況下是有用的:容器并不需要網絡(例如只需要寫磁盤卷的批處理任務);你希望自定義網絡,在第3章中有很多選項使用了該模式。
例2-4
?
?
$?docker?run?-d?-P?--net=none?nginx:1.9.1 $?docker?ps CONTAINER?ID??IMAGE??????????COMMAND???CREATED STATUS????????PORTS??????????NAMES d8c26d68037c??nginx:1.9.1????nginx?-g??2?minutes?ago Up?2?minutes?????????????????grave_perlman $??docker?inspect?d8c26d68037c?|?grep?IPAddress "IPAddress":?"", "SecondaryIPAddresses":?null,
在例2-4中可以看到,恰如我們所料,網絡沒有任何配置。
你可以在Docker官方文檔中讀到更多關于Docker網絡的配置。
?
?
注意:本書中的所有Docker命令都是在CoreOS環境中執行的,Docker客戶端和服務端的版本都是1.7.1。
?
?
更多話題
在本章中,我們了解了Docker單主機網絡的四種基本模式。現在我們討論下你應該了解的其他主題(這與多主機部署也是相關的):
?
分配IP地址
頻繁大量的創建和銷毀容器時,手動分配IP地址是不能接受的。bridge模式可以在一定程度上解決這個問題。為了防止本地網絡上的ARP沖突,Docker Daemon會根據分配的IP地址生成一個隨機地MAC地址。在下一章中,我們會再次討論分配地址的挑戰。
?
分配端口
你會發現有兩大陣營:固定端口分配(fixed-port-allocation)和動態端口分配(dynamically-port-allocation)。每個服務或者應用可以有各自的分配方法,也可以是作為全局的策略,但是你必須做出自己的判斷和決定。請記住,bridge模式中,Docker會自動分配UDP或TCP端口,并使其可路由。
?
網絡安全
Docker可以開啟容器間通信(意味著默認配置--icc=true),也就是說,宿主機上的所有容器可以不受任何限制地相互通信,這可能導致拒絕服務攻擊。進一步地,Docker可以通過--ip_forward和--iptables兩個選項控制容器間、容器和外部世界的通信。你應該了解這些選項的默認值,并讓網絡組根據公司策略設置Docker進程。可以讀一下StackEngine的Boyd Hemphill寫的文章Docker security analysis。
另一個網絡安全方面是線上加密(on-the-wire encryption),通常是指RFC 5246中定義的TLS/SSL。注意,在寫本書時,這一方面還很少被討論,實際上,只有兩個系統(下一章會詳細討論)提供了這個特性:Weave使用NACl,OpenVPN是基于TLS的。根據我從Docker的安全負責人Diogo Mónica那里了解的情況,v1.9之后可能加入線上加密功能。
最后,可以讀一下Adrian Mouat的Using Docker,其中詳細地介紹了網絡安全方面。
?
?
小技巧: 自動Docker安全檢查 為了對部署在生產環境中的Docker容器進行安全檢查,我強烈建議使用The Docker Bench for Security。現在,我們對單主機場景有了一個基本的了解,讓我們繼續看一下更有效的案例:多主機網絡環境。
?
?
?
Docker多主機網絡
只要是在單主機上使用Docker的話,那么上一章中介紹的技術就足夠了。然而,如果一臺宿主機的能力不足以應付工作負載,要么買一個更高配置的宿主機(垂直擴展),要么你添加更多同類型的機器(水平擴展)。
對于后者,你會搭建一個集群。那么,就出現了一系列問題:不同宿主機上的容器之間如何相互通信?如何控制容器間、容器和外部世界之間的通信?怎么保存狀態,如IP地址分配、集群內保持一致性等?如何與現有的網絡基礎架構結合?安全策略呢?
為了解決這些問題,在本章中,我們會討論多主機網絡的各種技術。
?
?
?
注意:對于本章中介紹的各種選項,請記住Docker信奉的是“batteries included but replaceable”,也就是說,總會有一個默認功能(如網絡、服務發現),但是你可以使用其他方案來替代。
?
?
Overlay
2015年3月,Docker, Inc.收購了軟件定義網絡(SDN)的創業公司SocketPlane,并更名為Docker Overlay驅動,作為多主機網絡的默認配置(在Docker 1.9以后)。Overlay驅動通過點對點(peer-to-peer)通信擴展了通常的bridge模式,并使用一個可插拔的key-value數據庫后端(如Consul、etcd和ZooKeeper)來分發集群狀態。
?
Flannel
CoreOS?Flannel是一個虛擬網絡,分配給每個宿主機一個子網。集群中的每個容器(或者說是Kubernetes中的pod)都有一個唯一的、可路由的IP地址,并且支持以下一系列后端:VXLAN、AWS VPC和默認的2層UDP overlay網絡。flannel的優勢是它降低了端口映射的復雜性。例如,Red Hat的Atomic項目使用的就是flannel。
?
?
Weave
Weaveworks?Weave創建了一個虛擬網絡,用來連接部署在多主機上的Docker容器。應用使用網絡的方式就像是容器直接插入到同一個網絡交換機上,不需要配置端口映射和連接。Weave網絡上的應用容器提供的服務可以直接在公共網絡上訪問,無論這些容器在哪里運行。同樣的,無論位置在哪,現有的內部系統都是暴露給應用容器的。Weave可以穿越防火墻,在部分連接的網絡中運行。流量可以加密,允許主機跨越非授信網絡進行連接。你可以從Alvaro Saurin的文章Automating Weave Deployment on Docker Hosts with Weave Discovery中學習到Weave的更多特性。
?
?
Project Calico
Metaswitch的Calico項目使用標準IP路由,嚴格的說是RFC 1105中定義的邊界網關協議(Border Gateway Protocol,簡稱BGP),并能使用網絡工具提供3層解決方案。相反,大多數其他的網絡解決方案(包括Weave)是通過封裝2層流量到更高層來構建一個overlay網絡。主操作模式不需要任何封裝,是為可以控制物理網絡結構的組織的數據中心設計的。
?
?
Open vSwitch
Open vSwitch是一個多層虛擬交換機,通過可編程擴展來實現網絡自動化,支持標準管理接口和協議,如NetFlow、IPFIX、LACP和802.1ag。除此之外,它還支持在多個物理服務器上分發,和VMware的vNetwork distributed vSwitch、Cisco的Nexus 1000V類似。
?
?
Pipework
Pipework由著名的Docker工程師Jér?me Petazzoni創建,稱為Linux容器的軟件定義網絡。它允許你使用cgroups和namespace在任意復雜的場景中連接容器,并與LXC容器或者Docker兼容。由于Docker, Inc.收購了SocketPlane并引入了Overlay Driver,我們必須看一下這些技術如何融合。
?
?
OpenVPN
OpenVPN,另一個有商業版本的開源項目,運行你創建使用TLS的虛擬私有網絡(virtual private networks,簡稱VPN)。這些VPN也可以安全地跨越公共網絡連接容器。如果你想嘗試一下基于Docker的配置,我建議看一下DigitalOcean很贊的教程How To Run OpenVPN in a Docker Container on Ubuntu 14.04。
?
?
未來的Docker網絡
在最近發布的Docker v1.9中,引入了一個新的命令docker network。容器可以動態地連接到其他網絡上,每個網絡都可以由不同的網絡驅動來支持。默認的多主機網絡驅動是Overlay。
為了了解更多實踐經驗,我建議看一下以下博客:
?
?
- Aleksandr Tarasov的Splendors and Miseries of Docker Network
- Calico項目的Docker libnetwork Is Almost Here, and Calico Is Ready!
- Weave Works的Life and Docker Networking – One Year On
?
?
更多話題
在本章中,我們討論了多主機網絡中的各種解決方案。這一小節會簡要介紹一下其他需要了解的話題:
?
?
IPVLAN
Linux內核v3.19引入了每個容器一個IP地址的特性,它分配給主機上的每個容器一個唯一的、可路由的IP地址。實際上,IPVLAN使用一個網卡接口,創建了多個虛擬的網卡接口,并分配了不同的MAC地址。這個相對較新的特性是由Google的Mahesh Bandewar貢獻的,與macvlan驅動類似,但是更加靈活,因為它可以同時使用在L2和L3上。如果你的Linux發行版已經使用了高于3.19的內核,那么你很幸運;否則,你就無法享受這個新功能。
?
IP地址管理(IPAM)
多主機網絡中,最大的挑戰之一就是集群中容器的IP地址分配。
?
編排工具兼容性
本章中討論的大多數多主機網絡解決方案都是封裝了Docker API,并配置網絡。也就是說,在你選擇其中一個之前,你需要檢查與容器編排工具的可兼容性。更多主題,請看第5章。
?
IPv4 vs. IPv6
到目前為止,大多數Docker部署使用的是標準IPv4,但是IPv6正在迎頭趕上。Docker從v1.5(2015年2月發布)開始支持IPv6。IPv4的持續減少將會導致越來越多的IPv6部署,也可以擺脫NATs。然而,什么時候轉變完成還不清楚。
現在,你已經對底層網絡和Docker網絡的解決方案有了充分理解,讓我們進入下一個內容:服務發現。
?
容器和服務發現
管理基礎架構的cattle方法的最大挑戰就是服務發現。服務發現和容器調度是一枚硬幣的兩面。如果你使用cattle方法的話,那么你會把所有機器看做相同的,你不會手動分配某臺機器給某個應用。相反,你會使用調度軟件來管理容器的生命周期。
那么,問題就來了:如何決定容器被調度到哪臺宿主機上?答對了,這就是服務發現。我們會在第5章詳細討論硬幣的另一面:容器編排。
?
?
挑戰
服務發現已經出現了一段時間了,被認為是zeroconf的一部分。
zeroconf
zeroconf的想法是自動化創建和管理計算機網絡,自動分配網絡地址,自動分發和解析主機名,自動管理網絡服務。
對于Docker容器來說,這個挑戰歸結于穩定地維護運行中容器和位置(location)的映射關系。位置這里指的是IP地址(啟動容器的宿主機地址)和可被訪問的端口。這個映射必須及時完成,并在集群中準確地重啟容器。容器的服務發現解決方案必須支持以下兩個操作:
?
?
注冊(Register)
建立container->location的映射。因為只有容器調度器才知道容器運行在哪,我們可以把該映射當做容器位置的“絕對真理”(the absolute source of truth)。
?
查詢(Lookup)
其他服務或應用可以查詢我們存儲的映射關系,屬性包括信息的實時性和查詢延遲。
讓我們看一下在選擇過程中相對獨立的幾點考慮:
?
- 除了簡單地向一個特定方向發送請求之外,怎么從搜索路徑中排除不健康的宿主機和掛掉的容器?你已經猜到了,這是和負載均衡高度相關的主題,因為這是很重要的,所以本章的最后一小節將討論這一主題。
- 有人認為這是實現細節,也有人認為需要考慮CAP三要素。在選擇服務發現工具時,需要考慮選擇強一致性(strong consistency)還是高可用性(high availability)。至少你要意識到這一點。
- 可擴展性也會影響你的選擇。當然,如果你只有少量的節點需要管理,那么上面討論的解決方案就夠用了。然而,如果你的集群有100多個節點,甚至1000個節點,那么在選擇某一項特定技術之前,你必須做一些負載測試。
?
?
CAP理論1998年,Eric Brewer提出了分布式系統的CAP理論。CAP代表了一致性(consistency)、可用性(availability)和分區容錯性(partition tolerance):?
一致性
分布式系統的所有節點同時看到相同的數據。?
可用性
保證每個請求都能得到響應,無論該響應是成功還是失敗。
分區容錯性?
無論哪塊分區由于網絡故障而失效,分布式系統都可以繼續運行。
CAP理論在分布式系統的實踐中已經討論多次了。你會聽到人們主要討論強一致性 vs 最終一致性,我建議讀一下Martin Kleppmann的論文A Critique of the CAP Theorem。該論文提出了一種不同的、更實際的思考CAP的方法,特別是一致性。
如果你想了解該領域更多的需求和根本的挑戰,可以讀一下Jeff Lindsay的Understanding Modern Service Discovery with Docker和Shopify的Simon Eskildsen在DockerCon分享的內容。
?
?
技術
該小節介紹了各種技術和它們的優缺點,并提供了網上的更多資源(如果你想獲得這些技術的實踐經驗,你可以看看Adrian Mouat的書Using Docker)。
?
?
ZooKeeper
Apache?ZooKeeper是ASF的頂級項目,基于JVM的集中式配置管理工具,提供了與Google的Chubby相兼容的功能。ZooKeeper(ZK)將數據載荷組織成文件系統,成為znodes的層級結構。在集群中,選舉出一個leader節點,客戶端能夠連接到服務器中的任意一個來獲取數據。一個ZK集群中需要2n+1個節點。最常見的配置是3、5、7個節點。
ZooKeeper是經戰場證明的、成熟的、可擴展的解決方案,但是也有一下缺點。有些人認為ZK集群的安裝和管理不是一個令人愉快的體驗。我碰到的大多數ZK問題都是因為某個服務(我想到了Apache Storm)錯誤地使用了它。它們可能在znodes里放入了太多數據,更糟糕的是,他們的讀寫率很不健康(unhealthy read-write ratio),特別是寫得太快。如果你打算使用ZK的話,至少考慮使用高層接口。例如,Apache Curator封裝了ZK,提供了大量的方法;Netflix的Exhibitor可以管理和監控一個ZK集群。
從圖4-1可以看出,你可以看到兩個組件:R/W(作為注冊監控器(registration watcher),你需要自己提供)和NGINX(被R/W控制)。當一個容器被調度到一個節點上時,它會在ZK中注冊,使用一個路徑為/$nodeID/$containerID的znode,IP地址作為數據載荷。R/W監控znodes節點的變化,然后相應地配置NGINX。這種方法對于HAProxy和其他負載均衡器也同樣有效。
?
圖 4-1
?
etcd
etcd是由CoreOS團隊使用Go語言編寫的。它是一個輕量級的、分布式鍵值對數據庫,使用Raft算法實現一致性(帶有leader選舉的leader-follower模型),在集群中使用復制日志(replicated log)向followers分發lead收到的寫請求。從某種意義上說,在概念上,etcd和ZK是相當類似的。雖然負載數據是任意的,但是etcd的HTTP API是基于JSON的。就像ZK一樣,你可以觀察到etcd保存的值的變化。etcd的一個非常有用的特性是鍵的TTL,是服務發現的重要的一個結構單元。和ZK一樣,一個etcd集群至少需要2n+1個節點。
etcd的安全模型支持基于TLS/SSL和客戶端證書加密的線上加密(on-the-wire encryption),加密可以發生在客戶端和集群之間,也可以在etcd節點之間。
在圖4-2中,你可以看到etcd服務發現的搭建和ZK是相當類似的。主要區別在于etcd使用confd來配置NGINX,而不是使用自己編寫的腳本。和ZK一樣,這種搭建方法也適用于HAProxy或者其他負載均衡器。
?
圖 4-2
?
Consul
Consul是HashiCorp的產品,也是用Go語言寫的,功能有服務注冊、服務發現和健康檢查,可以使用HTTP API或者DNS來查詢服務。Consul支持多數據中心的部署。
Consul的其中一個特性是一個分布式鍵值對數據庫,與etcd相似。它也是用Raft一致性算法(同樣需要2n+1個節點),但是部署方式是不同的。Consul有agent的概念,有兩種運行方式:服務器模式(提供鍵值對數據庫和DNS)和客戶端模式(注冊服務和健康檢查),使用serf實現了成員和節點發現。
使用Consul,你有四種方式來實現服務發現(從最可取到最不可取):
?
- 使用服務定義配置文件(service definition config file),由Consul agent解釋。
- 使用traefik等工具,其中有Consul后端(backend)。
- 編寫你自己的進程通過HTTP API注冊服務。
- 讓服務自己使用HTTP API來注冊服務。
想要學習Consul來做服務發現嗎?請閱讀這兩篇文章:Consul Service Discovery with Docker和Docker DNS & Service Discovery with Consul and Registrator。?
?
?
純基于DNS的解決方案
在互聯網中,DNS經受了數十年的戰場驗證,是很健壯的。DNS系統的最終一致性、特定的客戶端強制性地(aggressively)緩存DNS查詢結果、對于SRV記錄的依賴這些因素使你明白這是正確的選擇。
本小節之所以叫做“純基于DNS的解決方案”的原因是,技術上講Consul也是用了DNS服務器,但這只是Consul做服務發現的其中一個選項。以下是著名的、常用的、純粹的基于DNS的服務發現解決方案:
?
?
Mesos-DNS
該解決方案是專門用于Apache Mesos的服務發現的。使用Go編寫,Mesos-DNS下拉任意任務的有效的Mesos Master進程,并通過DNS或HTTP API暴露IP:PORT信息。對于其他主機名或服務的DNS請求,Mesos-DNS可以使用一個外部的域名服務器或者你的現有DNS服務器來轉發Mesos任務的請求到Mesos-DNS。
?
SkyDNS
使用etcd,你可以將你的服務通告給SkyDNS,SkyDNS在etcd中保存了服務定義,并更新DNS記錄。你的客戶端應用發送DNS請求來發現服務。因此,在功能層面,SkyDNS與Consul是相當類似的,只是沒有健康檢查。
?
WeaveDNS
WeaveDNS由Weave 0.9引入,作為Weave網絡的服務發現解決方案,允許容器按照主機名找到其他容器的IP地址。在Weave 1.1中,引入了所謂的Gossip DNS,通過緩存和超時功能使得查詢更加快速。在最新的實現中,注冊是廣播到所有參與的實例上,在內存中保存所有條目,并在本地處理查詢。
?
Airbnb的SmartStack和Netflix的Eureka
在本小節中,我們將會看一下兩個定做的系統,它們是用來解決特定的需求。這并不意味著你不能或者不應該使用它們,你只是需要意識到它們。
Airbnb的SmartStack是一個自動的服務發現和注冊框架,透明地處理創建、刪除、故障和維護工作。在容器運行的同一個宿主機上,SmartStack使用了兩個分離的服務:Nerve(寫到ZK)用于服務注冊,Synapse(動態配置HAProxy)用于查詢。這是一個針對非容器環境的完善的解決方案,隨著實踐推移,你會看到對于Docker,SmartStack也是有用的。
Netflix的Eureka則不同,它運行在AWS環境中(Netflix全部運行在AWS上)。Eureka是一個基于REST的服務,用于定位服務以便負載均衡和中間件層服務器的故障遷移;Eureka還有一個基于Java的客戶端組件,可以直接與服務交互。這個客戶端有一個內置的負載均衡器,可以做基本的round-robin的負載均衡。在Netflix,Eureka用于做red/black部署、Cassandra和memcached部署、承載應用中關于服務的元數據。
Eureka集群在參與的節點之間異步地復制服務注冊信息;與ZK、etcd、Consul不同,Eureka相對于強一致性更傾向于服務可用性,讓客戶端自行處理過時的讀請求,優點是在網絡分區上更有彈性。你也知道的:網絡是不可靠的。
?
負載均衡
服務發現的一個方面是負載均衡,有的時候負載均衡被認為是正交的,有的時候負載均衡被認為是服務發現的一部分。它可以在很多容器之間分散負載(入站服務請求)。在容器和微服務的語境下,負載均衡同時具有以下功能:
?
?
- 最大化吞吐量,最小化響應時間
- 防止熱點(hotspotting),例如單一容器過載
- 可以處理過度激進的DNS緩存(overly aggressive DNS caching)
以下列舉了一些有名的Docker中的負載均衡解決方案:
*?NGINX
*?HAProxy
*?Bamboo
*?Kube-Proxy
*?vulcand
*?Magnetic.io的vamp-router
*?moxy
*?HAProxy-SRV
*?Marathon的servicerouter.py
*?traefik
如果你想了解更多關于負載均衡的信息,請查看Mesos meetup視頻和nginx.conf 2014上關于NGINX和Consul的負載均衡的演講。
?
?
更多話題
在本章的最后,我列舉了服務發現解決方案的一覽表。我并不想評出一個優勝者,因為我相信這取決于你的用例和需求。因此,把下表當做一個快速定位和小結:
?
?
最后請注意:服務發現領域在不斷變化中,每周都會出現新工具。例如,Uber最近開源了它的內部解決方案Hyperbahn,一個路由器的overlay網絡,用來支持TChannel RPC協議。因為容器服務發現在不斷發展,因此你可能要重新評估最初的選擇,直到穩定下來為止。
?
容器和編排
就像上一章中介紹的那樣,使用cattle方法來管理基礎架構,你不必手動為特定應用分配特定機器。相反,你應該使用調度器來管理容器的生命周期。盡管調度是一個重要的活動,但是它其實只是另一個更廣闊的概念——編排的一部分。
從圖5-1,可以看到編排包括健康檢查(health checks)、組織原語(organizational primitives,如Kubernetes中的labels、Marathon中的groups)、自動擴展(autoscaling)、升級/回滾策略、服務發現。有時候base provisioning也被認為是編排的一部分,但是這已經超出了本書的討論范圍,例如安裝Mesos Agent或Kubernetes Kubelet。
服務發現和調度是同一枚硬幣的兩面。決定一個特定的容器運行在集群的哪個節點的實體,稱之為調度器。它向其他系統提供了containers->locations的映射關系,可以以各種方式暴露這些信息,例如像etcd那樣的分布式鍵值對數據庫、像Mesos-DNS那樣的DNS。
?
?
圖 5-1
本章將從容器編排解決方案的角度討論服務發現和網絡。背后的動機很簡單:假設你使用了某個平臺,如Kubernetes;然后,你主要的關注點是平臺如何處理服務發現和網絡。
?
?
注意:接下來,我會討論滿足以下兩個條件的容器編排系統:開源的和相當大的社區。
你可以看一下以下幾個不同的解決方案:Fackebook的Bistro或者托管的解決方案,如Amazon EC2的容器服務ECS。
另外,你如果想多了解一下分布式系統調度這個主題,我推薦閱讀Google關于Borg和Omega的研究論文。
在我們深入探討容器編排系統之前,讓我們先看一下編排的核心組件——調度器到底是做什么的。
?
?
?
調度器到底是做什么的?
分布式系統調度器根據用戶請求將應用分發到一個或多個可用的機器上。例如,用戶可能請求運行應用的100個實例(或者Kubernetes中的replica)。
在Docker中,這意味著:(a)相應的Docker鏡像存在宿主機上;(b)調度器告訴本地的Docker Daemon基于該鏡像開啟一個容器。
在圖5-2中,你可以看到,對于集群中運行的應用,用戶請求了三個實例。調度器根據它對于集群狀態的了解,決定將應用部署在哪里。比如,機器的使用情況、成功啟動應用所必須的資源、約束條件(該應用只能運行在使用SSD的機器)等。進一步地,服務質量也是考量因素之一。
?
?
圖 5-2
通過John Wilkes的Cluster Management at Google了解更多內容。
?
?
警告:對于調度容器的限制條件的語義,你要有概念。例如,有一次我做了一個Marathon的demo,沒有按照預期工作,原因是我沒有考慮布局的限制條件:我使用了唯一的主機名和一個特定的角色這一對組合。它不能擴展,原因是集群中只有一個節點符合條件。同樣的問題也可能發生在Kubernetes的label上。
?
?
Vanilla Docker and Docker Swarm
創造性地,Docker提供了一種基本的服務發現機制:Docker連接(links)。默認情況下,所有容器都可以相互通信,如果它們知道對方的IP地址。連接允許用戶任何容器發現彼此的IP地址,并暴露端口給同一宿主機上的其他容器。Docker提供了一個方便的命令行選項--link,可以自動實現這一點。
但是,容器之間的硬連接(hard-wiring of links)并不有趣,也不具擴展性。事實上,這種方法并不算好。長久來說,這個特性會被棄用。
讓我們看一下更好的解決方案(如果你仍然想要或者必須使用連接的話):ambassador模式。
?
Ambassadors
如圖5-3所示,這個模式背后的想法是使用一個代理容器來代替真正的容器,并轉發流量。它帶來的好處是:ambassador模式允許你在開發階段和生產階段使用不同的網絡架構。網絡運維人員可以在運行時重寫應用,而不需要更改應用代碼。
簡單來說,ambassador模式的缺點是它不能有效地擴展。ambassador模式可以用在小規模的、手動的部署中,但是當你使用真正的容器編排工具(如Kubernetes或Apache Mesos)時,應該避免使用ambassador模式。
?
?
圖 5-3
?
?
注意:如果你想要了解如何在Docker中部署ambassador模式,我再次建議你參考Adrian Mouat的書Using Docker。事實上,在圖5-3中,我使用的就是他的amouat/ambassador鏡像。
?
?
Docker Swarm
除了容器的靜態鏈接(static linking),Docker有一個原生的集群工具Docker Swarm。Docker Swarm基于Docker API構建,并通過以下方式工作:有一個Swarm manager負載調度,在每一個宿主機上運行了一個agent,負責本地資源管理(如圖5-4所示)。
Swarm中有趣的地方在于,調度器是插件式的(plug-able),所以你可以使用除了內置以外的其他調度器,如Apache Mesos。在寫本書的過程中,Swarm發布了1.0版本,并完成了GA(General Availability);新的特性(如高可用性)正在進行開發中。
?
圖 5-4
?
網絡
在本書的第2章和第3章中,我們介紹了Docker中的單宿主機和多宿主機中的網絡。
?
服務發現
Docker Swarm支持不同的后端:etcd、Consul和Zookeeper。你也可以使用靜態文件來捕捉集群狀態。最近,一個基于DNS的服務發現工具wagl被引入到了Swarm中。
如果你想更多了解Docker Swarm,可以讀一下Rajdeep Dua的幻燈片。
?
Kubernetes
Kubernetes(請看圖5-5)是一個opinionated的開源框架,彈性地管理容器化的應用。簡單來說,它吸取了Google超過十年的運行容器負載的經驗,我們會簡要地介紹一下。進一步地,你總是可以選擇其他開源或閉源的方法來替換Kubernetes的默認實現,比如DNS或監控。
?
?
圖 5-5
以下討論假設你已經熟悉Kubernetes和它的技術。如果你還不熟悉Kubernetes的話,我建議看一下Kelsey HighTower的Kubernetes Up and Running。
Kubernetes中,調度單元是一個pod,這是a tightly coupled set of containers that is always collocated。pod運行實例的數目是由Replication Controller定義和指定的。pods和services的邏輯組織是由labels定義的。
在每個Kubernetes節點上,運行著一個稱為Kubelet的agent,負責控制Docker daemon,向Master匯報節點狀態,設置節點資源。Master節點提供API(例如,圖5-6中的web UI),收集集群現在的狀態,并存儲在etcd中,將pods調度到節點上。
?
圖 5-6
?
網絡
在Kubernetes中,每個pod都有一個可路由的IP,不需要NAT,集群節點上的pods之間也可以相互通信。pod中的所有容器共享一個端口命名空間(port namespace)和同一個notion localhost,因此沒有必要做端口代理(port brokering)。這是Kubernetes的基本要求,可以通過network overlay來實現。
在pod中,存在一個所謂的infrastructure容器,kubelet實例化的第一個容器,它會獲得pod的IP,并設置網絡命名空間。pod中的所有其他容器會加入到infra容器的網絡和IPC命名空間。infra容器的網絡啟用了bridge模式(請參考第九頁的bridge模式網絡),pod中的所有其他容器使用container模式(請參考第11頁的container模式網絡)來共享它的命名空間。infra容器中的初始進程實際上什么也沒做,因為它的目的只是提供命名空間的載體。關于端口轉發的最近的work around可能在infra容器中啟動額外的進程。如果infra容器死亡的話,那么Kubelet會殺死pod中所有的進程,然后重新啟動進程。
進一步地,Kubernetes的命名空間會啟動所有control points。其中一個網絡命名空間的例子是,Calico項目使用命名空間來強化coarse-grained網絡策略(policy)。
?
服務發現
在Kubernetes的世界里,有一個服務發現的canonical抽象,這是service primitive。盡管pods隨時可能啟動和銷毀因為他們可能失敗(或者pods運行的宿主機失敗),服務是長時間運行的:它們提供集群層面的服務發現和某種級別的負載均衡。它們提供了一個穩定的IP地址和持久化名字,compensating for the shortlivedness of all equally labelled pods。Kubernetes提供了兩種發現機制:通過環境變量(限制于一個特定節點上)和DNS(集群層面上的)。
?
Apache Mesos
Apache Mesos?(圖5-7)是一個通用的集群資源管理器,抽象了集群中的各項資源(CPU、RAM等),通過這種方式,集群對于開發者來說就像一個巨大的計算機。
在某種程度上,Mesos可以看作是分布式操作系統的內核。因此,它從未單獨使用,總是和其他框架一起工作,例如Marathon(用于long-running任務,如web服務器)、Chronos(用于批量任務)或者大數據框架(如Apache Spark或Apache Cassandra)。
?
?
圖 5-7
Mesos同時支持容器化負載(Docker容器)和普通的可執行文件(包括bash腳本、Python腳本、基于JVM的應用、一個純粹的老的Linux二進制格式),也支持無狀態和有狀態的服務。
接下來,我假設你已經熟悉了Mesos和它的相關技術。如果你不熟悉Mesos,我建議你閱讀David Greenberg的書《Building Applications on Mesos》,該書介紹了Mesos,特別是對于分布式應用的開發者。
如圖5-8所示,你可以看到Marathon的UI,使用Apache Mesos來啟動和管理長期運行的服務和應用。
?
圖 5-8
?
網絡
網絡特性和能力主要取決于Mesos使用的容器方案:
?
- 對于Mesos containerizer來說,有一些要求,如Linux內核版本要大于3.16,并安裝libnl。開啟網絡隔離功能之后,你可以構建一個Mesos Agent。啟動之后,你可以看到以下輸出:
? mesos-slave?--containerizer=mesos?--isolation=network/port_mapping?--resources=ports:[31000-32000];ephemeral_ports:?[33000-35000]
Mesos Agent會配置成使用非臨時(non-ephemeral)端口31000-32000,臨時(ephemeral)端口33000-35000。所有容器共享宿主機的IP地址,端口范圍被分配到各個容器上(使用目的端口和容器ID之間的1:1映射)。通過網絡隔離,你可以定義網絡性能(如帶寬),使得你能夠監控容器的網絡流量。更多細節,請看MesosCon 2015 Seattle上的演講Per Container Network Monitoring and Isolation in Mesos。 - 對于Docker containerizer,請看第二章。
?
?
服務發現
盡管Mesos不提供服務發現功能,但是有一個Mesos特定的解決方案,在praxis中也很常用:Mesos-DNS(Pure-Play DNS-based Solutions)。然而,還有其他的解決方案,如traefik。如果你對于Mesos中的服務發現很感興趣,我們的文檔中有一個專門的章節介紹它。
?
Hashicorp Nomad
Nomad是HashiCorp開發的集群調度器,HashiCorp也開發了Vagrant。Nomad于2015年9月份引入,主要目的是簡化性。Nomad易于安裝和使用。據說,它的調度器設計受到Google的Omega的影響,比如維護了集群的全局狀態、使用優化的、高并發的調度器。
Nomad的架構是基于agent的,它有一個單獨的二進制文件,可以承擔不同的角色,支持滾動升級(rolling upgrade)和draining nodes(為了重新平衡)。Nomad使用了一致性協議(強一致性)來實現所有的狀態復制和調度,使用gossip協議來管理服務器地址,從而實現集群自動化(automatic clustering)和多區域聯合(multiregion federation)。從圖5-9可以看到,Nomad agent正在啟動。
?
?
圖 5-9
Jobs定義為HCL格式(HashiCorp-proprietary format)或JSON格式。Nomad提供了命令行接口和HTTP API,來和服務器進程進行交互。
接下來,我假設你已經熟悉了Nomad和它的術語,否則我不建議你讀這一節。如果你不熟悉的話,我建議你讀一下Nomad: A Distributed, Optimistically Concurrent Schedule: Armon Dadgar, HashiCorp(這是HashiCorp的CTO Armon Dadgar對于Nomad的介紹)和Nomad的文檔。
?
網絡
Nomad中有幾個所謂的任務驅動(task drivers),從通用的Java可執行程序到qemu和Docker。在之后的討論中,我們將會專注后者。
在寫這篇文章的時候,Nomad要求Docker的版本為1.8.2,并使用端口綁定技術,將容器中運行的服務暴露在宿主機網卡接口的端口空間中。Nomad提供了自動的和手動的映射方案,綁定Docker容器的TCP和UDP協議端口。
關于網絡選項的更多細節,例如端口映射(mapping ports)和標簽(labels),我建議你讀一下該文章。
?
服務發現
在v0.2中,Nomad提供了基于Consul的服務發現機制,請參考相關文檔。其中包含了健康檢查(health checks),并假設運行在Nomad中的任務能夠與Consul agent通信(使用bridge模式網絡),這是一個挑戰。
?
我應該用哪個呢?
以下內容當然只是我的一個建議。這是基于我的經驗,自然地,我也偏向于我正在使用的東西。可能有各種原因(包括政治上的原因)導致你選擇一個特定的技術。
從純粹的可擴展性的角度來看,這些選項有以下特點:
?
?
對于少量的節點來說,自然是無所謂的:根據你的偏好和經驗,選擇以上四個選項中的任意一個都可以。但是請記住,管理大規模的容器是很困難的:
?
- Docker Swarm可以管理1000個節點,請參考HackerNews和Docker的這篇博客。
- Kubernetes 1.0據說可以擴展至100個節點,并在持續改進中,以達到和Apache Mesos同樣的可擴展性。
- Apache Mesos可以管理最多50000個節點。
- 到目前為止,還沒有資料表明Nomad可以管理多少個節點。
從工作負載的角度來看,這些選項有以下特點:
?
?
非容器化(Non-containerized)意味著你可以運行任何Linux Shell中可以運行的程序,例如bash或Python腳本、Java程序等。容器化(containerized)以為你需要生成一個Docker鏡像。考慮到有狀態服務,當今應用中的很大一部分需要一些調整。如果你想更多地學習編排工具,請參考:
?
- Docker Clustering Tools Compared: Kubernetes vs Docker Swarm
- O'Reilly Radar的Swarm v. Fleet v. Kubernetes v. Mesos
為了完整性,我想介紹這個領域的一個新成員Firmament,這是一個非常不錯的項目。這個項目的開發者們也是Google的Omega和Borg的貢獻者,這個新的調度器將任務和機器組成了一個流網絡,并運行最小成本優化(minimum-cost optimization)。特別有趣的一點是,Firmament不僅可以單獨使用,也可以與Kubernetes和Mesos整合。
?
?
容器的一天
當選擇使用哪種容器編排方案時,你需要考慮容器的整個生命流程。
?
圖 5-10
Docker容器典型的生命周期包括以下幾個階段:
?
階段1: dev
容器鏡像(你的服務和應用)從一個開發環境中開始它的生命流程,通常是從一名開發者的筆記本開始的。你可以使用生產環境中運行的服務和應用的特性請求(feature requests)作為輸入。
?
階段2: CI/CD
然后,容器需要經歷持續集成和持續發布(continuous integration and continous delivery),包括單元測試、整合測試和冒煙測試。
?
階段3: QA/staging
然后,你可以使用一個QA環境(企業內部或云中的集群)和/或staging階段。
?
階段4:prod
最后,容器鏡像是部署到生產環境中的。你也需要有一個策略去分發這些鏡像。不要忘記以canaries的方式進行構建,并為核心系統(如Apache Mesos)、潛在的高層組件(如Marathon)和你的服務和應用的滾動式升級(rolling upgrade)做計劃。
在生產環境中,你會發現bugs,并收集相關指標,可以用來改善下一個迭代(返回到階段1)。
這里討論的大部分系統(Swarm、Kubernetes、Mesos和Nomad)提供了很多指令、協議和整合點來覆蓋這些階段。然而,在你選擇任何一個系統之前,你仍然需要端到端地試用該系統。
?
社區是很重要的
當選擇編排系統時,另一個你需要考慮的一件方面是背后的社區。以下是一些指標:
?
- 是否由一個正式的實體或流程來管理?例如,Apache軟件基金會或Linux基金會。
- 郵件列表、IRC頻道、bug/issue追蹤器、Git倉庫(補丁或PR的數量)是否活躍?看一下歷史情況,但是請特別注意活躍度。一個健康的社區至少會在其中一個領域非常活躍。
- 該編排工具是否由一個單一實體實際控制?例如,對于Nomad來說,很明顯的是,HashiCorp具有完全控制權。那么Kubernetes和Mesos呢?
- 是否有多個獨立的提供商提供支持?例如,你可以在多個不同的環境中運行Kubernetes或Mesos,并從很多商業或非商業的組織和個人得到幫助。
我們已經到了本書的結尾。在容器的網絡和服務發現方面,你已經學習到了不少知識。看完本章之后,你已經可以選擇和部署容器化應用了。如果你希望深入地了解本書中的各個主體,請查看附錄A,附錄A提供了大量的資源列表。
?
?
?
附錄A 參考
以下這些鏈接,有的包含了背景知識,有的包含了一些高級內容。
?
?
?
網絡參考
- Docker Networking
- Concerning Containers’ Connections: on Docker Networking
- Unifying Docker Container and VM Networking
- Exploring LXC Networking
- Letting Go: Docker Networking and Knowing When Enough Is Enough
- Networking in Containers and Container Clusters
?
服務發現參考
- Service Discovery on?p24e.io
- Understanding Modern Service Discovery with Docker
- Service Discovery in Docker Environments
- Service Discovery, Mesosphere
- Docker Service Discovery Using Etcd and HAProxy
- Service discovery with Docker:?Part 1?and?Part 2
- Service Discovery with Docker: Docker Links and Beyond
?
其他高級話題
- What Makes a Container Cluster?
- Fail at Scale—Reliability in the Face of Rapid Change
- Bistro: Scheduling Data-Parallel Jobs Against Live Production Systems
- Orchestrating Docker Containers with Slack
- The History of Containers
- The Comparison and Context of Unikernels and Containers
- Anatomy of a Container: Namespaces, cgroups & Some Filesystem Magic - LinuxCon
原文鏈接:Docker networking and service discovery(翻譯:夏彬)
總結
以上是生活随笔為你收集整理的Docker网络和服务发现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Go语言学习之encoding/json
- 下一篇: 从HashiCorp Nomad对上百万