閒談集羣管理模式

docker很火很紅,簡直到了沒有道理的地步了。docker爲何這麼紅?由於它是一種能夠用來掀桌子的技術。在部署自動化這條產業上的工人和機牀製造商們,看家護院的 cmdb,分佈式腳本執行等所謂核心技術即使不會變成明日黃花,也會淪爲二流技術。僅僅把 docker 當成一個輕量級 vmware 來使用,是無法看穿其實質的。要理解 docker 的意義,不能從 docker 是什麼,可以幹什麼提及。讓咱們先來回憶一下集羣管理模式的發展歷程,以及這些落後的模式的種種弊端。python

手工管理時代

IP地址是放在 excel 表裏的。管理是靠登錄跳板機,用 SSH 鏈接服務器。手工執行命令作新的服務器部署,已有服務器的程序版本升級,以及各類配置刷新修改的工做。
弊端不言而喻,主要有這麼幾點:git

  • 缺少一致性,由於是手工操做因此服務器之間老是有一些差別
  • 效率低下,一我的能夠管理的服務器數量很是有限

自動化大躍進時代

業務數量的增加,很快使得機器的數量超過手工操做維護的極限。不管再爛的團隊,只要業務長到這個份上了,必然會出現大量的自動化工具用腳本自動化執行的方式快速地支撐業務。這個時代是一個黃金時代,運維真正長臉的時代。由於沒有自動化的運維技術,業務就會遇到瓶頸。自動化技術的引入,切實地體現成了業務的收益。
這時代的特徵是兩個關鍵的系統github

  • 把本地 excel 表格裏的 IP 地址用數據庫的方式管理起來,稱之爲 CMDB
  • 基於 ssh 或者 agent 的分佈式腳本執行平臺

效率低下了再也不是主要問題,主要的弊端變爲了:docker

  • 大量的腳本,雜亂無章,內容重複,質量難以保證,最終給故障留下隱患
  • 沒有對現網預期狀態的定義和管理,全部的現網狀態都是腳本日積月累的產物,致使服務器狀態漂移,產生雪花服務器(每一個機器都不同),進而給業務穩定性留下隱患

這些弊端短時間對業務來講並無立竿見影的傷害,屬於內傷型的。並且不少隱患即使暴露了也會流於強調紀律,強調運維意識云云。不多會有人去追究背後的運維理念的問題。結果就是大部分公司都停留在這個階段了。畢竟運維是一個足夠用便可的支撐領域。運維搞得再高科技,特高可用,未必和創業公司的成功有多少直接聯繫。數據庫

開發鬧革命時代

伴隨 devops 同時出現的是 infrastructure as code 的提法。簡單來講就是一幫開發殺到運維領域以後,看見這些運維竟然是這樣去管理現網狀態的。因而他們把寫代碼的經驗帶過來,將現網狀態創建成模型(所謂 code),把預期的狀態提交到版本控制中。就像寫代碼同樣,去管理服務器配置。
不少後臺開發主導的小創業公司直接跳過了上個時代,運維自動化體系從一開始就是基於 puppet 和 chef 來搞的。平心而論,用 puppet 的更可能是缺乏歷史包袱,而不是由於運維問題有多複雜。不少管理的機器數量不超過十臺,卻在如何使用 puppet/chef 上浪費大把時間的團隊也是有的。相反不少大公司由於有沉重的歷史包袱,和龐大的傳統運維團隊,這種開發鬧革命的路反而走不通。
這種作法主要是解決了腳本的管理問題,並且由於直接定義了現網狀態,服務器之間的一致性也會好不少。可是光鮮亮麗的模型背後本質上仍是一堆腳原本驅動的。上個時代的弊端只是通過了包裝和改良,並無辦法根除後端

  • 應用預期狀態到現網依靠的仍是跑腳本。並且與以前不一樣,如今更多的是跑別人寫的cookbook了,質量也是參差不齊的
  • 雖然定義了預期的現網狀態,可是起點不一樣(好比從a=>c, b=>c)須要作的升級操做可能徹底是不一樣的。要編寫一個面面俱到的升級腳本其實很是困難。

還有哪些問題?

