1. 程式人生 > >從零開始入門 K8s| 阿里技術專家詳解 K8s 核心概念

從零開始入門 K8s| 阿里技術專家詳解 K8s 核心概念

作者| 阿里巴巴資深技術專家、CNCF 9個 TCO 之一 李響

一、什麼是 Kubernetes

Kubernetes,從官方網站上可以看到,它是一個工業級的容器編排平臺。Kubernetes 這個單詞是希臘語,它的中文翻譯是“舵手”或者“飛行員”。在一些常見的資料中也會看到“ks”這個詞,也就是“K8s”,它是通過將 8 個字母“ubernete ”替換為“8”而導致的一個縮寫。

Kubernetes 為什麼要用“舵手”來命名呢?大家可以看一下這張圖:

這是一艘載著一堆集裝箱的輪船,輪船在大海上運著集裝箱奔波,把集裝箱送到它們該去的地方。我們之前其實介紹過一個概念叫做 container,container 這個英文單詞也有另外的一個意思就是“集裝箱”。Kubernetes 也就藉著這個寓意,希望成為運送集裝箱的一個輪船,來幫助我們管理這些集裝箱,也就是管理這些容器。

這個就是為什麼會選用 Kubernetes 這個詞來代表這個專案的原因。更具體一點地來說:Kubernetes 是一個自動化的容器編排平臺,它負責應用的部署、應用的彈性以及應用的管理,這些都是基於容器的。

二、Kubernetes 有如下幾個核心的功能:

  • 服務的發現與負載的均衡;
  • 容器的自動裝箱,我們也會把它叫做 scheduling,就是“排程”,把一個容器放到一個叢集的某一個機器上,Kubernetes 會幫助我們去做儲存的編排,讓儲存的宣告週期與容器的生命週期能有一個連線;
  • Kubernetes 會幫助我們去做自動化的容器的恢復。在一個叢集中,經常會出現宿主機的問題或者說是 OS 的問題,導致容器本身的不可用,Kubernetes 會自動地對這些不可用的容器進行恢復;
  • Kubernetes 會幫助我們去做應用的自動釋出與應用的回滾,以及與應用相關的配置密文的管理;
  • 對於 job 型別任務,Kubernetes 可以去做批量的執行;
  • 為了讓這個叢集、這個應用更富有彈性,Kubernetes 也支援水平的伸縮。

下面,我們希望以三個例子跟大家更切實地介紹一下 Kubernetes 的能力。

1、排程

Kubernetes 可以把使用者提交的容器放到 Kubernetes 管理的叢集的某一臺節點上去。Kubernetes 的排程器是執行這項能力的元件,它會觀察正在被排程的這個容器的大小、規格。

比如說它所需要的 CPU以及它所需要的 memory,然後在叢集中找一臺相對比較空閒的機器來進行一次 placement,也就是一次放置的操作。在這個例子中,它可能會把紅顏色的這個容器放置到第二個空閒的機器上,來完成一次排程的工作。

2、自動修復

Kubernetes 有一個節點健康檢查的功能,它會監測這個叢集中所有的宿主機,當宿主機本身出現故障,或者軟體出現故障的時候,這個節點健康檢查會自動對它進行發現。

下面 Kubernetes 會把執行在這些失敗節點上的容器進行自動遷移,遷移到一個正在健康執行的宿主機上,來完成叢集內容器的一個自動恢復。

3、水平伸縮

Kubernetes 有業務負載檢查的能力,它會監測業務上所承擔的負載,如果這個業務本身的 CPU 利用率過高,或者響應時間過長,它可以對這個業務進行一次擴容。

比如說在下面的例子中,黃顏色的過度忙碌,Kubernetes 就可以把黃顏色負載從一份變為三份。接下來,它就可以通過負載均衡把原來打到第一個黃顏色上的負載平均分到三個黃顏色的負載上去,以此來提高響應的時間。

 

以上就是 Kubernetes 三個核心能力的簡單介紹。

三、Kubernetes 的架構

Kubernetes 架構是一個比較典型的二層架構和 server-client 架構。Master 作為中央的管控節點,會去與 Node 進行一個連線。

所有 UI 的、clients、這些 user 側的元件,只會和 Master 進行連線,把希望的狀態或者想執行的命令下發給 Master,Master 會把這些命令或者狀態下發給相應的節點,進行最終的執行。

