當我們談論不可變基礎設施時,我們在談論什么
作者 | 陳海波(漂石)
午夜時分,電話響起,線上告急。你從千呼萬釘中醒來,睡眼朦朧,手忙腳亂。恍惚之間,終于梳理清楚發生了什么,一個陳年老應用突然停機,消息堆積,系統停擺。而你就像一個下水道小工疏通馬桶一般,大力出奇跡,重啟機器,恢復服務。只見消息隊列中的堆積事件一瀉千里,警告消除。次日,你再也不想重現午夜兇鈴,決定對系統進行永久性修復:加一個定時重啟服務的腳本。斗轉星移,許多時日過去了,你也在不同的角落加了無數的腳本,也好久沒有半夜驚醒,甚至還能悠閑享受下午茶。但是,直到今天。今天,你們部門要降本增效,為了避免自己成為被砍掉的成本,你決定主動對線上的機器開刀:合并服務,裁撤機器。雖然你對機器上都部署了什么應用了然于胸,但是你已經不記得都有哪些腳手架支撐著應用的運轉。重建環境難如登天,你又開始難眠了。
一、變化的基礎設施
復雜、神秘而神奇的線上環境承載了半部都市傳說,甚至有些公司的線上環境本身就是一本需要口耳相傳的上古神話。我雖然沒有看過沙漠下暴雨,但是看過沒人說的清楚上面有什么的環境。我雖然沒有看過大海親吻鯊魚,但是我看過重啟再也起不來的機器。如果你能說清楚任何一臺機器上都部署了什么應用,以及機器上服務之間的依賴關系是什么樣子的,你已經擊敗了八成的玩家。而造成這種局面的根本原因就是基礎設施的易變。
- 新增一個服務時:“我找臺機器部署一下”
- 某一個服務出問題時:“我上機器改一下”
- 需要對某個系統配置變更時:“我搞個腳本跑一跑”
看似常規運維變更,有文檔記錄或者沒有文檔記錄,每一個環境都是如此的別致和獨一無二,再加上人員變動,造就了無數的“祖傳秘技”。
1.什么是不可變的基礎設施
容器在被廣泛接受的同時,「不可變」也逐漸被潛移默化的接受。應用容器消亡之后,容器內的修改會隨著容器一起不復存在,不要在容器內做修改就是最樸素的不可變理念。在程序啟動階段遇到問題,很少人還會把在容器內修修補補作為正經方案,而會回到最一開始的階段,從容器構建階段解決問題。隨之帶來的就是大家對容器鏡像無盡的信任感,容器突然出現問題?重建試試。換個機器跑不起來?肯定是機器的問題。
2.容器帶來了什么
大家普遍認同 Docker 或者說容器引發了一場革命。但是為何說容器是一場革命,到底革了什么的命?有一種說法是 Docker 簡化了服務的管理,停啟服務更加簡單,但是事實上 systemd 或者 supervisor 等老牌服務管理、運維工具在這一點上不見得比 docker 難用多少。我認為是鏡像技術引爆了革命,一個不可臨時修改的、固化的、自包含的交付物,真正的一次構建到處運行,一個可以快速鏟掉和快速部署的實體,再也沒有 「Works on my machine」,是如此的安心和可依賴。也正是因為容器的重建是如此的快捷,使得我們有機會對「重啟試試」發揮到極致,出問題了,重建容器看看?你想嘗試使用 Docker,但是你的業務如此復雜,上機器重建容器和直接上機器重啟服務又有什么本質差別呢。
二、Pet vs Cattle
隨之 Kubernetes 的到來,大規模的容器管理成為可能,而劃定大規模容器的管理最佳實踐也成為了熱門議題。
1.如何飼養一只貓
如果你得到了一只貓,你會如何飼養它?我記得我在領回一只貓之后,花了很長的時間和腦細胞用來商定一個我和它都能接受的名字。緊接著就是帶著我的小貓去醫院,制定疫苗計劃,來保證我的小貓未來的健康。后面便是日復一日的鏟屎和等著主子的眷顧。小王子告訴我:正因為你為你的貓花費了時間,這才使你的貓如此重要。經典的運維方式和貓的飼養是一樣的,我們可以稱之為寵物式運維。你會對機器和應用做詳盡的規劃,甚至為這個環境起一個名字,比如叫生產好了。你也會對這個環境悉心照料,定期看看監控、做下升級保養。你為你的環境花費了時間,你的環境如此重要。很難設想你的貓和你的環境突然間離你而去的場景,也許你會傷心的撕心裂肺和破產的撕心裂肺。
2.農場主入門
在獲得了一只貓之后,你一不留神又獲得了一家牧場。但你可能無法像養一只貓一樣養幾千頭牛,因為幾千個名字應該是很難記住的。
你可能也不會依次帶著你的牛去醫院打疫苗,何不直接批發疫苗統一接種呢。如果有小牛犢存在嚴重的缺陷,也許你會陪在它身邊悉心照料,但更可能的是把它盡早的從流程中剔除,省的浪費更多的飼料。從此你的生活便目無全牛,只要為牛群建立足夠多的保障設施,某一頭牛的狀態對整體又有什么影響呢。03
三、放牧式運維
當你已經為上千頭牛建設了完善的飼養設施,你會驚奇的發現,即使再加 100 頭牛,并不會增加太多的成本。而不像飼養貓,當你有兩只貓的時候,最好能有 3 個貓砂盆,否則你將有機會體驗到雞飛狗跳。你決心當一個牧牛人運維,再也不想給生產環境的主子們鏟屎了。擁抱 Kubernetes,像放牧一樣管理你的應用。
1.牧養一群 Pod
你把生產環境的主子們裝進集裝箱,通過容器鏡像對部署方式進行標準化,誰也甭想做非標的操作,再使用 Pod 對應用進行部署,再也不去關心應用在哪個 Node 上啟動,這一切自有牧場(Kubernetes)自行處理。一個 Pod 異常了?沒關系,刪掉看看,下次起來又是一個全新的應用。絲毫不會影響到牧場的正常運轉。
一切絲般順滑,歲月靜好。午夜時分,電話響起,線上告急。你從千呼萬釘中醒來,睡眼朦朧,手忙腳亂。
恍惚之間,終于梳理清楚發生了什么,原來是不知何處流量涌現,節點雪崩。而你就像一個下水道小工疏通馬桶一般,大力出奇跡,擴容機器,恢復服務。pending Pod 消失不見,警告消除。次日,你再也不想重現午夜兇鈴,但陷入深思,身為牧場主的你,逐漸意識到一個燈下黑的問題。你可以輕松的同質化對待每一頭牛,但你無法同質化整個牧場。
2.牧養真正的基礎設施
幾番梳理,你找到了問題的關鍵:盡管可以放牧式管理 Pod,但是機器的運維卻還是寵物式的。你依然會悉心照料每個機器:提前規劃、取一個名字、單獨控制規格、挑選操作系統,甚至還有幾臺深得你愛,噓寒問暖,日夜牽掛,擁有單獨的內部昵稱代號。作為業界領先的牧場主,你決心改造自己的牧場,如果能像管理 Pod 一樣管理 Node 是不是一個好主意?如果 Node 異常直接刪除 Node,等著彈出新的?還沒想完,你后背有些發涼,你還沒有像信任容器一樣信任虛機,雖然你深知重啟可解決 90% 的故障,而重裝系統可以解決 99% 的故障。思來想去,你依然想做些嘗試,稍加思考,鎖定痛點有二:
- 機器按需快速彈縮,同質管理
- OS 鏡像化:快速、安全、不可變
3.馴服虛機
經過調研,你發現事情并不像原來設想的那樣深不可測,主流云廠商早就提供了野生工具,你只需要稍加馴服,便可以為自己的牧場服務。云廠商們很早便推出了彈性伸縮組,可以按照負載和期望維護虛擬機的數目。而阿里云也有自己的實現(ESS),可以無需人工干預的根據規則對 ECS 進行擴縮容。你看到了希望,這不就是 Node 的 Deployment 嗎?但是只是擴容虛擬機對你來說并沒有什么價值,你深知需要的是牛圈,而不是木材,你需要對他們進行馴服。這時,你轉頭看到了你的 Kubernetes 集群,靈感蹦出,為何要直面虛擬機呢,只要新擴容出的機器能被納管到集群中不就解決了基本問題。說干就干,通過 AutoScaling 定義了啟動命令,開機后進行標準化安裝和執行 kube join 動作。當機器開機不久,就可以出現在 Kubernetes 集群中。你感覺距離目標進了一步。
4.馴服 OS
很快,你又發現了一個新的問題,傳統的 OS 啟動和容器實在無法比擬,明明所有的依賴都在容器內部,而且所有的應用都已經在容器內運行,但你還是不得不為 OS 內置的、沒人使用的服務買單,這些服務拖慢了啟動速度,還引入了安全漏洞。而且,總是有人意識不到同質化管理的好處,時不時有人上機器做一些不可知的修改,導致你每次想釋放虛機時需要去群里喊一喊,避免碰到什么神奇的 Bug。自尋煩惱,你苦笑道。你打算馴服 OS,對傳統的 OS 進行剪裁,除了容器依賴的東西全部清理掉,說不好能大大加快機器的啟動速度。還有,最好能在啥地方加個告示,敬告大家不要在機器上做寫操作,避免釋放機器時文件的丟失。有天,你發現了阿里云的 ContainerOS,一個針對容器剪裁和優化的操作系統,你不需要親自動手剪裁了,甚至都不再需要加一個告示,因為 RootFS 都是只讀的,連 SSH 都不會默認打開,從根本上杜絕了非標操作。
你嘗試了一下,針對容器優化的 OS 啟動賊快,點完彈出,一分鐘后你就可以把業務調度上去了。把 Node 當做 Pod 管理,你看到了希望。
四、托管式放牧
但不久,你遇到了一個新的問題,創建機器一時爽,你的老板告訴你,你手里有一批機器存在一個要緊的 CVE 安全漏洞,需要抓緊時間搞一搞,你開始頭大了,因為你知道,除了存量的節點,現在只要創建新的機器就有安全漏洞。你有了一種若隱若現的感覺:你在走向深水區。
一番探尋后,你聽說有人提出應該像自動駕駛一樣去托管一個集群,也看到了阿里云 ACK 的托管節點池。節點的擴縮容、節點故障的自恢復、安全加固、OS 的托管,無不觸動著你。你意識到應該從根本上解決問題:放手自建的 Kubernetes,全面擁抱托管。
擁抱托管后,你豁然開朗,原來事情本應如此簡單,多年的摸索仿佛一顆種子,在看到托管節點池后瞬間發芽成果。從此,世界上又開始流傳了新三板斧傳統:等等自愈看看?Pod 刪下看看?Node 刪下看看?樸實無華且有效。