1. 程式人生 > 其它 >k8s架構詳解

k8s架構詳解

每個微服務通過 Docker 進行釋出,隨著業務的發展,系統中遍佈著各種各樣的容器。於是,容器的資源排程,部署執行,擴容縮容就是我們要面臨的問題。

基於 Kubernetes 作為容器叢集的管理平臺被廣泛應用,今天我們一起來看看 Kubernetes 的架構中有那些常用的元件以及執行原理。

Kubernetes 架構概述

Kubernetes 是用來管理容器叢集的平臺。既然是管理叢集,那麼就存在被管理節點,針對每個 Kubernetes 叢集都由一個 Master 負責管理和控制叢集節點。

我們通過 Master 對每個節點 Node 傳送命令。簡單來說,Master 就是管理者,Node 就是被管理者。

Node 可以是一臺機器或者一臺虛擬機器。在 Node 上面可以執行多個 Pod,Pod 是 Kubernetes 管理的最小單位,同時每個 Pod 可以包含多個容器(Docker)。

通過下面的 Kubernetes 架構簡圖可以看到 Master 和 Node 之間的關係:

通常我們都是通過 kubectl 對 Kubernetes 下命令的,它通過 APIServer 去呼叫各個程序來完成對 Node 的部署和控制。

APIServer 的核心功能是對核心物件(例如:Pod,Service,RC)的增刪改查操作,同時也是叢集內模組之間資料交換的樞紐。

它包括了常用的 API,訪問(許可權)控制,註冊,資訊儲存(etcd)等功能。在它的下面我們可以看到 Scheduler,它將待排程的 Pod 繫結到 Node 上,並將繫結資訊寫入 etcd 中。

etcd 包含在 APIServer 中,用來儲存資源資訊。接下來就是 Controller Manager 了,如果說 Kubernetes 是一個自動化執行的系統,那麼就需要有一套管理規則來控制這套系統。

Controller Manager 就是這個管理者,或者說是控制者。它包括 8 個 Controller,分別對應著副本,節點,資源,名稱空間,服務等等。

緊接著,Scheduler 會把 Pod 排程到 Node 上,排程完以後就由 kubelet 來管理 Node 了。

kubelet 用於處理 Master 下發到 Node 的任務(即 Scheduler 的排程任務),同時管理 Pod 及 Pod 中的容器。

在完成資源排程以後,kubelet 程序也會在 APIServer 上註冊 Node 資訊,定期向 Master 彙報 Node 資訊,並通過 cAdvisor 監控容器和節點資源。

由於,微服務的部署都是分散式的,所以對應的 Pod 以及容器的部署也是。為了能夠方便地找到這些 Pod 或者容器,引入了 Service(kube-proxy)程序,它來負責反向代理和負載均衡的實施。

上面就是 Kubernetes 架構的簡易說明,涉及到了一些核心概念以及簡單的資訊流動。

將一些功能收錄到了 APIServer 中,這個簡圖比官網的圖顯得簡單一些,主要是方便大家記憶。

後面我們會用一個簡單的例子,帶大家把 Kubernetes 的概念的由來做深入的瞭解。

從一個例子開始

假設使用 Kubernetes 部署 Tomcat 和 MySQL 服務到兩個 Node 上面。其中 Tomcat 服務生成兩個例項也就是生成兩個 Pod,用來對其做水平擴充套件。

MySQL 只部署一個例項,也就是一個 Pod。可以通過外網訪問 Tomcat,而 Tomcat 可以在內網訪問 MySQL。

這裡我們假設 Kubernetes 和 Docker 的安裝都已經完成,並且映象檔案都已經準備好了。重點看 Kubernetes 如何部署和管理容器。

kubectl和 APIServer

既然我們要完成上面的例子,接下來就要部署兩個應用。

首先,根據要部署的應用建立 Replication Controller(RC)。RC 是用來宣告應用副本的個數,也就是 Pod 的個數。

按照上面的例子,Tomcat 的 RC 就是 2,MySQL 的 RC 就是 1。

由於 kubectl 作為使用者介面向 Kubernetes 下發指令,那麼指令是通過“.yaml”的配置檔案編寫的。

定義 mysql-rc.yaml 的配置檔案來描述 MySQL 的 RC:
 1 apiVersion: V1
 2 kind: ReplicationController
 3 metadata:
 4  name: mysql#RC的名稱,全域性唯一
 5 spec:
 6  replicas:1 #Pod 副本的期待數量
 7 selector :
 8 app: mysql
 9  template: #Pod模版,用這個模版來建立Pod
