開發與維運

如何輕鬆學習 Kubernetes?

一 什麼是 Kubernetes?

我們來看一下什麼是 Kubernetes。這部分內容我會從四個角度來跟大家分享一下我的看法。

1 未來什麼樣

image.png

這是一張未來大部分公司後端 IT 基礎設施的架構圖。簡單來說,以後所有公司的 IT 基礎設施都會部署在雲上。用戶會基於 Kubernetes 把底層雲資源分割成具體的集群單元,給不同的業務使用。而隨著業務微服務化的深入,服務網格這樣的服務治理邏輯會變得跟下邊兩層一樣,成為基礎設施的範疇。

目前,阿里基本上所有的業務都跑在雲上。而其中大約有一半的業務已經遷移到了自己定製 Kubernetes 集群上。另外據我瞭解,阿里計劃今年完成 100% 的基於 Kubernetes 集群的業務部署。

而服務網格這塊,在阿里的一些部門,像螞蟻金服,其實已經有線上業務在用了。大家可以通過螞蟻一些同學的分享來了解他們的實踐過程。

雖然這張圖裡的觀點可能有點絕對,但是目前這個趨勢是非常明顯的。所以未來幾年, Kubernetes 肯定會變成像 Linux 一樣的,作為集群的操作系統無處不在。

2 Kubernetes 與操作系統

image.png

這是一張傳統的操作系統和 Kubernetes 的比較圖。大家都知道,作為一個傳統的操作系統,像 Linux 或者 Windows,它們扮演的角色,就是底層硬件的 一個抽象層。它們向下管理計算機的硬件,像內存或 CPU,然後把底層硬件抽象成一些易用的接口,用這些接口,向上對應用層提供支持。

而 Kubernetes 呢,我們也可以把它理解為一個操作系統。這個操作系統說白了也是一個抽象層,它向下管理的硬件,不是內存或者 CPU 這種硬件,而是多臺計算機組成的集群,這些計算機本身就是普通的單機系統,有自己的操作系統和硬件。Kubernetes 把這些計算機當成一個資源池來 統一管理,向上對應用提供支撐。

這裡的應用比較特別,就是這些應用都是容器化的應用。如果對容器不太瞭解的同學,可以簡單把這些應用,理解為一個應用安裝文件。安裝文件打包了所有的依賴庫,比如 libc 這些。這些應用不會依賴底層操作系統的庫文件來運行。

3 Kubernetes 與 Google 運維解密

image.png

上圖中,左邊是一個 Kubernetes 集群,右邊是一本非常有名的書,就是 Google 運維解密這本書。相信很多人都看過這本書,而且有很多公司目前也在實踐這本書裡的方法。包括故障管理,運維排班等。

Kubernetes 和這本書的關係,我們可以把他們比作劍法和氣功的關係。不知道這裡有多少人看過笑傲江湖。笑傲江湖裡的華山派分兩個派別,氣宗和劍宗。氣宗注重氣功修煉,而劍宗更強調劍法的精妙。實際上氣宗和劍宗的分家,是因為華山派兩個弟子偷學一本葵花寶典,兩個人各記了一部分,最終因為觀點分歧分成了兩派。

Kubernetes 實際上源自 Google 的集群自動化管理和調度系統 Borg,也就是這本書裡講的運維方法所針對的對象。Borg 系統和書裡講的各種運維方法可以看做是一件事情的兩個方面。如果一個公司只去學習他們的運維方法,比如開了 SRE 的職位,而不懂這套方法所管理的系統的話,那其實就是學習葵花寶典,但是隻學了一部分。

Borg 因為是 Google 內部的系統,所以我們一般人是看不到的,而 Kubernetes 基本上繼承了 Borg 在集群自動化管理方面非常核心的一些理念。所以如果大家看了這本書,覺得很厲害,或者在實踐這本書裡的方法,那大家一定要深入理解下 Kubernetes。

4 技術演進史

image.png

早期的時候,我們做一個網站後端,可能只需要把所有的模塊放在一個可執行文件裡,就像上圖一樣,我們有 UI、數據和業務三個模塊,這三個模塊被編譯成一個可執行文件,跑在一臺服務器上。

但是隨著業務量的大幅增長,我們沒有辦法,通過升級服務器配置的方式來擴容。這時候我們就必須去做微服務化了。

微服務化會把單體應用拆分成低耦合的小應用。這些應用各自負責一塊業務,然後每個應用的實例獨佔一臺服務器,它們之間通過網絡互相調用。

這裡最關鍵的是,我們可以通過增加實例個數,來對小應用做橫向擴容。這就解決了單臺服務器無法擴容的問題。

微服務之後會出現一個問題,就是一個實例佔用一臺服務器的問題。這種部署方式,資源的浪費其實是比較嚴重的。這時我們自然會想到,把這些實例混部到底層服務器上。

