滴滴彈性云:從物理機到Kubernetes的那些坑與心得
今天我將帶來一些關于滴滴彈性云的分享,內容是從物理機到 Kubernetes 的那些坑與心得。
先簡單自我介紹下,我叫譚霖,之前在 Intel 從事 OpenStack 相關的工作,也花了很大精力在開源社區這方面。
后來我來到滴滴的彈性云團隊,主要從事基于 Kubernetes 的基礎平臺建設,可以說是從一個做菜的“廚師”變成了一個“食客”。
今天的分享主要分為四個部分:
- 整體架構
- 產品功能
- 方案細節
- 心得展望
在我們準備做彈性云時,我們問了自己三個問題:
- 為什么要做私有云
- 為什么選容器
- 為什么選 Kubernetes
為什么要做私有云?因為滴滴的集群規模太大,有數萬臺物理機(這樣的規模量要求我們做一個私有云平臺),結果因為之前沒有一個比較好的方案,造成了資源使用率特別低、資源浪費大的問題。
另一個主要原因是滴滴的發展太快,總有新的業務,隔一段時間就聽說成立了一個新的部門,而且隨著新需求的出現,更新迭代異常頻繁,這些都對平臺的穩定性提出了特別高的要求。
這個問題靠堆人是解決不了的,所以需要有一個好的平臺和機制來解決它。
為什么選容器?KVM / Xen 這樣的傳統虛擬化已經出現多年了,很穩定,但大家也知道其弊端,就是損耗比較大。
另外,傳統混部也就是滴滴現在在用的方案(即繼續保持原有的傳統混部),雖然能夠部分解決資源使用率低的問題,但因為完全沒有隔離,導致程序之間容易互相影響。
而容器是一個相對折中的方案,具有一定的隔離性、損耗更少,這是我們選擇它的最主要原因。
同時,更重要的是容器的鏡像所帶來的新玩法,因為鏡像的環境是一致的,對運維人員特別友好。
因此他們不用再關心那些紛繁復雜的配置文件,也不用頻繁地走初始化流程,更不用每次上線更新都提心吊膽,擔心會對新的服務造成影響。
為什么要選擇 Kubernetes?大家都知道現在比較著名的容器平臺有 Mesos、Kubernetes 和 Swarm。
一年前我們在 Mesos 和 Kubernetes 之間猶豫過很久,后來主要覺得我們要做的是一個基于容器的平臺,相比較 Mesos,Kubernetes 更專注容器。
而 Swarm 當時還很年輕,很多功能不夠完善,相較之下 Kubernetes 更成熟。當然更關鍵的原因是 Kubernetes 的社區更有活力,設計架構也更清晰,可拓展性也高。
現在回過頭來看一年前的選擇,非常慶幸我們做了正確的選擇,因為之前相較于兩者,Kubernetes 還只是旗鼓相當,而現在則有一統江山的趨勢。
我們目前還是基于 Kubernetes 1.6 版本做的改造,接下來 1.8 版本 release 之后,我們會盡量跟上,保持和社區同步。
整體架構
項目介紹
滴滴彈性云的目標就是基于容器技術,為滴滴提供穩定高效、可伸縮的服務管理平臺。
先簡單看看彈性云的項目歷程:
- 2016 年 7 月,彈性云項目正式啟動,然后 10 月份出了***版。
- 2017 年 4 月,發布了第二版。在幾個月的使用體驗中,我們根據用戶的反饋,不管是產品形式還是底層網絡方案都經過大規模優化。
- 目前第三版也正在開發中,這一版會更側重在用戶交互和可視化上。
截止到目前為止,我們總共有 300 多臺宿主機,2000+ 的容器實例,這不算很多,但目前有多條滴滴核心業務線跑在我們的平臺上,預見 2018 年規模會有指數型的上升。
整體目標
為了解決先前提出的三個問題,我們的整體目標有四點:
- 實現資源按需分配,提高資源利用率
- 實現資源的彈性伸縮,可以快速響應負載變化
- 基礎環境保持一致,實現服務的快速交付
- 保證服務的容錯性,實現基礎設施免運維
解決方案
針對不同的產品線和需求,我們具體落地的產品解決方案主要分為兩大塊:
- 基于容器構建的輕量級虛擬機,叫做靜態容器組。
- 更純粹的微服務類容器,我們稱之為彈性伸縮組。同時我們還整合了滴滴現有的部署監控和日志收集系統。
如上圖,是整體架構,中間***的一塊就是我們的 K8S 集群,它主要分成控制節點和工作節點兩部分。
上面一塊是我們的控制臺和管理員入口,左邊是滴滴的一些現有的權限認證系統和服務樹,右邊是我們的網絡方案。
所以按照流程我們主要做的操作是用戶先通過權限系統認證后,創建服務(也就是 K8S 的實例),實現容器的擴容縮容和部署更新。
之后我們平臺就會進行實時監控和日志收集,完成監控數據的上報和鏡像拉取。
剛才說的主要是管理員相關的工作流程,現在看看用戶流量。首先我們這邊實現了每個容器通過 IPAM 組件,都能獲取一個獨立的 IP,這個 IP 可以和物理機雙向互通,所以允許用戶的流量可以直接通過容器 IP 訪問實例。
同時我們也提供了一個 4 層的 LB,允許用戶可以通過只訪問一個 VIP,自動把流量打到后面的容器里。
產品功能
接下來詳細講講滴滴彈性云具體的產品功能。
功能類型
正如之前所說,我們主要提供靜態容器和動態伸縮兩大產品,同時伸縮組方面又細分為有狀態和無狀態伸縮組。
其實在剛開始時,我們只想提供 K8S 支持得***的 Deployment,也就是無狀態伸縮,這也是***容器使用習慣的產品形式。但在實際落地的過程中,我們發現完全不是那么一回事。
首先,不是所有程序都能比較輕易地改造成 Cloud-Native 的服務,所以針對這樣的傳統服務,我們還是需要提供一個比較貼近物理機的用戶體驗的產品,它的問題就是不能彈性伸縮,但好處是可以掛載本地存儲,IP 是恒定的。
同時為了支持有狀態的服務,我們也提高了有狀態伸縮組。既支持彈性伸縮又支持掛載網絡存儲。
不過比較出人意料的是,用戶選擇有狀態伸縮組的很大一部分原因并不是因為掛載 Ceph,而是因為有狀態伸縮組的容器 IP/HostName 是不變的,這樣不管是從監控和日志上,都是更友好的。
而無狀態伸縮我們這個當初最想推動的服務,也就只有在一些對彈性伸縮速度有特別高的要求的場景下才會用到。
功能特性
具體到產品功能的特性上,我們主要有三大塊:
- 復雜配置簡單化
- 上線流程標準化
- 服務管理
復雜配置簡單化
了解過 K8S 的朋友們都清楚,它上手很難,有特別多的配置,有時候反而給用戶帶來了困擾。
所以我們做了減法,簡化了很多配置,只留給用戶一些接口,避免不必要的困擾。
比如我們支持多種接入方式,既可以一鍵完成從 Git 代碼倉庫到上線鏡像的轉換過程,也支持直接通過自定義鏡像。
同時我們也對鏡像做了分層(基礎鏡像→環境鏡像→服務鏡像),實現 RD 和 SRE 每個角色負責不同的鏡像制作,這樣分工更合理、層次更清晰,做到比較好的權責分明、高效有序。
監控日志自動配置關聯也是做了減法,希望用戶較少關注這一點,從而得到更好的體驗。
上線流程標準化
相對于減法來說,我們也做了很多的加法,因為我們是一個嚴肅的運維平臺,之所以強調嚴肅,是因為只要有人參與的地方就容易犯錯。
一方面我們要盡量減少人工參與的地方;另一方面又要盡量通過各種規范來減少人犯錯的機會。
比如變更審批系統,每一次上線變更都需要開發 leader 的審核;同時也對它進行了改造,使其每次分組小流量灰度。
每次發布更新的過程中都有強制的觀察時間,如果在觀察過程中,比如說你發布了第二組后,發現你的更新過程中代碼出了 Bug,我們還支持了一鍵回滾。
服務管理
在服務管理方面,我們實現了服務不可用自動重啟、一鍵擴容和負載均衡等,最為重要的就是對用戶強制異地多活,必須在我們的兩個機房都有實例。
方案細節
現在介紹我們的方案細節,主要包括:
- 網絡監控
- 日志
- 鏡像市場
網絡介紹
SDN
我們的網絡方案主要是基于 Onos+OVS 的 SDN 網絡方案,每個容器都有一個區別于機房實體機的 Overlay IP,容器與容器之間實現“大二層”互通,與機房網絡之間通過交換機打通。
物理機可以直接通過容器 Overlay IP 訪問容器,反之亦然。
IP
在 IP 上,靜態容器和伸縮容器都可以進行 Hostname 綁定,通過容器不變的 Hostname 保證容器在漂移到其他宿主后 IP 依舊保持不變,當容器發布更新時,它永遠保持穩定。
對于 IP 隨機分配的情況,我們還提供了 IP 池,保證 IP 只會從 IP 池里出現。
負載均衡
我們使用彈性云獨立的 4 層、7 層負載均衡器,實現動態的負載均衡及故障自動剔除。
網絡打通
架構
當前彈性云容器網絡大體上分為三種類型:同宿主間的容器通信、跨主機間的容器通信,以及容器與物理機間的通信。
每一個部署容器的宿主機,都會部署一套 Ovs 網絡組建,其中關鍵的就是兩個 Ovs Bridge,一個負責建立隧道與外界通信,叫 Ovs-tunnel 橋。
一個負責整合本機上的容器通信,叫 Ovs-int 橋。所有的 Ovs-tunnel 都會與 Onos 的 Controller 建立連接,負責查詢流表并建立流表和其他宿主機間的隧道。
因此三種通信類型就可以解釋為:
- 同宿主間的容器通信:直接通過 Ovs-int 橋通信,因此也不依賴 Ovs-tunnel 與外界的隧道。
- 跨主機間的容器通信:***次通信時,Ovs-tunnel 也會查詢 Onos,Onos 返回目標容器的主機信息,Ovs-tunnel 通過主機間的隧道,將容器數據發送到目的容器的宿主機,目的容器宿主機上的 Ovs-tunnel 則會將數據繼續向上一層傳遞,經 Ovs-int 傳遞給容器。
- 容器與物理機間的通信:容器發送物理機的數據包,會被 Ovs-tunnel 經隧道發送給 Overlay 網關,Overlay 網關進行 Vxlan 解包的操作,將數據傳遞到物理網絡。
相反地,物理機發送給容器的數據包,經 Overlay 網關把數據封包成 Vxlan 數據包,再通過隧道發往容器宿主,再由宿主傳遞給上一層的容器。
網絡 IP 分配
具體到產品上,每個 IP 分配方案如下:
- 靜態容器組:IP 和 Hostname 恒定。
- 有狀態伸縮組:IP 和 Hostname 恒定,支持 IP 池。
- 無狀態伸縮組:支持 IP 池,IP 隨機分配,靈活度更高。
創建過程
這個是容器網絡創建的過程。一旦用戶有創建容器需求時,控制節點會對整個集群做一個調度,選擇一個合適的工作節點,而作為節點最重要核心的 Kubelet 就負責創建容器,控制節點會把需求發給它。
具體創建步驟如下:
- 當 Kubelet 收到調度到本 Node 的 Pod 信息后,會先創建一個無網絡配置的 Infrastructure 的基礎容器,此容器用于承載 Pod 中所有容器的網絡 Namespace。
- Kubelet Exec 啟動 CNIPlugin,并將***步中創建的網絡 Namespace 及 Pod 名稱、容器 ID 等作為標準輸入,傳給新啟動的 Plugin 進程。
- CNIPlugin 根據收到的參數,去 IP Controller 中申請容器的網絡 IP。
- IP Controller 會判斷該容器屬于哪一個子網,子網中是否有可用的 IP,及是否有綁定的 IP 地址等,在根據計算出的 IP 地址及子網信息等,去 SDN IPAM 端申請虛擬 Port(Overlay IP)。
- IPAM 會將創建好的虛擬 Port 返回 API 調用者 IP Controller,并同時將信息同步給 SDN Onos。
- IP Controller 會將返回的 Port 保存在自己的存儲庫中。如果是綁定 IP 類型的 Pod,它還會將該 Pod 與該虛擬 Port(Overlay IP)進行綁定,則下一次該 Pod 再一次進行申請時,仍會申請到該 Port(Overlay IP)。數據保存后,它會把 Port 信息再返回給 CNIPlugin。
- CNIPlugin 收到 Port 信息后,會根據其中的 Overlay IP、Gateway、Vlan Tag 等信息創建 Veth Pair、配置 Veth 信息、配置路由、添加 Ovs-brdge 等操作。
- 至此,本來沒有任何網絡的基礎容器,就有了網絡配置(除了與外部通信的 Ovs 網絡外,同時也會添加 Lo 網絡)。
- CNIPlugin 在成功配置完網絡后,會將結果返回給 Kubelet。
- Kubelet 會使用配置成功的基礎容器的網絡 Namespace 繼續去創建其他的業務容器,如果配置失敗了,會繼續從***步開始,繼續創建基礎容器,直到網絡配置成功。
監控需求
監控主要有兩方面需求:
- 基礎監控:基礎監控使用了 Google 開源容器監控軟件 Cadvisor/Cgroup 作為監控數據來源,數據上報至 Odin,同時可在 Odin 和彈性云頁面上展開監控數據。
物理機監控 Agent 無法采集到容器有效監控數據,Cadvisor、Proc、Cgroup 容器基礎監控項同物理機有明顯差異,但用戶的需求沒變。
- 業務監控:業務監控同物理機需求完全一致,復用物理機監控方式。
這張圖就是彈性云配置監控和查看監控的示意圖,我們在每個物理機上有獲取容器的基礎監控指標,容器里面也會有獲取業務指標。
日志需求
日志主要有三個方面考慮:
- 日志時效性:在線日志采集延遲 2min,滿足大多數場景,緊急情況下可以登錄到容器內查看日志。
- 日志持久性:生成的容器直接拉到遠端存儲一份,選擇分布式存儲日志在 Ceph 存儲一份。
- 日志展示:事后追溯有多種豐富的日志展示、分析系統。
這是我們在彈性云平臺上創建容器的一個操作日志,也是一個簡單的示意圖。
通常用戶都打在容器里,而容器一旦發布更新,漂移之后數據都丟了,所以我們直接把日志打到 Ceph 上,用戶不喜歡用這個的話可以直接打到遠端,遠端采集系統可以使用不同的系統。
比如說 ES 和 HDFS,這樣就提供了更加豐富的日志展示和分析系統。
持久化存儲
存儲主要提供了本地卷和網絡卷:
本地卷 Host Path 提供給靜態容器組,我們把宿主機上的目錄掛載到容器里作為數據存儲卷,優勢是穩定和讀寫性高。
網絡卷 Ceph 的優勢是多備份更可靠,支持容器遷移,缺點是網絡抖動不可避免,所以得用 Ceph 的服務做改造,避免網絡抖動影響整個服務的進程。
Overlay FS
我們選擇 Overlay FS 作為存儲,一方面是因為它的性能/穩定性更好,當然它也有不足。
比如 DeviceMapper 可以通過 LVM 來解決磁盤的容量限制,但 Overlay FS 單靠本身是解決不了的,需要靠 XFS 來限制。
但我們發現在某些場景中 XFS 因為沒有開啟 ftype 功能,導致系統讀寫緩慢,因此我們建議大家如果也選用了 Overlay FS+XFS 方式,要把 ftype 設置為 1。
鏡像市場
如上圖所示,鏡像市場主要還是分層,目的是讓不同的用戶可以專注于不同的事情上:
- 基礎環境鏡像:彈性云管理員制作的鏡像:FROM 官方鏡像,增加了服務用到的各種 Agent、常用軟件、系統配置(添加 User、日志切割等)的鏡像。包攬最復雜的周邊應用的整合,并兼顧將鏡像做得更小。
- 服務環境鏡像:SRE 同學制作和維護的鏡像:FROM 基礎環境鏡像,安裝了服務運行所需的環境、配置。更加專注服務環境的保障,使鏡像滿足產品線的使用。
- 服務鏡像:使用 RD 代碼中 Dockerfile(一般只需要 Copy 代碼到線上所需目錄即可),FROM 服務環境鏡像,通過彈性云系統生成的提供服務的鏡像。
心得與展望
心得體會
首先,特別想強調的是“云計算拼的是運維,拼的是可靠性”。產品做得再好、運維人不靠譜,出了紕漏后就沒人敢再用你的產品了,說得再好也沒用。
其次,“線上無小事,要對線上保持敬畏感”。我之前是做開源社區的,解決方案做得多,但現在做云計算方案時才發現實際與想象的差別特別大,可以說云計算落地更難。
也許大家看了一些網上的分享后都會覺得搭建一套容器環境是比較容易的,可最難的就像我們這樣已經有現成的體系。
如果你要把它落地就需要做各種打通、妥協,甚至對一些功能做一些切割,有時這些不是我們想做的,但為了推進落地不得不去做。
此外,技術挑戰是一方面,但用戶習慣是更加大的挑戰,特別是業務方,他們肯定會說為什么我要遷,現在用得好好的,即便你和他們說做這個是對公司省成本的,可以提高運維的便利性,他們依然會覺得我不缺錢,怕麻煩。
再者,他們不是做運維的,明顯感覺不到這些帶來的好處。另一方面,有些用戶覺得我上你的云可以,但你不要改變我的習慣,原來是什么樣現在還得保持什么樣。
但問題是原來是物理機的用法,可現在已經上容器了 ,還想保持原來的方式,這是不可能的。
運維是一個特別苦的職業,線上無小事,一點點小改動,如果沒有考慮清楚、沒有充分驗證過回滾方案,那分分鐘要出事,相信大家也深諳此理。
未來展望
對于彈性云的未來規劃,***是更細粒度的隔離。大家對容器比較了解的話,就會清楚現在 Docker 更多的是對 Memory 使用量的隔離,以及對 CPU 使用量的隔離。
但實際過程中我們會發現,比如你給用戶一個 8G 內存,在某種極端配置下 8G 內存會不斷地刷新讀寫,那你的 L3 Cache 很快就會被刷爆了,導致大量的 Cache Miss,這樣的話還是會對程序性能造成很大影響的。
第二是靜態容器的彈性伸縮。因為靜態容器確實就像虛擬機一樣,運維成本特別高,所以一旦物理機掛了,容器也就掛了,很多東西是找不回來的。
而且你要擴容也只能按照傳統的方法,先申請一個容器再去上面做部署、配置等,這些都會給運維同學帶來非常大的困擾。
第三是更智能的擴容算法。目前我們是根據實時的使用率來進行擴容,但其實對于我們來說,很多業務高峰期是有規律的,如果能做到提前預測出高峰期,做適應的擴容,那將會極大地提高資源使用率。
最重要的一點是依托社區、回饋社區。我們打算騰出手來,把一些定制化需求不是那么高的解決方案來回饋到社區。
譚霖,滴滴出行彈性云架構師、云計算專家,曾任職于英特爾從事云計算方向研究。OpenStack Ironic 項目核心開發者,《OpenStack設計與實現》作者,多次在OpenStack Summit SRECon 峰會上分享 Topic。目前從事基于 Kubernetes 的私有云平臺的研發,專注提高服務的穩定性和研發、運維效率。