Mesos/Marathon 折騰久了,咱們一直但願有機會深刻到 Swarm 內部一探究竟。 另外, Mesos 這一套東西雖然是久經企業級考驗的, 可是安裝、部署和使用相對複雜,上手有門檻。同時,在今年的 DockerCon 上,內置了Swarm 功能的 Docker 1.12 發佈。基於以上背景,數人云計劃圍繞 Docker 1.12 Swarm 開發一版輕量級的集羣管理工具,也藉此與 Mesos/Marathon 對比下。目前,咱們初版數人云容器管理面板 Crane 已經開發完畢,過程也是磕磕絆絆,這裏趁機總結幾篇技術分享。node
正文開始前先八卦一下,關注 Docker 技術的小夥伴們應該清楚 Docker 1.12 的 Swarm mode 頗受爭議:首先是有人認爲 Docker 公司 Market Drive Develop,違背了 Linux 信徒恪守的哲學——一個工具只幹一件事情;其次, 有人認爲 Swarm mode 的功能不及 Mesos 和 K8S,還不適合生產環境使用,這一點我倒認爲穩定性而不是功能纔是 Swarm 目前不適合生產環境的緣由;最後, Docker 的向後兼容性不足也引來口水無數,畢竟 Docker 還在 active develop。其它的像容器網絡標準的爭議, Runc 的爭議這些都把 Docker 推到了風口浪尖。固然,不辯不明,相信 Docker 給咱們提供的不止眼前這些。mysql
咱們首先從應用編排( Application Stack)談起,應用編排是 Docker 1.12 引入的概念,目前仍是 experimental 的功能,必須得安裝 experimental 的包才能夠嘗試。除去編排 (stack), Docker 1.12 還引入了服務 (service) 和任務 (task) 的概念, Docker 藉此從新闡述了應用與容器 (container) 之間的關係。上述幾個概念的關係以下圖所示:
(圖片來自網絡)git
即:一個應用編排表明一組有依賴關係的服務,服務之間能夠相互發現(後面詳細介紹),每一個服務由多個任務組成,任務的數量能夠擴縮 (scale),而任務則物化爲一個具體的 Docker 容器及其配置。github
Docker 經過擴展名爲 dab( Distributed application bundles) 的文件來描述一個應用編排,下圖是一個帶有兩個服務的 dab 文件例子:sql
這裏有dab文件的詳細介紹:
https://github.com/docker/doc...docker
其中 Image 這裏推薦使用 image@digest 而不是 image:tag,緣由是爲了不這種狀況 : 在集羣中部署服務時, image:tag 沒法保證鏡像是全局一致的,本地的 image:tag 可能與鏡像倉庫裏面的 image:tag 數據不一致,這個問題在跨機環境中被放大。而 image@digest 這種方式經過中心化倉庫設置全局惟一的 digest 值,避免了上述問題。安全
除此以外,還有下述幾個關鍵特性值得分享:網絡
滾動更新:服務的鏡像更新是一個基本訴求。 Docker 能夠經過關鍵詞 update-parallelism 和 update-delay 來控制並行更新的頻率。 Marathon 也提供了相似的功能。這個特性很關鍵,若是沒法控制更新頻率,成百上千的鏡像拉取和任務調度會致使嚴重的資源波峯。 Docker 文檔還聲稱支持更新失敗回滾,嘗試了下,目前沒發現怎麼玩,還沒來得及看底層代碼。架構
服務模式 (service mode): Docker 1.12 提供了兩種方式控制任務數量—— replicated 和 global,在 replicated 方式下,咱們須要提供指望的任務數量, Swarm 將一直嘗試維護這個任務數;而在 global 方式下, Swarm 嘗試在每一個節點上啓動一個任務,這種方式特別適合向每一個節點下發 agent 的場景。app
stop-grace-period 參數:在服務縮容時,咱們比較關心容器被強制 kill 而帶來的事務 (transaction) 問題,配合該參數 stop-grace-period( 強制殺死容器前的等待時間 ) 和容器內部的退出信號監聽,能夠達到容忍程序友好退出和快速回收資源之間的平衡。 Mesos / Marathon 也採用了相似的策略來解決這個問題。
with-registry-auth 參數:在服務建立時,該參數聲明將管理節點 (Swarm manager) 上的 registry authentication 信息帶到工做節點 (worker node) 上,從而爲工做節點提供從 registry 拉取鏡像的認證信息。在 Docker 的非 Swarm 場景下, Docker-client 負責 registry 認證信息的管理,但在 Swarm 方式下,再也不是 Docker-client 觸發鏡像拉取動做,因此服務沒法使用工做節點本地的 registry 認證信息了,必需要經過上述方式從管理節點分發認證信息。同時節點間的加密通訊也保證了認證信息傳輸的安全性。
任務的生命週期:在容器的生命週期之上, Docker 1.12 引入了任務 (task) 的生命週期。某任務下的容器異常退出時,帶有一樣任務編號 (slot) 的新容器將會被嘗試啓動。不一樣於容器的生命週期只囿於一臺固定主機上,任務的生命週期是與主機無關的,咱們能夠依此對容器的日誌進行聚合獲得任務的日誌。這一點正好是 Mesos / Marathon 所欠缺的。
重啓策略:Docker 1.12 提供了三種重啓條件 -any, none, on-failure,其中 none 指的是退出不重啓,on-failure 指的是失敗( exit code 不是零)時重啓,而 any 指的是不管任務正常或是異常退出,都重啓。any 方式配合參數重啓間隔 (restart-delay) 能夠知足定時任務的場景; none 方式則能夠知足批處理任務場景。另外參數評估間隔 (restart-window) +參數嘗試次數 (restart-max-attempts) 能夠控制在一段時間內的任務重啓次數,避免異常任務頻繁重啓帶來的集羣資源失控。
固然,Swarm mode 還有不少問題亟待解決:
dab 文件的表達能力有限:當前版本的 dab 文件只有寥寥數個關鍵詞,服務 (service) 建立的諸多參數 dab 都沒法支持。在咱們的實踐中,爲了解決這個問題, team 不得不二次開發引入服務的其它參數,以期對服務的參數全量支持。
容器回收問題:按照目前的設計,只要服務 (service) 還在,退出的容器是不會被自動回收掉的,在某些場景下,這會致使集羣失控,各主機的文件描述符被耗盡。
容器的健康檢查 (healthcheck): 在我看來,這是 Swarm mode 以外, Docker 1.12 引入的最關鍵功能,有了 healthcheck 這個 feature,咱們能夠將業務內部真正的健康情況暴露出來了。這個功能落後於 Marathon 足足一年的時間。但惋惜的是,服務( service)建立目前還不支持這個關鍵詞,這就限制了服務 (service) 異常重啓的能力,從而間接下降了服務容錯能力。這一點 Marathon 作的特別好。
資源控制: 1.12 目前支持單個任務 CPU / mem 的資源控制。還沒法像 Mesos 那樣,自由的配置管理磁盤, GPU,端口等資源。
沒法使用主機網絡:經過服務( service)啓動的容器是沒法使用主機網絡的 (network host is not eligible for Docker services),但同時按照網絡上 Percona 提供的壓測結果, overlay 網絡相較於主機網絡有 60% 的性能損耗。這嚴重侷限了 Swarm 的應用場景,咱們能夠認爲這是編排功能帶來的架構反作用。而 Mesos 從資源維度管理集羣很好的規避了這個問題。
接下來讓咱們看看下一層:Docker 是怎樣在 stack, service, task container 之間創建聯繫的?同一個 stack 內的 service 又是如何相互發現的?
第一個問題很好回答, service label 和 container name, Docker 經過在 service 上添加 label: com.Docker.stack.namespace=XXX 來標示這個 service 屬於哪個 stack。咱們能夠 inspect 一個 service 看下:
Docker 經過特定格式的 container name 標示這個 container 隸屬於哪個 service 下面,以下圖所示:
容器名稱 merryfox_mysql.1.by842qrj7xhsne93yzfpjp367 表明該容器是服務 merryfox_mysql 的任務 1 的容器。Docker 在不少地方使用了這種技巧來處理數據。而第二個問題就引出了咱們下面的——服務發現。
在談服務發現以前,咱們簡單討論下 Docker overlay 網絡的性能問題,根據 https://www.percona.com/blog/... 的網絡壓測結果,相較於 host 網絡, overlay 有 60% 的網絡性能損耗,問題主要出在多 CPU 下網絡負載不均。同時容器沒法在 Swarm 編排模式下使用 host 網絡,這帶來的問題就是:在 Docker 1.12 Swarm mode 下網絡性能損耗沒法避免。
與 Marathon / Mesos 的 Mesos-DNS、 bamboo 相似, Swarm 的服務發現也分爲內部服務發現 (internal service discovery) 與外部服務發現 (ingress service discovery),這兩種服務發現使用了不一樣的技術。
若是想讓一個服務暴露到集羣以外,咱們須要藉助 service create 的參數 publish,該參數顯式的聲明將集羣特定端口 PORT_N(集羣端口 PORT_N 表明集羣中全部主機的端口 PORT_N)分配給這個服務。這樣不管該服務的容器運行在哪臺主機上,咱們均可以經過集羣中任何主機的 PORT_N 端口訪問這個服務了。下圖能夠形象的描述這個場景:
接下來,咱們就能夠把集羣中部分或全部主機的 IP 加上述端口配置到咱們的前置負載均衡器上對公網提供服務了。通常稱這種分佈式的負載均衡策略爲 routing mesh,在 Calico 網絡方案中也提到了相似的概念。因爲沒有了中心化的負載均衡器,集羣不會因某臺機器異常而致使整個服務對外不可用,很好的避免了單點問題,同時也帶了可擴展性。關於routing mesh這個概念的詳細介紹能夠參考該連接(https://en.wikipedia.org/wiki...。
這裏摘抄一個簡短解釋:
A mesh network is a network topology in which each node relays data for the network. All mesh nodes cooperate in the distribution of data in the network.
上述就是 Swarm 的外部負載均衡(也能夠稱爲routing mesh),那麼 Docker 在底層作了什麼來實現上述功能的呢?以下圖所示:
在 Swarm 集羣初始化時, Docker 會建立一個 overlay 網絡 ingress,同時在每一個節點上建立與 ingress 關聯的 sandbox 網絡命名空間,這樣集羣中的每一個主機都變爲了 ingress 網絡的一部分;
當咱們建立 service 申請一個 publish port 時, Docker 會經過 Iptables rules 創建 主機 IP:Port 到 sandbox IP:Port 間的映射,即 : 將對應端口的包轉發給 ingress 網絡;
同時在 sandbox 網絡命名空間內, Docker 經過 Iptables rules + IPVS 控制對應 端口/ Port 的包負載均衡到不一樣的容器。這裏 IPVS(IP virtual server) 的功能與 HAproxy 相似,承擔着 Swarm 集羣內部的負載均衡工做。
對於只供集羣內部訪問的服務,無需使用上述 routing mesh,Swarm 還提供了一套內部服務發現 + 負載均衡。以下圖所示(這裏咱們只討論基於 VIP 的負載均衡方法):
manager 會爲該 service 分配一個 VIP(Virtual IP),並在內部 DNS 上創建一條 VIP 與 service name 的映射記錄。注意這裏的 DNS server 也是分佈式的,每個主機上都有一個 DNS server ;
Iptables 配合 IPVS 將 VIP 請求負載到 service 下面的一個具體容器上。
另外,主機間 routing mesh,load balancing rule 等信息是利用gossip協議進行數據同步的,限於篇幅,這裏再也不深究這個問題。
最後友情提示幾個雷區:
Q1:爲何個人機器沒法加入 (join) 到 Swarm 集羣中?終端報錯:加入集羣超時。
A1:這個問題極有多是主機間時鐘不一樣步致使的,建議開啓 ntp 服務,同步主機時間。
Q2:爲何我在 manager A 上經過命令 Docker network create 的 overlay 網絡沒法在集羣另外的機器 B 上經過 Docker network ls 發現?
A2: 這有多是正常的。按 Swarm 當前的設計,只有使用相應網絡的容器被調度到了機器 B 上, overlay 網絡信息纔會更新到機器 B 上去。
Q3: 爲何個人服務的 publish port 在有些機器上不生效?我使用 netstat – lnp 方式看不到端口監聽。
A3: 與問題 1 同樣,這也多是時鐘不一樣步致使的問題。
參考連接:
http://collabnix.com/archives...
https://sreeninet.wordpress.c...