一致性和穩定性是最大的問題。服務器開機以後,常年是不重裝系統的。無數人在上面跑過腳本,執行過命令,定位過問題。服務器實際的狀態是沒有辦法精確管控的。infrastructure as code 是一種改良,可是仍未根除這個問題。每一次在服務器上跑腳本其實就是一種賭博,由於沒有兩臺服務器是徹底同樣的。在本地測試可行的腳本,未必在另一臺上不會引發問題。這不是強調一下代碼裏不能 rm * ,而要 rm path/* 就能夠解決的問題。ruby

版本管理其實一直是沒有的。作過開發的人,可能還會用 git/svn 來做爲部署的基線,基本的版本都會提交到倉庫裏。更多的一線運維用的仍是 rsync 的模式。rsync 的意思就是要安裝一個新服務器,須要找一臺「與之最像」的服務器。而後把文件拷貝到新服務器上,把配置修改一下,啓動完事。攜程出事了,我我的猜想應該與版本管理混亂有關係。服務器

故障替換是很是困難的。先不說故障替換,就是故障機剔除就是一個頭疼的事情。好比 zookeeper。各個客戶端都硬編碼三個 ip 地址。一旦其中一個 ip 掛掉了。zookeepr按照高可用協議能夠保持正常,可是長期來講這個掛掉的ip仍是要從各個使用方里剔除的。這個就且改了。一旦業務的高可用作得很差,須要運維來搞一些接告警以後替換故障機的事情,那就是各類腳本折騰各類配置文件的節奏了。網絡

Docker 是如何掀桌子的

兩點神論,進入到 Docker 時代以後app

  • CMDB 再也不相當重要了。CMDB 連同IP,以及服務器資源變成底層藍領工人關心的問題了。上層的後臺開發和業務運維再也不須要也沒法再以 IP 爲中心的 CMDB 來管理配置。
  • 分佈式腳本執行平臺從核心做業系統退居二線。很簡單,服務器再也不須要變動了,常規的上新服務器,發佈新版本都再也不依賴腳本在一個已有的服務器上執行去修改狀態。而是建立一個新的容器。

Docker的實質是一個真正的版本管理工具。在 Docker 以前版本管理是各類拼湊的解決方案。什麼是版本,服務器是由三部分組成:版本、配置、數據。所謂版本就是操做系統,以及操做系統的配置。各類第三方包,開發給的可執行文件,和一部分配置文件。這些的集合是一個版本,其實就是一個完整的可執行環境。除此以外通常就是一個數據庫,裏面放了兩部份內容,一部分是管理員能夠從頁面上修改的配置,一部分是業務數據。在 puppet 時代的版本,是一個申明文件。這個申明文件執行的時候,須要先從某個 ISO 安裝出一個操做系統,而後用 apt-get/yum 從某個鏡像源安裝一堆系統的包,而後用 pip/bundle 安裝一堆 python/ruby 語言層面的包,最後纔是開發給你的 git/svn/某個不知名的tar.gz。你覺得這些東西每次拼裝出來的東西都是一樣的版本麼?其實未必。想當年某牆幹掉 github 的時候,不知道多少人沒法作發佈了。Docker 打包出的連繫統在一塊兒的鏡像,實際上是對版本的最好闡述。

使用 Docker 以後再也不須要修改現網的 container 了。一個 container 若是須要升級,那麼就把它幹掉,再把預先作好的新的鏡像發佈成一個新的 container 替換上去。分佈式腳本執行,變成了分佈式容器替換了。固然這種標準化的操做,用 mesos + marathon 已經完美解決了。

使用 Docker 以後,沒法再基於 IP 作管理了。倒不是給每一個 container 分配一個 IP 分配不過來,而是 IP 表明的靜態模型沒法跟上時代了。基於 IP 管理,就意味你會基於 SSH 登錄這個 IP 來管理。這種思想從骨子裏就是落後的了。進程,進程組,模塊,set 這些纔是管理的粒度。至於進程是跑在哪一個 IP 上的哪一個容器裏,再也不重要了。一圖能夠說明這個問題;

圖片描述

上面這個擴容的按鈕點完以後有讓你填 IP 嗎?沒有!你只須要告訴marathon,我要32個進程實例。它就會去找這些資源運行這 32 個實例。業務最終須要的是 32 個進程,而不是 32 個 IP。IP只是運行進程須要的資源而已。實際運行的時候進程多是在一個IP上啓動了32個端口,也多是隨機分配了5個IP,每一個各跑了一些端口。固然這些分配都是能夠經過「約束」的方式表達的。而不是讓你去搞32個IP來,再跑個腳本去這些IP上部署這些進程。

The Missing Piece

拼圖遊戲就差最後這一塊了。Docker 作爲一個版本工具是絕對合格的。Marathon 以 Docker 的方式託管全部進程也是靠譜的。可是還不完整:

  • Docker鏡像做爲版本發佈到現網以後是沒法運行的,由於任何一個應用起碼都有好幾個服務要互相訪問。這些硬編碼在鏡像裏的 IP 地址換了一個環境是沒法執行的。一個版本里任何配置均可以硬編碼,就是 IP 地址和端口是沒硬編碼的。
  • 擴容縮容能夠很容易建立和銷燬容器,可是引用了這個容器的服務器的其餘容器怎麼辦呢?
  • 發佈,故障替換都是一樣的問題

解決方案能夠看這兩張圖:

2-a0a81433f4c5a22bea25e1d66cc49333.png

3-7e1229ab3f99757bd2c598a2164602d0.png

方案其實很是簡單。把 app1 => app2 的網絡訪問關係,改爲 app1 =local=> haproxy =network=> haproxy =local=> app2。經過在容器本地部署 haproxy 「託管全部的端口」,也就是用 haproxy 在進程之間作聯線,而不是每一個進程本身去負責鏈接網絡上的其餘進程。

試想一下以前是在配置文件裏硬編碼 10.0.0.1:3306 是某臺數據庫。硬編碼是不對的,是要打屁股的。因此咱們把硬編碼的 ip 地址改爲 127.0.0.1:10010。這一次咱們再也不硬編碼任何 IP 了,咱們只硬編碼一個特殊的端口號。每一個進程都有一堆特殊的本地端口號用於訪問本身須要的上下游服務。這個端口號背後的進程到底在哪一個 IP,哪一個 端口,哪一個 container 裏執行。作爲使用方不須要修改任何代碼(好比兼容什麼 zookeeper/etcd 神馬的),也不用關心。甚至這個端口後面是多個遠程的IP構成一個基於客戶端的高可用。代理甚至還能夠作一些出錯換一個後端再重試的事情。

有了這種神器以後,擴容所容,發佈變動,故障替換都很輕鬆了。容器隨便新增,隨便刪除。網絡結構變化了以後,刷新各個地方的 haproxy 配置就是了。各類灰度,各類零停機替換方案均可以搞起。

名字服務與網絡

相似的方案有不少。最底層的方案是 SDN/IP 漂移,以及網絡的bonding。這種方案的特色是保持 IP 地址做爲最傳統的名字服務,妄圖延續其生命。
上層一點的方案是 DNS。再上層一些的方案是 Zookeeper。
各類方案爭的就是服務如何註冊本身,如何彼此發現這個點。各類方案的優缺點能夠本身去讀:

http://nerds.airbnb.com/smartstack-service-discovery-cloud/
https://blog.docker.com/tag/smartstack/

btw,airbnb 在 13 年就把這套方案投入生產了。

最有意思的是把這種 haproxy 的方案與基於 SDN 的 IP 漂移方案作對比。haproxy 的就是替網絡作應用層進程之間聯線的事情,經過引入 haproxy 讓這種聯線更具備靈活性。 而 SDN 的方案是說,你如今的業務進程之間是經過 IP 之間靜態連接的,這種鏈接不夠靈活不要緊,路由器幫你整。一個 IP 掛掉了,能夠把IP漂移到另一臺機器上去繼續使用。其實就是在一個場景下實現兩個進程的從新聯線,突破兩 IP 之間靜態互訪的限制,給基於 IP 的部署方案續命。

二者底層的技術是相通的。所謂 IP 漂移最後靠的是現代牛逼的CPU,和軟件路由技術。最後玩的都是用戶態轉發,dpdk神馬的。因此 haproxy 慢,轉發效率有問題神馬的,長期來看都不會是問題。用軟件來聯線,是趨勢。連路由器都開始這麼玩了,連硬件廠商都開始賣軟件了。

The Final Battle

集羣管理純粹變成進程管理,IP再也不重要,狀態再也不重要。CMDB會變得愈來愈邊緣化。 發佈變動再也不是去修改服務器,而是新建銷燬容器,以及更新進程間網絡聯線關係。分佈式做業系統會愈來愈少用,跳板機就更加不容許使用了。 記住「immutable servers」這個提法吧,它終將會獲得歷史的承認。

相關文章
相關標籤/搜索