但是混部會引入兩個新問題,一個是依賴庫兼容性問題。這些應用依賴的庫文件版本可能完全不一樣,安裝到一個操作系統裡,必然會出問題。另一個問題就是應用調度和集群資源管理的問題。

比如一個新的應用被創建出來,我們需要考慮這個應用被調度到哪臺服務器,調度上去之後資源夠不夠用這些問題。

這裡的依賴庫兼容性問題,是靠容器化來解決的,也就是每個應用自帶依賴庫,只跟其他應用共享內核。而調度和資源管理就是 Kubernetes 所解決的問題。

順便提一句,我們可能會因為,集群裡混部的應用太多,這些應用關係錯綜複雜,而沒有辦法去排查一些像請求響應慢這樣的問題。所以類似服務網格這類服務治理的技術,肯定會成為下一個趨勢。

二 怎麼學習 Kubernetes?

1 Kubernetes 學習難點

image.png

總體來說,Kubernetes 之所以門檻比較高,比較難學習,一個是因為它的技術棧非常深,包括了內核,虛擬化,容器,軟件定義網絡 SDN,存儲,安全,甚至可信計算等,絕對可以稱得上全棧技術。

同時 Kubernetes 在雲環境的實現,肯定會牽扯到非常多的雲產品,比如在阿里雲上,我們的 Kubernetes 集群用到了 ECS 雲服務器,VPC 虛擬網絡,負載均衡,安全組,日誌服務,雲監控,中間件產品像 ahas 和 arms,服務網格,彈性伸縮等等大量雲產品。

最後,因為 Kubernetes 是一個通用的計算平臺,所以它會被用到各種業務場景中去,比如數據庫。據我所知,像我們的 PolarDB Box 一體機就是計劃基於 Kubernetes 搭建。另外還有邊緣計算,機器學習,流計算等等。

2 瞭解、動手、思考

image.png

基於我個人的經驗,學習 Kubernetes,我們需要從瞭解、動手、以及思考三個方面去把握。

瞭解其實很重要,特別是瞭解技術的演進史,以及技術的全景圖。

我們需要知道各種技術的演進歷史,比如容器技術是怎麼從 chroot 這個命令發展而來的,以及技術演進背後要解決的問題是什麼,只有知道技術的演進史和發展的動力,我們才能對未來技術方向有自己的判斷。

同時我們需要了解技術全景,對 Kubernetes 來說,我們需要了解整個雲原生技術棧,包括容器,CICD,微服務、服務網格這些,知道 Kubernetes 在整個技術棧裡所處的位置。

除了這些基本的背景知識以外,學習 Kubernetes 技術,動手實踐是非常關鍵的。

從我和大量工程師一起解決問題的經驗來說,很多人其實是不會去深入研究技術細節的。我們經常開玩笑說工程師有兩種,一種是 search engineer,就是搜索工程師,一種是 research engineer,就是研究工程師。很多工程師遇到問題,google 一把,如果搜不到答案,就直接開工單了。這樣是很難深入理解一個技術的。

最後就是怎麼去思考,怎麼去總結了。我個人的經驗是,我們需要在理解技術細節之後,不斷的問自己,細節的背後,有沒有什麼更本質的東西。也就是我們要把複雜的細節看簡單,然後找出普通的模式出來。

下邊我用兩個例子來具體解釋一下上邊的方法。

3 用冰箱來理解集群控制器

image.png

第一個例子是關於集群控制器的。我們在學習 Kubernetes 的時候會聽到幾個概念,像聲明式 API,Operator,面向終態設計等。這些概念本質上 都是在講一件事情,就是控制器模式。

我們怎麼來理解 Kubernetes 的控制器呢?上面這張圖是一個經典的 Kubernetes 架構圖,這張圖裡有集群管控節點和工作節點,管控節點上有中心數據庫,API Server,調度器及一些控制器。

中心數據庫是集群的核心存儲系統,API Server 是集群的管控入口,調度器負責把應用調度到資源充沛的節點上。而控制器是我們這裡要說的重點。控制器的作用,我們用一句話概括,就是“讓夢想照進現實”。從這個意義上來講,我自己也經常扮演控制器的角色,我女兒如果說,爸爸我要吃冰激凌,那我女兒就是集群的用戶,我就是負責把她這個願望實現的人,就是控制器。

除了管控節點以外,Kubernetes 集群有很多工作節點,這些節點都部署了 Kubelet 和 Proxy 這兩個代理。Kubelet 負責管理工作節點,包括應用在節點上啟動和停止之類的工作。Proxy 負責把服務的定義落實成具體的 iptables 或者 ipvs 規則。這裡服務的概念,其實簡單來說,就是利用 iptables 或者 ipvs 來實現負載均衡。