Kubernetes 的 Master 包含四個主要的元件:API Server、Controller、Scheduler 以及 etcd。如下圖所示:

  • API Server:顧名思義是用來處理 API 操作的,Kubernetes 中所有的元件都會和 API Server 進行連線,元件與元件之間一般不進行獨立的連線,都依賴於 API Server 進行訊息的傳送;
  • Controller:是控制器,它用來完成對叢集狀態的一些管理。比如剛剛我們提到的兩個例子之中,第一個自動對容器進行修復、第二個自動進行水平擴張,都是由 Kubernetes 中的 Controller 來進行完成的;
  • Scheduler:是排程器,“排程器”顧名思義就是完成排程的操作,就是我們剛才介紹的第一個例子中,把一個使用者提交的 Container,依據它對 CPU、對 memory 請求大小,找一臺合適的節點,進行放置;
  • etcd:是一個分散式的一個儲存系統,API Server 中所需要的這些原資訊都被放置在 etcd 中,etcd 本身是一個高可用系統,通過 etcd 保證整個 Kubernetes 的 Master 元件的高可用性。

我們剛剛提到的 API Server,它本身在部署結構上是一個可以水平擴充套件的一個部署元件;Controller 是一個可以進行熱備的一個部署元件,它只有一個 active,它的排程器也是相應的,雖然只有一個 active,但是可以進行熱備。

Kubernetes 的架構:Node

Kubernetes 的 Node 是真正執行業務負載的,每個業務負載會以 Pod 的形式執行。等一下我會介紹一下 Pod 的概念。一個 Pod 中執行的一個或者多個容器,真正去執行這些 Pod 的元件的是叫做 kubelet,也就是 Node 上最為關鍵的元件,它通過 API Server 接收到所需要 Pod 執行的狀態,然後提交到我們下面畫的這個 Container Runtime 元件中。

在 OS 上去建立容器所需要執行的環境,最終把容器或者 Pod 執行起來,也需要對儲存跟網路進行管理。Kubernetes 並不會直接進行網路儲存的操作,他們會靠 Storage Plugin 或者是網路的 Plugin 來進行操作。使用者自己或者雲廠商都會去寫相應的 Storage Plugin 或者 Network Plugin,去完成儲存操作或網路操作。

在 Kubernetes 自己的環境中,也會有 Kubernetes 的 Network,它是為了提供 Service network 來進行搭網組網的。(等一下我們也會去介紹“service”這個概念。)真正完成 service 組網的元件的是 Kube-proxy,它是利用了 iptable 的能力來進行組建 Kubernetes 的 Network,就是 cluster network,以上就是 Node 上面的四個元件。

Kubernetes 的 Node 並不會直接和 user 進行 interaction,它的 interaction 只會通過 Master。而 User 是通過 Master 向節點下發這些資訊的。Kubernetes 每個 Node 上,都會執行我們剛才提到的這幾個元件。

下面我們以一個例子再去看一下 Kubernetes 架構中的這些元件,是如何互相進行 interaction 的。

使用者可以通過 UI 或者 CLI 提交一個 Pod 給 Kubernetes 進行部署,這個 Pod 請求首先會通過 CLI 或者 UI 提交給 Kubernetes API Server,下一步 API Server 會把這個資訊寫入到它的儲存系統 etcd,之後 Scheduler 會通過 API Server 的 watch 或者叫做 notification 機制得到這個資訊:有一個 Pod 需要被排程。

這個時候 Scheduler 會根據它的記憶體狀態進行一次排程決策,在完成這次排程之後,它會向 API Server report 說:“OK!這個 Pod 需要被排程到某一個節點上。”

這個時候 API Server 接收到這次操作之後,會把這次的結果再次寫到 etcd 中,然後 API Server 會通知相應的節點進行這次 Pod 真正的執行啟動。相應節點的 kubelet 會得到這個通知,kubelet 就會去調 Container runtime 來真正去啟動配置這個容器和這個容器的執行環境,去排程 Storage Plugin 來去配置儲存,network Plugin 去配置網路。

這個例子我們可以看到:這些元件之間是如何相互溝通相互通訊,協調來完成一次Pod的排程執行操作的。

四、Kubernetes 的核心概念與它的 API

核心概念

第一個概念:Pod

Pod 是 Kubernetes 的一個最小排程以及資源單元。使用者可以通過 Kubernetes 的 Pod API 生產一個 Pod,讓 Kubernetes 對這個 Pod 進行排程,也就是把它放在某一個 Kubernetes 管理的節點上執行起來。一個 Pod 簡單來說是對一組容器的抽象,它裡面會包含一個或多個容器。

比如像下面的這幅圖裡面,它包含了兩個容器,每個容器可以指定它所需要資源大小。比如說,一個核一個 G,或者說 0.5 個核,0.5 個 G。