10 metadata:
11  labels:
12 app:mysql#Pod副本的標籤
13 spec:
14  containers:#容器定義部分
15      -name:mysql
16 Image:mysql#容器對應的DockerImage
17       Ports:
18       -containerPort:3306#容器應用監聽的埠號
19       Env:#注入容器的環境變數
20       -name:MYSQL_ROOT_PASSWORD
21       Value:”123456


從上面的配置檔案可以看出,需要對這個 RC 定義一個名字,以及期望的副本數,以及容器中的映象檔案。然後通過 kubectl 作為客戶端的 cli 工具,執行這個配置檔案。

通過 kubectl 執行 RC 配置檔案

執行了上面的命令以後,Kubernetes 會幫助我們部署副本 MySQL 的 Pod 到 Node。

此時先不著急看結果,回到最開始的架構圖,可以看到 kubectl 會向 Master 中的 APIServer 發起命令,看看 APIServer 的結構和資訊的傳遞吧。

Kubernetes API Server 通過一個名為 kube-apiserver 的程序提供服務,該程序執行在 Master 上。

可以通過 Master 的 8080 埠訪問 kube-apiserver 程序,它提供 REST 服務。

因此可以通過命令列工具 kubectl 來與 Kubernetes APIServer 互動,它們之間的介面是 RESTful API。

APIServer 的架構從上到下分為四層:

  • API 層:主要以 REST 方式提供各種 API 介面,針對 Kubernetes 資源物件的 CRUD 和 Watch 等主要 API,還有健康檢查、UI、日誌、效能指標等運維監控相關的 API。

  • 訪問控制層:負責身份鑑權,核准使用者對資源的訪問許可權,設定訪問邏輯(Admission Control)。

  • 登錄檔層:選擇要訪問的資源物件。PS:Kubernetes 把所有資源物件都儲存在登錄檔(Registry)中,例如:Pod,Service,Deployment 等等。

  • etcd 資料庫:儲存建立副本的資訊。用來持久化 Kubernetes 資源物件的 Key-Value 資料庫。

當 kubectl 用 Create 命令建立 Pod 時,是通過 APIServer 中的 API 層呼叫對應的 RESTAPI 方法。

之後會進入許可權控制層,通過 Authentication 獲取呼叫者身份,Authorization 獲取許可權資訊。

AdmissionControl 中可配置許可權認證外掛,通過外掛來檢查請求約束。例如:啟動容器之前需要下載映象,或者檢查具備某名稱空間的資源。

還記得 mysql-rc.yaml 中配置需要生成的 Pod 的個數為 1。到了 Registry 層會從 CoreRegistry 資源中取出 1 個 Pod 作為要建立的 Kubernetes 資源物件。

然後將 Node,Pod 和 Container 資訊儲存在 etcd 中去。這裡的 etcd 可以是一個叢集,由於裡面儲存叢集中各個 Node/Pod/Container 的資訊,所以必要時需要備份,或者保證其可靠性。

Controller Manager,Scheduler 和 kubelet

前面通過 kubectl 根據配置檔案,向 APIServer 傳送命令,在 Node 上面建立 Pod 和 Container。

在 APIServer,經過 API 呼叫,許可權控制,呼叫資源和儲存資源的過程。實際上還沒有真正開始部署應用。

這裡需要 Controller Manager,Scheduler 和 kubelet 的協助才能完成整個部署過程。

在介紹他們協同工作之前,要介紹一下在 Kubernetes 中的監聽介面。從上面的操作知道,所有部署的資訊都會寫到 etcd 中儲存。

實際上 etcd 在儲存部署資訊的時候,會發送 Create 事件給 APIServer,而 APIServer 會通過監聽(Watch)etcd 發過來的事件。其他元件也會監聽(Watch)APIServer 發出來的事件。

