看到一篇介紹 Docker swarm以及如何編排的好文章,挪放到這里,自己學習的同時也分享出來。
原文鏈接: http://wwwbuild.net/dockerone/414200.html
Docker社區目前最熱的話題莫過於Docker 1.12的發布, 明顯的感覺就是大家都在討論Docker 1.12的新功能,各種關於1.12的使用手冊,文章,深度教程層出不窮, 一句話總結來說, 不知道Docker 1.12都不好意思跟人打招呼了。
個人理解Docker 1.12最大的功能莫過於SwarmKit的引入,這應該算是Docker發展里程碑式的一個Release(上一個里程碑應該是runC和Containerd的剝離,標志着Docker公司自己孤獨地玩到容器標准化概念引入),自此再也不要說Docker是主機容器管理了, Docker已經能夠管理一群主機上的容器了。概念上Docker引入了node、service、task甚至更高於service一層的stack, 自此大家會發現容器和網絡已經不是Docker的first-class概念, 取而代之的是service、 stack和跨主機網絡。Docker SwarmKit的引入給容器編排投入了一顆重磅炸彈, 給我的感覺是原來容器編排還可以這么玩,終於不要某某sos和某8s的全家桶了, 在容器編排的遠古時代(其實也不遠,就是觀念陳舊)不裝個五六七八個組件都不好意思跟人說是編排, 真的有這個必要么? 當然了, Docker Swarm主要功能還是是借鑒了“遠古時代”的幾款產品, 吸收了前人的優秀經驗。 讓我列幾個牛哄哄的功能給大家吧:
-
內置Raft, 媽媽再也不用擔心我還要依賴Zookeeper、Etcd、Consul了, 光部署這些東西就浪費我一整天外加三台機器。
-
不區分管理節點和Worker節點,想讓誰上就讓誰上, 猜想是參考了人家Nomad吧, 關鍵還能運行時Promote、Demote, 太方便了。
-
Service,Stack外加DAB, 用過都說好, 方便。
-
Rolling Update, Scale一個Service,灰度發布分分鍾搞定(雖然有點雞肋),這個不用說也是借鑒了Kubernetes。
一張圖展示一下Docker1.12的和老版本的功能對比。
當然當前Docker 1.12的功能還很初級,還沒有聽說過有人大規模生產級的應用(據說能管理2000個節點,10W個容器),不過看的出來SwarmKit team新功能推出的速度還是相當快的。 個人很看好這一趨勢。
下面分享一下Docker的一個服務是如何被外部訪問的。
在沒有Docker的時代我們更喜歡的兩種辦法來部署一個服務 1, 單個機器上的單個進程,綁定到固定IP上的固定端口, 這種方式的優點是簡單明了,程序員同學們需要做的事情最大化的優化單個進程的處理能力, 保障這個進程不會因為各種問題退出, 因為一旦退出就沒得玩了。 2, 單個機器上的多個進程綁定到固定端口, 前面放一個代理工具。
容器化后大家發現以前的做法或多或少需要做些調整, 第一,由於主機概念被弱化,集群概念被突出, 應用程序不再依賴某個主機或者某個端口; 第二, 容器生命周期不固定, 容器可以隨時被啟動被停止, 容器的數量可多可少(這就是我們常說的彈性)。由於上面提到的兩個容器化的特性,一些新的問題被引入,聰明的工程師們想到了一些解決辦法來應對這些問題, 第一個解決辦法就是我們要談到的服務發現,針對的問題是服務對外地址不定和服務隨時被啟動停止。 服務被發現以后要解決是如何把任務按照一定規則負載到容器中, 這就是第二個我們要談的負載均衡。 負載均衡解決了單一入口負載到多個容器上問題, 但是由於容器調度之后可能落到多個機器上, 假如某些主機上面沒有工作的容器,而對外服務時候又希望服務可以被訪問, Routing Mesh概念引入是解決多個入口點負載到單個容器的問題。
服務發現
單純的服務發現很好實現, 無非就是監測Container的啟動、停止, 根據這些變動記錄下服務到底可以通過哪些IP+端口可以被訪問, 理論上實現一個初級的可用的服務發現不會超過十行代碼。成熟的服務發現還需要額外的工作比如健康檢查, 注意到我們之前是假設了容器啟動就可以對外服務, 實際中情況可能遠非如此, 一個應用啟動之后可能要准備環境, 加載數據之后才可以對外服務,健康檢查是保證服務可用之后再對外服務。 另外一個成熟的服務發現必備條件是高可用, 明眼人可能已經發現之前的簡單版本不具備高可用和狀態一致性, 這也是為什么Docker引入了Raft協議。
負載均衡
傳統理解的負載均衡根據協議不同可以分為7層的和4層的, 7層負載均衡特點是可以支持很復雜的用戶規則,比如HTTP header、Cookie等應用邏輯, 而4層只能支持到IP地址負載不同服務。
Docker1.12的服務發現和負載均衡是結合到一起的, 實現辦法有兩種,DNS輪詢和IPVS。 理解這兩種策略之前需要知道的一個前提是Docker為每個服務都分配了一個虛擬IP, 這個IP對應的不是具體的一個Task或者一個具體的Container,而是專門為一個服務保留。
下面我們舉例子分別說明一下兩種負載均衡實現:
首先准備一下環境。
第一步如下圖所示用Go寫一段小代碼, 編譯成二進制放在一個ubuntu基礎鏡像里, 同時我的ubuntu里面安裝了一些基礎的網絡工具, 比如dig、curl、 ping等, 保存成鏡像ubuntu-base。
第二步, 根據Docker官方安裝文檔 我們在虛擬機環境里啟動兩個虛擬機, 構造一個Docker Swarm集群。
第三步, 創建一個Overlay網絡, 取名overlay-test。
下面我們試一下DNS輪訓模式的服務發現和負載均衡, 設置一個服務使用DNS輪詢還是VIP, 只要設置好endpoint-mode這個參數就好, 如下圖所示:
使用下面命令啟動我們的服務:
docker service create –network overlay-test –name demo –replicas=4 –endpoint-mode=dnsrr ubuntu-base
—network overlay-test是指定使用剛剛創建的Overlay網絡, –replicas=4 指定task數量, –endpoint-mode=dnsrr使用dnsrr方式做負載均衡。
啟動成功后如下圖所示:
當前機器上運行docker ps會發現有只有兩個容器生成, 原因是另外兩個task被調度到另外一台主機上。
下一步我們考慮進入容器中看一下虛擬出來的網絡情況。
我們之前明明指定了使用overlay-test網絡, 按理應該只有兩塊網卡, 實際上Docker卻為我們生成了4塊, 多出來的兩塊是Docker為容器做的手腳, 讓我來一一講解為什么會有4塊網卡的出現。
-
lo網卡不用多說, 是本地網卡, 也叫回環網卡;
-
eth2屬於之前創建的overlay-test網絡;
-
eth1和docker_gwbridge網橋構成的網絡可以使容器內的服務可以在主機上訪問, 主機上telnet 172.18.0.4可以訪問到我們的服務,如下圖:
-
eth0是ingress網絡中的一塊網卡, 是為了Routing Mesh而設,稍后我們會詳細說明。
繼續回到容器里面看我們查看一下服務情況, 執行命令:
大家會發現通過服務名或者容器ID都能找到IP地址, 區別是服務名發現了本機上所有提供服務的容器IP, 至此同時實現了服務發現和內部負載均衡。
以上就是通過DNS輪詢實現的服務發現和負載均衡, 這樣的負載均衡是有一些缺點的, 比如:
-
一些應用可能緩存DNS請求, 導致容器變化之后DNS不能實時更新;
-
DNS生效時間也導致不能實時反映服務變化情況;
-
由於以上原因導致的負載均衡不夠准確。
下面我來演示一下VIP和IPVS模式的服務發現和負載均衡。 VIP和IPVS原理上比較容易理解, 就是Docker為每個服務分配了一個VIP, DNS解析服務名稱或者自定義的別名到這個VIP上。
由於VIP本身沒有容器提供服務,Docker把到VIP的請求通過IPVS技術負載到后面的容器上。
Docker發布一個服務時候默認會選擇VIP模式, 下面我們用同樣的鏡像演示一下。
docker service create –network overlay-test –name demo –replicas=4 –endpoint-mode=vip —publish 8080:8080 ubuntu-base
啟動服務之后我們inspect一下, 會發現Virtual IPs有兩個入口, 期中10.0.0.2就是overlay-test網絡下面的一個Endpoint, 這個Endpoint是服務而非容器的。
我們進入容器中執行dig命令會發現:
此時DNS解析出來的是一個虛擬地址, 虛擬地址通過IPVS和一系列的iptables規則動態轉發到容器中。 這樣的負載均衡屏蔽了DNS輪詢的時效性問題,同時可以支持UDP等協議, 性能也非常好。 缺點是不能做比如回話保持, 基於URL等應用層協議的規則的轉發。
下面聊聊Routing Mesh, Routing Mesh的目的是每個主機上都為服務預留端口, 保證每台機器上都可以訪問到服務。實現的辦法就是Ingress網絡, 之前我們提到容器中會多出一塊網絡,我們Inspect ingress網絡,同時會發現網絡對應的容器上多出一個容器 ingress-sbox
一個請求到主機端口8080之后, 數據包的流向如下所示:
主機端口8080 => Ingress-sbox-VIP:8080 => 容器Ingress-sbox => IPVS分發到containers。
大家可以看到訪問主機之后數據包流到了一個特殊的Sandbox容器里, 這個容器和我們的容器共享一個Ingress網絡,通過Iptables和IPVS等重定向到了最終容器之上。 達到了服務在任何一台主機的8080端口都可達的目的。
已上就是我理解的Docker SwarmKit的幾種功能, 一些新的網絡技術大家也在討論,比如Macvlan和Ipvlan等, 通過這些技術Docker的應用場景越來越豐富, 越來越成熟, 讓我們拭目以待。
國內首個基於Docker SwarmKit的容器管理面板——數人雲Crane第一版最新出爐,歡迎點擊“閱讀原文”申請體驗,點贊or吐槽都可以。