當然在這個 Pod 中也可以包含一些其他所需要的資源:比如說我們所看到的 Volume 卷這個儲存資源;比如說我們需要 100 個 GB 的儲存或者 20GB 的另外一個儲存。

在 Pod 裡面,我們也可以去定義容器所需要執行的方式。比如說執行容器的 Command,以及執行容器的環境變數等等。Pod 這個抽象也給這些容器提供了一個共享的執行環境,它們會共享同一個網路環境,這些容器可以用 localhost 來進行直接的連線。而 Pod 與 Pod 之間,是互相有 isolation 隔離的。

第二個概念:Volume

Volume 就是卷的概念,它是用來管理 Kubernetes 儲存的,是用來宣告在 Pod 中的容器可以訪問檔案目錄的,一個卷可以被掛載在 Pod 中一個或者多個容器的指定路徑下面。

而 Volume 本身是一個抽象的概念,一個 Volume 可以去支援多種的後端的儲存。比如說 Kubernetes 的 Volume 就支援了很多儲存外掛,它可以支援本地的儲存,可以支援分散式的儲存,比如說像 ceph,GlusterFS ;它也可以支援雲端儲存,比如說阿里雲上的雲盤、AWS 上的雲盤、Google 上的雲盤等等。

第三個概念:Deployment

Deployment 是在 Pod 這個抽象上更為上層的一個抽象,它可以定義一組 Pod 的副本數目、以及這個 Pod 的版本。一般大家用 Deployment 這個抽象來做應用的真正的管理,而 Pod 是組成 Deployment 最小的單元。

Kubernetes 是通過 Controller,也就是我們剛才提到的控制器去維護 Deployment 中 Pod 的數目,它也會去幫助 Deployment 自動恢復失敗的 Pod。

比如說我可以定義一個 Deployment,這個 Deployment 裡面需要兩個 Pod,當一個 Pod 失敗的時候,控制器就會監測到,它重新把 Deployment 中的 Pod 數目從一個恢復到兩個,通過再去新生成一個 Pod。通過控制器,我們也會幫助完成釋出的策略。比如說進行滾動升級,進行重新生成的升級,或者進行版本的回滾。

第四個概念:Service

Service 提供了一個或者多個 Pod 例項的穩定訪問地址。

比如在上面的例子中,我們看到:一個 Deployment 可能有兩個甚至更多個完全相同的 Pod。對於一個外部的使用者來講,訪問哪個 Pod 其實都是一樣的,所以它希望做一次負載均衡,在做負載均衡的同時,我只想訪問某一個固定的 VIP,也就是 Virtual IP 地址,而不希望得知每一個具體的 Pod 的 IP 地址。

我們剛才提到,這個 pod 本身可能 terminal go(終止),如果一個 Pod 失敗了,可能會換成另外一個新的。

對一個外部使用者來講,提供了多個具體的 Pod 地址,這個使用者要不停地去更新 Pod 地址,當這個 Pod 再失敗重啟之後,我們希望有一個抽象,把所有 Pod 的訪問能力抽象成一個第三方的一個 IP 地址,實現這個的 Kubernetes 的抽象就叫 Service。

實現 Service 有多種方式,Kubernetes 支援 Cluster IP,上面我們講過的 kuber-proxy 的組網,它也支援 nodePort、 LoadBalancer 等其他的一些訪問的能力。

第五個概念:Namespace

Namespace 是用來做一個叢集內部的邏輯隔離的,它包括鑑權、資源管理等。Kubernetes 的每個資源,比如剛才講的 Pod、Deployment、Service 都屬於一個 Namespace,同一個 Namespace 中的資源需要命名的唯一性,不同的 Namespace 中的資源可以重名。

Namespace 一個用例,比如像在阿里巴巴,我們內部會有很多個 business units,在每一個 business units 之間,希望有一個檢視上的隔離,並且在鑑權上也不一樣,在 cuda 上面也不一樣,我們就會用 Namespace 來去給每一個 BU 提供一個他所看到的這麼一個看到的隔離的機制。

Kubernetes 的 API

下面我們介紹一下 Kubernetes 的 API 的基礎知識。從 high-level 上看,Kubernetes API 是由 HTTP+JSON 組成的:使用者訪問的方式是 HTTP,訪問的 API 中 content 的內容是 JSON 格式的。

Kubernetes 的 kubectl 也就是 command tool,Kubernetes UI,或者有時候用 curl,直接與 Kubernetes 進行溝通,都是使用 HTTP + JSON 這種形式。

下面有個例子:比如說,對於這個 Pod 型別的資源,它的 HTTP 訪問的路徑,就是 API,然後是 apiVesion: V1, 之後是相應的 Namespaces,以及 Pods 資源,最終是 Podname,也就是 Pod 的名字。