Kubernetes 就是用這種 List-Watch 的機制保持資料同步的,如上圖:

  • 這裡有三個 List-Watch,分別是 kube-controller-manager(執行在Master),kube-scheduler(執行在 Master),kublete(執行在 Node)。他們在程序已啟動就會監聽(Watch)APIServer 發出來的事件。

  • kubectl 通過命令列,在 APIServer 上建立一個 Pod 副本。

  • 這個部署請求被記錄到 etcd 中,儲存起來。

  • 當 etcd 接受建立 Pod 資訊以後,會發送一個 Create 事件給 APIServer。

  • 由於 Kubecontrollermanager 一直在監聽 APIServer 中的事件。此時 APIServer 接受到了 Create 事件,又會發送給 Kubecontrollermanager。

  • Kubecontrollermanager 在接到 Create 事件以後,呼叫其中的 Replication Controller 來保證 Node 上面需要建立的副本數量。

    上面的例子 MySQL 應用是 1 個副本,Tomcat 應用是兩個副本。一旦副本數量少於 RC 中定義的數量,Replication Controller 會自動建立副本。總之它是保證副本數量的 Controller。PS:擴容縮容的擔當。

  • 在 Controller Manager 建立 Pod 副本以後,APIServer 會在 etcd 中記錄這個 Pod 的詳細資訊。例如在 Pod 的副本數,Container 的內容是什麼。

  • 同樣的 etcd 會將建立 Pod 的資訊通過事件傳送給 APIServer。

  • 由於 Scheduler 在監聽(Watch)APIServer,並且它在系統中起到了“承上啟下”的作用

    “承上”是指它負責接收建立的 Pod 事件,為其安排 Node;“啟下”是指安置工作完成後,Node 上的 kubelet 服務程序接管後繼工作,負責 Pod 生命週期中的“下半生”。

    換句話說,Scheduler 的作用是將待排程的 Pod 按照排程演算法和策略繫結到叢集中 Node 上,並將繫結資訊寫入 etcd 中。

  • Scheduler 排程完畢以後會更新 Pod 的資訊,此時的資訊更加豐富了。除了知道 Pod 的副本數量,副本內容。還知道部署到哪個 Node 上面了。

  • 同樣,將上面的 Pod 資訊更新到 etcd 中,儲存起來。

  • etcd 將更新成功的事件傳送給 APIServer。

  • 注意這裡的 kubelet 是在 Node 上面執行的程序,它也通過 List-Watch 的方式監聽(Watch)APIServer 傳送的 Pod 更新的事件。

    實際上,在第 9 步的時候建立 Pod 的工作就已經完成了。

    為什麼 kubelete 還要一直監聽呢?

    原因很簡單,假設這個時候 kubectl 發命令,需要把原來的 MySQL 的 1 個 RC 副本擴充成 2 個。那麼這個流程又會觸發一遍。

    作為 Node 的管理者 kubelet 也會根據最新的 Pod 的部署情況調整 Node 端的資源。

    又或者 MySQL 應用的 RC 個數沒有發生變化,但是其中的映象檔案升級了,kubelet 也會自動獲取最新的映象檔案並且載入。

通過上面 List-Watch 的介紹大家發現了,除了之前引入的 kubectl 和 APIServer 以外又引入了 Controller Manager,Scheduler 和 kubelet。 這裡給大家介紹一下他們的作用和原理:

Controller Manager

Kubernetes 需要管理叢集中的不同資源,所以針對不同的資源要建立不同的 Controller。 每個 Controller 通過監聽機制獲取 APIServer 中的事件(訊息),它們通過 API Server 提供的(List-Watch)介面監控叢集中的資源,並且調整資源的狀態。 可以把它想象成一個盡職的管理者,隨時管理和調整資源。比如 MySQL 所在的 Node 意外宕機了,Controller Manager 中的 Node Controller 會及時發現故障,並執行修復流程。 在部署了成百上千微服務的系統中,這個功能極大地協助了運維人員。從此可以看出,Controller Manager 是 Kubernetes 資源的管理者,是運維自動化的核心。

它分為 8 個 Controller,上面我們介紹了 Replication Controller,這裡我們把其他幾個都列出來,就不展開描述了。

Controller Manager

Kubernetes 需要管理叢集中的不同資源,所以針對不同的資源要建立不同的 Controller。 每個 Controller 通過監聽機制獲取 APIServer 中的事件(訊息),它們通過 API Server 提供的(List-Watch)介面監控叢集中的資源,並且調整資源的狀態。 可以把它想象成一個盡職的管理者,隨時管理和調整資源。比如 MySQL 所在的 Node 意外宕機了,Controller Manager 中的 Node Controller 會及時發現故障,並執行修復流程。 在部署了成百上千微服務的系統中,這個功能極大地協助了運維人員。從此可以看出,Controller Manager 是 Kubernetes 資源的管理者,是運維自動化的核心。

它分為 8 個 Controller,上面我們介紹了 Replication Controller,這裡我們把其他幾個都列出來,就不展開描述了。