如果我們從控制器的角度來看第一張圖的話,我們就會得到第二張圖。也就是說,集群實際上就包括一個數據庫,一個集群入口,以及很多個控制器。這些組件,包括調度器,Kubelet 以及 Proxy,實際上都是不斷的去觀察集群裡各種資源的定義,然後把這些定義落實成具體的配置,比如容器啟動或 iptables 配置。

從控制器的角度觀察 Kubernetes 的時候,我們其實得到了 Kubernetes 最根本的一個原理了。就是控制器模式。

其實控制器模式在我們生活中無處不在的,這裡我拿冰箱做個例子。我們在控制冰箱的時候,並不會直接去控制冰箱裡的製冷系統或者照明系統。我們打開冰箱的時候,裡邊的燈會打開,我們在設置了想要的溫度之後,就算我們不在家,製冷系統也會一直保持這個溫度。這背後就是因為有控制器模式在起作用。

4 為什麼刪除不掉命名空間

image.png

第二個例子,我們來看一個真實問題的排查過程。這個問題是一個命名空間不能被刪除的問題。問題稍微有點複雜,我們一步一步來看。

命名空間是 Kubernetes 集群的 一個收納盒機制,就像這裡的第一張圖片一樣。這個盒子就是命名空間,它裡邊收納了橡皮和鉛筆。

命名空間可以被創建或者刪除。我們經常會遇到不能刪除命名空間的問題。遇到這個問題,我們如果完全不知道怎麼排查。第一步我們可能會想到,研究一下 API Server 是怎麼處理這個刪除操作的,因為 API Server 就是集群的 管理入口。

API Server 本身是一個應用,我們可以通過提升這個應用的日誌級別,來深入理解它的操作流程。在這個問題裡,我們會發現,API Server 收到刪除命令,但是就沒有其他信息了。

這裡我們需要稍微理解下命名空間的刪除過程,用戶在刪除命名空間的時候,其實命名空間並不會被直接刪除掉,而會被改成“刪除中”的狀態。這個時候命名空間控制器就會看到這個狀態。

為了理解命名空間控制器的行為,我們同樣可以把控制器的日誌級別提高來查看詳細的日誌。這個時候呢,我們會發現,控制器正在嘗試去獲取所有的 API 分組。

到這裡我們需要去理解兩個事情。一個是為什麼刪除命名空間,控制器會去獲取 API 分組。第二個是 API 分組到底是什麼。

我們先看第二個問題,API 分組到底是什麼。簡單來說,API 分組就是集群 API 的分類機制,比如網絡相關的 API 就在 networking 這個組裡。而通過網絡 API 分組創建出來的資源就屬於這個組。

那為什麼命名空間控制器會去獲取 API 分組呢?是因為在刪除命名空間的時候,控制器需要刪除命名空間裡的所有資源。這個操作不像我們刪除文件夾一樣,會把裡邊的文件都一起刪掉。

命名空間收納了資源,實際上是這些資源用類似索引的機制,指向了這個命名空間。集群只有遍歷所有的 API 分組,找出指向這個命名空間的所有資源,才能逐個把它們刪除掉。

而遍歷 API 組這個操作呢,會使得集群的 API Server 和它的擴展進行通信。這是因為 API Server 的擴展,也可以實現一部分 API 分組。所以想知道被刪除的命名空間裡是不是有包括這個擴展定義的資源,API Server 就必須和擴展通信。

到這一步之後,問題實際上變成 API Server 和他的擴展之間通信的問題。也就是刪除資源的問題就變成了網絡問題。

阿里雲的 Kubernetes 集群,是在 VPC 網絡,也就是虛擬局域網上創建的。默認情況下, VPC 的只認識 VPC 網段的地址,而集群裡邊的容器,一般會使用和 VPC 不同的網段。比如 VPC 使用 172 網段,那容器可能就使用 192 網段。

我們通過在 VPC 的路由表裡,增加容器網段的路由項,可以讓容器使用 VPC 網絡進行通信。

在右下角這張圖,我們有兩個集群節點,他們的地址是 172 網段,那我們給路由表裡增加 192 網段的路由項,就可以讓 VPC 把發給容器的數據轉發到正確的節點上,再由節點發給具體的容器。

而這裡的路由項,是在節點加入集群的時候,由路由控制器來添加的。路由控制器在發現有新節點加入集群之後,會立刻做出反應,給路由表裡增加一條路由項。

添加路由項這個操作,其實是對 VPC 的一次操作。這個操作是需要使用一定的授權的,這是因為這個操作跟線下一臺機器訪問雲上資源是差不多的,肯定需要授權。

這裡路由控制器使用的授權,是以 RAM 角色的方式綁定到路由控制器所在的集群節點上的。而這個 RAM 角色,正常會有一系列的授權規則。

最後,我們通過檢查,發現用戶修改了授權規則,所以導致了這個問題。

Leave a Reply

Your email address will not be published. Required fields are marked *