如果我們去提交一個 Pod,或者 get 一個 Pod 的時候,它的 content 內容都是用 JSON 或者是 YAML 表達的。上圖中有個 yaml 的例子,在這個 yaml file 中,對 Pod 資源的描述也分為幾個部分。

第一個部分,一般來講會是 API 的 version。比如在這個例子中是 V1,它也會描述我在操作哪個資源;比如說我的 kind 如果是 pod,在 Metadata 中,就寫上這個 Pod 的名字;比如說 nginx,我們也會給它打一些 label,我們等下會講到 label 的概念。在 Metadata 中,有時候也會去寫 annotation,也就是對資源的額外的一些使用者層次的描述。

比較重要的一個部分叫做 Spec,Spec 也就是我們希望 Pod 達到的一個預期的狀態。比如說它內部需要有哪些 container 被執行;比如說這裡面有一個 nginx 的 container,它的 image 是什麼?它暴露的 port 是什麼?

當我們從 Kubernetes API 中去獲取這個資源的時候,一般來講在 Spec 下面會有一個專案叫 status,它表達了這個資源當前的狀態;比如說一個 Pod 的狀態可能是正在被排程、或者是已經 running、或者是已經被 terminates,就是被執行完畢了。

剛剛在 API 之中,我們講了一個比較有意思的 metadata 叫做“label”,這個 label 可以是一組 KeyValuePair。

比如下圖的第一個 pod 中,label 就可能是一個 color 等於 red,即它的顏色是紅顏色。當然你也可以加其他 label,比如說 size: big 就是大小,定義為大的,它可以是一組 label。

這些 label 是可以被 selector,也就是選擇器所查詢的。這個能力實際上跟我們的 sql 型別的 select 語句是非常相似的,比如下圖中的三個 Pod 資源中,我們就可以進行 select。name color 等於 red,就是它的顏色是紅色的,我們也可以看到,只有兩個被選中了,因為只有他們的 label 是紅色的,另外一個 label 中寫的 color 等於 yellow,也就是它的顏色是黃色,是不會被選中的。

通過 label,kubernetes 的 API 層就可以對這些資源進行一個篩選,那這些篩選也是 kubernetes 對資源的集合所表達預設的一種方式。

例如說,我們剛剛介紹的 Deployment,它可能是代表一組的 Pod,它是一組 Pod 的抽象,一組 Pod 就是通過 label selector 來表達的。當然我們剛才講到說 service 對應的一組 Pod,就是一個 service 要對應一個或者多個的 Pod,來對它們進行統一的訪問,這個描述也是通過 label selector 來進行 select 選取的一組 Pod。

所以可以看到 label 是一個非常核心的 kubernetes API 的概念,我們在接下來的課程中也會著重地去講解和介紹 label 這個概念,以及如何更好地去使用它。

五、以一個 demo 結尾

最後一部分,我想以一個例子來結束,讓大家跟我一起來嘗試一個 kubernetes,在嘗試 Kubernetes 之前,我希望大家能在本機上安裝一下 Kubernetes,安裝一個 Kubernetes 沙箱環境。

安裝這個沙箱環境,主要有三個步驟:

  • 首先需要安裝一個虛擬機器,來在虛擬機器中啟動 Kubernetes。我們會推薦大家利用 virtualbox 來作為虛擬機器的執行環境;

安裝 VirtualBox: https://www.virtualbox.org/wiki/Downloads

  • 其次我們需要在虛擬機器中啟動 Kubernetes,Kubernetes 有一個非常有意思的專案,叫 minikube,也就是啟動一個最小的 local 的 Kubernetes 的一個環境。

minikube 我們推薦使用下面寫到的阿里雲的版本,它和官方 minikube 的主要區別就是把 minikube 中所需要的 Google 上的依賴換成國內訪問比較快的一些映象,這樣就方便了大家的安裝工作;

安裝 MiniKube(中國版): https://yq.aliyun.com/articles/221687

  • 最後在安裝完 virtualbox 和 minikube 之後,大家可以對 minikube 進行啟動,也就是下面這個命令。

啟動命令:minikube start —vm-driver virtualbox

如果大家不是 Mac 系統,其他作業系統請訪問下面這個連結,檢視其它作業系統如何安裝 minikube 沙箱環境。

https://kubernetes.io/docs/tasks/tools/install-minikube/

當大家安裝好之後,我會跟大家一起做一個例子,來做三件事情:

  1. 提交一個 nginx deployment;

kubectl apply  -f  https://k8s.io/examples/application/deployment.yaml

  1. 升級 nginx deployment;