ControllerManager中不同的 Controller 負責對不同資源的監控和管理

Scheduler 與 kubelet

Scheduler 的作用是,將待排程的 Pod 按照演算法和策略繫結到 Node 上,同時將資訊儲存在 etcd 中。 如果把 Scheduler 比作排程室,那麼這三件事就是它需要關注的,待排程的 Pod、可用的 Node,排程演算法和策略。 簡單地說,就是通過排程演算法/策略把 Pod 放到合適的 Node 中去。此時 Node 上的 kubelet 通過 APIServer 監聽到 Scheduler 產生的 Pod 繫結事件,然後通過 Pod 的描述裝載映象檔案,並且啟動容器。 也就是說 Scheduler 負責思考,Pod 放在哪個 Node,然後將決策告訴 kubelet,kubelet 完成 Pod 在 Node 的載入工作。

說白了,Scheduler 是 boss,kubelet 是幹活的工人,他們都通過 APIServer 進行資訊交換。

Scheduler 與 kubelet 協同工作圖

Service 和kubelet

經歷上面一系列的過程,終於將 Pod 和容器部署到 Node 上了。

MySQL 部署成功 作為部署在 Kubernetes 中,Pod 如何訪問其他的 Pod 呢?答案是通過 Kubernetes 的 Service 機制。 在 Kubernetes 中的 Service 定義了一個服務的訪問入口地址(IP+Port)。Pod 中的應用通過這個地址訪問一個或者一組 Pod 副本。

Service 與後端 Pod 副本叢集之間是通過 Label Selector 來實現連線的。Service 所訪問的這一組 Pod 都會有同樣的 Label,通過這樣的方法知道這些 Pod 屬於同一個組。

Pod 通過Service 訪問其他 Pod

寫 MySQL 服務的配置檔案(mysql-svc.yaml)如下:

1 apiVersion : v1
2 kind: Service #說明建立資源物件的型別是Service
3 metadata:
4  name: mysql#Service全域性唯一名稱
5 spec:
6 prots:
7 -port: 3306#Service的服務埠號
8  selector:#Service對應的Pod標籤,用來給Pod分類
9    app: mysql

按照慣例執行 kubectl,建立 Service:

再用 getsvc 命令檢查 Service 資訊:

這裡的 Cluster-IP 169.169.253.143 是由 Kubernetes 自動分配的。當一個 Pod 需要訪問其他的 Pod 的時候就需要通過 Service 的 Cluster-IP 和 Port。 也就是說 Cluster-IP 和 Port 是 Kubernetes 叢集的內部地址,是提供給叢集內的 Pod 之間訪問使用的,外部系統是無法通過這個 Cluster-IP 來訪問 Kubernetes 中的應用的。 上面提到的 Service 只是一個概念,而真正將 Service 落實的是 kube-proxy。 只有理解了 kube-proxy 的原理和機制,我們才能真正理解 Service 背後的實現邏輯。 在 Kubernetes 叢集的每個 Node 上都會執行一個 kube-proxy 服務程序,我們可以把這個程序看作 Service 的負載均衡器,其核心功能是將到 Service 的請求轉發到後端的多個 Pod 上。 此外,Service 的 Cluster-IP 與 NodePort 是 kube-proxy 服務通過 iptables 的 NAT 轉換實現的。kube-proxy 在執行過程中動態建立與 Service 相關的 iptables 規則。 由於 iptables 機制針對的是本地的 kube-proxy 埠,所以在每個 Node 上都要執行 kube-proxy 元件。

因此在 Kubernetes 叢集內部,可以在任意 Node 上發起對 Service 的訪問請求。

叢集內部通過 kube-proxy(Service)訪問其他Pod 正如 MySQL 服務,可以被 Kubernetes 內部的 Tomcat 呼叫,那麼 Tomcat 如何被 Kubernetes 外部呼叫?

先生成配置檔案,myweb-rc.yaml 看看:

 1 apiVersion: V1
 2 kind: ReplicationController
 3 metadata:
 4  name: myweb#RC的名稱,全域性唯一
 5 spec:
 6  replicas:2#Pod 副本的期待數量,這裡的數量是2,需要建立兩個Tomcat的副本
 7 selector :
 8 app: myweb
 9  template: #Pod模版,用這個模版來建立Pod