kubectl apply -f  https://k8s.io/examples/application/deployment-update.yaml

  1. 擴容 nginx deployment。

kubectl apply -f  https://k8s.io/examples/application/deployment-update.yaml

第一步,我們提交一個 nginx 的 Deployment,然後對這個 Deployment 進行一次版本升級,也就是改變它中間 Pod 的版本。最後我們也會嘗試對 nginx 進行一次擴容,進行一次水平的伸縮,下面就讓大家一起跟我來嘗試這三個操作吧。

首先,我們先看一下 minikube 的 status,可以看到 kubelet master 和 kubectl 都是配置好的。

下一步我們利用 kubectl 來看一下這個叢集中節選的狀態,可以看到這個master 的節點已經是running狀態:

我們就以這個為節點,下面我們嘗試去看一下現在叢集中 Deployment 這個資源:

可以看到叢集中沒有任何的 Deployment,我們可以利用 watch 這個語義去看叢集中 Deployment 這個資源的變化情況。

下面我們去做剛才想要的三個操作:第一個操作是去建立一個 Deployment。可以看到下面第一個圖,這是一個 API 的 content,它的 kind 是 Deployment,name 是 nginx-deployment, 有圖中它的 replicas 數目是2,它的映象版本是 1.7.9。

![](https://img2018.cnblogs.com/blog/1411156/201909/1411156-20190919143310619-331641224.png)![](https://img2018.cnblogs.com/blog/1411156/201909/1411156-20190919143311058-1668787295.png)

我們下面還是回到 kubectl 這個 commnd 來執行這次 Deployment 的真正的操作。我們可以看到一個簡單的操作,就會去讓 Deployment 不停地生成副本。

Deployment 副本數目是 2 個,下面也可以 describe 一下現在的 Deployment 的狀態。我們知道之前是沒有這個 Deployment 的,現在我們去 describe 這個 nginx-deployment。

下圖中可以看到:有一個 nginx-deployment 已經被生成了,它的 replicas 數目也是我們想要的、selector 也是我們想要的、它的 image 的版本也是 1.7.9。還可以看到,裡面的 deployment-controller 這種版本控制器也是在管理它的生成。

下面我們去升級這個 Deployment 版本,首先下載另外一個 yaml 檔案 deployment-update.yaml,可以看到這裡面的 image 本身的版本號從 1.7.9 升級到 1.8。

接下來我們重新 apply 新的 deployment-update 這個 yaml 檔案。

可以看到,在另一邊的螢幕上顯示出了這個 Deployment 升級的一些操作,最終它的 up-to-date 值從 0 變成了 2,也就是說所有的容器都是最新版本的,所有的 Pod 都是最新版本的。我們也可以 discribe 具體去看一下是不是所有 Pod 的版本都被更新了,可以看到這個 image 的版本由 1.7.9 真正更新到了 1.8。

最後,我們也可以看到  controller 又執行了幾次新的操作,這個控制器維護了整個 Deployment 和 Pod 狀態。

最後我們演示一下給 Deployment 做水平擴張,下載另一個 yaml 檔案 deployment-scale.yaml,這裡面的 replicas 數目已經從 2 改成了 4。

回到最開始的視窗,用 kubectl 去 apply 這個新的 deployment-scale.yaml 檔案,在另外一個視窗上可以看到,當我們執行了 deployment-scale 操作之後,它的容器 Pod 數目從 2 變成了 4。我們可以再一次 describ 一下當前叢集中的 deployment 的情況,可以看到它的 replicas 的數目從 2 變到了 4,同時也可以看到 controller 又做了幾次新的操作,這個 scale up 成功了。

最後,讓我們利用 delete 操作把我們剛才生成的 Deployment 給刪除掉。kubectl delete deployment,也是剛才我們本身的 deployment name,當我們把它刪除掉之後,我們今天所有的操作就完成了。

我們再去重新 get 這個 Deployment,也會顯示這個資源不再存在,這個叢集又回到了最開始乾淨的狀態。

本文總結

本文我們關注了 Kubernetes 的核心概念以及 Kubernetes 的架構設計,主要有以下內容:

  • Kubernetes 是一個自動化的容器編排平臺,它負責應用的部署、應用的彈性以及應用的管理,這些都是基於容器的;
  • Kubernetes 架構是一個比較典型的二層架構和 server-client 架構;

“ 阿里巴巴雲原生微信公眾號(ID:Alicloudnative)關注微服務、Serverless、容器、Service Mesh 等技術領域、聚焦雲原生流行技術趨勢、雲原生大規模的落地實踐,做最懂雲原生開發者的技術公眾號。”