10 metadata:
11  labels:
12 app:myweb#Pod副本的標籤
13 spec:
14  containers: #容器定義部分
15      -name:mysql
16 Image:kubeguide/tomcat-app:v1#容器對應的DockerImage
17       Ports:
18       -containerPort:8080#容器應用監聽的埠號

在 kubectl 中使用 Create 建立 myweb 副本。

副本建立完畢以後,建立對應的服務配置檔案 myweb-svc.yaml。

 1 apiVersion : v1
 2 kind: Service #說明建立資源物件的型別是Service
 3 metadata:
 4  name: myweb#Service全域性唯一名稱
 5 spec:
 6 prots:
 7 -port: 8080#Service的服務埠號
 8 nodePort: 30001#這個就是外網訪問Kubernetes內部應用的埠。
 9  selector: #Service對應的Pod標籤,用來給Pod分類
10    app: myweb

同樣在 kubectl 中執行 Create 命令,建立 Service 資源。

從上面的配置檔案可以看出,Tomcat 的 Service 中多了一個 nodePort 的配置,值為 30001。 也就是說外網通過 30001 這個埠加上 NodeIP 就可以訪問 Tomcat 了。 執行命令之後,得到一個提示,大致意思是“如果你要將服務暴露給外網使用,你需要設定防火牆規則讓 30001 埠能夠通行。” 由於 Cluster-IP 是一個虛擬的 IP,僅供 Kubernetes 內部的 Pod 之間的通訊。 Node 作為一個物理節點,因此需要使用 Node-IP 和 nodePort 的組合來從 Kubernetes 外面訪問內部的應用。

如果按照上面的配置,部署了兩個 Tomcat 應用,當外網訪問時選擇那個 Pod 呢?這裡需要通過 Kubernetes 之外的負載均衡器來實現的。

Kubernetes 之外的負載均衡器 可以通過 Kubernetes 的 LoadBlancerService 元件來協助實現。通過雲平臺申請建立負載均衡器,向外暴露服務。 目前 LoadBlancerService 元件支援的雲平臺比較完善,比如國外的 GCE、DigitalOcean,國內的阿里雲,私有云 OpenStack 等等。 從用法上只要把 Service 的 type=NodePort 改為 type=LoadBalancer,Kubernetes 就會自動建立一個對應的 Load Balancer 例項並返回它的 IP 地址供外部客戶端使用。

至此,MySQL(RC 1)和 Tomcat(RC 2)已經在 Kubernetes 部署了。並在 Kubernetes 內部 Pod 之間是可以互相訪問的,在外網也可以訪問到 Kubernetes 內部的 Pod。

Pod在 Kubernetes 內互相訪問,外網訪問 Pod 另外,作為資源監控 Kubernetes 在每個 Node 和容器上都運行了 cAdvisor。它是用來分析資源使用率和效能的工具,支援 Docker 容器。 kubelet 通過 cAdvisor 獲取其所在 Node 及容器(Docker)的資料。cAdvisor 自動採集 CPU、記憶體、檔案系統和網路使用的統計資訊。 kubelet 作為 Node 的管理者,把 cAdvisor 採集上來的資料通過 RESTAPI 的形式暴露給 Kubernetes 的其他資源,讓他們知道 Node/Pod 中的資源使用情況。

總結

由於微服務的迅猛發展,Kubernetes 作為微服務治理平臺被廣泛應用。由於其發展時間長,包含服務功能多我們無法一一列出。 因此,從一個簡單的建立應用副本的例子入手,介紹了各個重要元件的概念和基本原理。 Kubernetes 是用來管理容器叢集的,Master 作為管理者,包括 APIServer,Scheduler,Controller Manager。 Node作為副本部署的載體,包含多個 Pod,每個 Pod 又包含多個容器(container)。使用者通過 kubectl 給 Master 中的 APIServer 下部署命令。 命令主體是以“.yaml”結尾的配置檔案,包含副本的型別,副本個數,名稱,埠,模版等資訊。 APIServer 接受到請求以後,會分別進行以下操作:許可權驗證(包括特殊控制),取出需要建立的資源,儲存副本資訊到etcd。 APIServer 和 Controller Manager,Scheduler 以及 kubelete 之間通過 List-Watch 方式通訊(事件傳送與監聽)。 Controller Manager 通過 etcd 獲取需要建立資源的副本數,交由 Scheduler 進行策略分析。 最後 kubelet 負責最終的 Pod 建立和容器載入。部署好容器以後,通過 Service 進行訪問,通過 cAdvisor 監控資源。