Kubernetes中的大部分概念如Node、Pod、Replication Controller、 Service等都可以被看作一種資源物件,幾乎所有資源物件都可以通過 Kubernetes提供的kubectl工具(或者API程式設計呼叫)執行增、刪、改、查 等操作並將其儲存在etcd中持久化儲存。從這個角度來看,Kubernetes 其實是一個高度自動化的資源控制系統,它通過跟蹤對比etcd庫裡儲存 的“資源期望狀態”與當前環境中的“實際資源狀態”的差異來實現自動控制和自動糾錯的高階功能。
Kubernetes中重要的資源物件
1.1 Master
Kubernetes裡的Master指的是叢集控制節點,在每個Kubernetes叢集裡都需要有一個Master來負責整個叢集的管理和控制,基本上 Kubernetes的所有控制命令都發給它,它負責具體的執行過程,我們後面執行的所有命令基本都是在Master上執行的。Master通常會佔據一個獨立的伺服器(高可用部署建議用3臺伺服器),主要原因是它太重要了,是整個叢集的“首腦”,如果它當機或者不可用,那麼對叢集內容器應用的管理都將失效。
Master上執行著以下關鍵程式
-
Kubernetes API Server(kube-apiserver):提供了HTTP Rest介面的關鍵服務程式,是Kubernetes裡所有資源的增、刪、改、查等操作的唯一入口,也是叢集控制的入口程式。
-
Kubernetes Controller Manager(kube-controller-manager):Kubernetes裡所有資源物件的自動化控制中心,可以將其理解為資源物件的“大總管”。
-
Kubernetes Scheduler(kube-scheduler):負責資源排程(Pod排程)的程式,相當於公交公司的“排程室”。
1.2 Node
除了Master,Kubernetes叢集中的其他機器被稱為Node,在較早的 版本中也被稱為Minion。與Master一樣,Node可以是一臺物理主機,也 可以是一臺虛擬機器。Node是Kubernetes叢集中的工作負載節點,每個 Node都會被Master分配一些工作負載(Docker容器),當某個Node當機 時,其上的工作負載會被Master自動轉移到其他節點上。
每個Node上都執行著以下關鍵程式
- kubelet:負責Pod對應的容器的建立、啟停等任務,同時與 Master密切協作,實現叢集管理的基本功能。
- kube-proxy:實現Kubernetes Service的通訊與負載均衡機制的重要元件。
- Docker Engine(docker):Docker引擎,負責本機的容器建立 和管理工作。
Node可以在執行期間動態增加到Kubernetes叢集中,前提是在這個 節點上已經正確安裝、配置和啟動了上述關鍵程式,在預設情況下 kubelet會向Master註冊自己,這也是Kubernetes推薦的Node管理方式。 一旦Node被納入叢集管理範圍,kubelet程式就會定時向Master彙報自身 的情報,例如作業系統、Docker版本、機器的CPU和記憶體情況,以及當 前有哪些Pod在執行等,這樣Master就可以獲知每個Node的資源使用情 況,並實現高效均衡的資源排程策略。而某個Node在超過指定時間不上 報資訊時,會被Master判定為“失聯”,Node的狀態被標記為不可用 (Not Ready),隨後Master會觸發“工作負載大轉移”的自動流程。
從建立 deployment 開始
deployment 是用於編排 pod 的一種控制器資源,我們會在後面做介紹。這裡以 deployment 為例,來看看架構中的各元件在建立 deployment 資源的過程中都幹了什麼。
- 1.首先是 kubectl 發起一個建立 deployment 的請求
- 2.apiserver 接收到建立 deployment 請求,將相關資源寫入 etcd;之後所有元件與 apiserver/etcd 的互動都是類似的
- 3.deployment controller list/watch 資源變化併發起建立 replicaSet 請求
- 4.replicaSet controller list/watch 資源變化併發起建立 pod 請求
- 5.scheduler 檢測到未繫結的 pod 資源,通過一系列匹配以及過濾選擇合適的 node 進行繫結
- 6.kubelet 發現自己 node 上需建立新 pod,負責 pod 的建立及後續生命週期管理
- 7.kube-proxy 負責初始化 service 相關的資源,包括服務發現、負載均衡等網路規則
至此,經過 kubenetes 各元件的分工協調,完成了從建立一個 deployment 請求開始到具體各 pod 正常執行的全過程。
Pod
在 kubernetes 眾多的 api 資源中,pod 是最重要和基礎的,是最小的部署單元。
首先我們要考慮的問題是,我們為什麼需要 pod?pod 可以說是一種容器設計模式,它為那些”超親密”關係的容器而設計,我們可以想象 servelet 容器部署 war 包、日誌收集等場景,這些容器之間往往需要共享網路、共享儲存、共享配置,因此我們有了 pod 這個概念。
對於 pod 來說,不同 container 之間通過 infra container 的方式統一識別外部網路空間,而通過掛載同一份 volume 就自然可以共享儲存了,比如它對應宿主機上的一個目錄。
容器編排
容器編排是 kubernetes 的看家本領了,所以我們有必要了解一下。kubernetes 中有諸多編排相關的控制資源,例如編排無狀態應用的 deployment,編排有狀態應用的 statefulset,編排守護程式 daemonset 以及編排離線業務的 job/cronjob 等等。
我們還是以應用最廣泛的 deployment 為例。deployment、replicatset、pod 之間的關係是一種層層控制的關係。簡單來說,replicaset 控制 pod 的數量,而 deployment 控制 replicaset 的版本屬性。這種設計模式也為兩種最基本的編排動作實現了基礎,即數量控制的水平擴縮容、版本屬性控制的更新/回滾。
水平擴縮容
水平擴縮容非常好理解,我們只需修改 replicaset 控制的 pod 副本數量即可,比如從 2 改到 3,那麼就完成了水平擴容這個動作,反之即水平收縮。
滾動更新
我們更新應用,pod 總是一個一個升級,並且最小有 2 個 pod 處於可用狀態,最多有 4 個 pod 提供服務。這種”滾動更新”的好處是顯而易見的,一旦新的版本有了 bug,那麼剩下的 2 個 pod 仍然能夠提供服務,同時方便快速回滾。
在實際應用中我們可以通過配置 RollingUpdateStrategy 來控制滾動更新策略,maxSurge 表示 deployment 控制器還可以建立多少個新 Pod;而 maxUnavailable 指的是,deployment 控制器可以刪除多少箇舊 Pod。
kubernetes 中的網路
我們瞭解了容器編排是怎麼完成的,那麼容器間的又是怎麼通訊的呢?
講到網路通訊,kubernetes 首先得有”三通”基礎:
- node 到 pod 之間可以通
- node 的 pod 之間可以通
- 不同 node 之間的 pod 可以通
簡單來說,不同 pod 之間通過 cni0/docker0 網橋實現了通訊,node 訪問 pod 也是通過 cni0/docker0 網橋通訊即可。
而不同 node 之間的 pod 通訊有很多種實現方案,包括現在比較普遍的 flannel 的 vxlan/hostgw 模式等。flannel 通過 etcd 獲知其他 node 的網路資訊,並會為本 node 建立路由表,最終使得不同 node 間可以實現跨主機通訊。
微服務—service
在瞭解接下來的內容之前,我們得先了解一個很重要的資源物件:service。
我們為什麼需要 service 呢?在微服務中,pod 可以對應例項,那麼 service 對應的就是一個微服務。而在服務呼叫過程中,service 的出現解決了兩個問題:
- pod 的 ip 不是固定的,利用非固定 ip 進行網路呼叫不現實
- 服務呼叫需要對不同 pod 進行負載均衡
service 通過 label 選擇器選取合適的 pod,構建出一個 endpoints,即 pod 負載均衡列表。實際運用中,一般我們會為同一個微服務的 pod 例項都打上類似app=xxx的標籤,同時為該微服務建立一個標籤選擇器為app=xxx的 service。
kubernetes 中的服務發現與網路呼叫
在有了上述”三通”的網路基礎後,我們可以開始微服務架構中的網路呼叫在 kubernetes 中是怎麼實現的了。
這部分內容其實在說說 Kubernetes 是怎麼實現服務發現的已經講得比較清楚了,比較細節的地方可以參考上述文章,這裡做一個簡單的介紹。
服務間呼叫
首先是東西向的流量呼叫,即服務間呼叫。這部分主要包括兩種呼叫方式,即 clusterIp 模式以及 dns 模式。
clusterIp 是 service 的一種型別,在這種型別模式下,kube-proxy 通過 iptables/ipvs 為 service 實現了一種 VIP(虛擬 ip)的形式。只需要訪問該 VIP,即可負載均衡地訪問到 service 背後的 pod。
上圖是 clusterIp 的一種實現方式,此外還包括 userSpace 代理模式(基本不用),以及 ipvs 模式(效能更好)。
dns 模式很好理解,對 clusterIp 模式的 service 來說,它有一個 A 記錄是 service-name.namespace-name.svc.cluster.local,指向 clusterIp 地址。所以一般使用過程中,我們直接呼叫 service-name 即可。
服務外訪問
南北向的流量,即外部請求訪問 kubernetes 叢集,主要包括三種方式:nodePort、loadbalancer、ingress。
nodePort 同樣是 service 的一種型別,通過 iptables 賦予了呼叫宿主機上的特定 port 就能訪問到背後 service 的能力。
loadbalancer 則是另一種 service 型別,通過公有云提供的負載均衡器實現。
我們訪問 100 個服務可能需要建立 100 個 nodePort/loadbalancer。我們希望通過一個統一的外部接入層訪問內部 kubernetes 叢集,這就是 ingress 的功能。ingress 提供了統一接入層,通過路由規則的不同匹配到後端不同的 service 上。ingress 可以看做是”service 的 service”。ingress 在實現上往往結合 nodePort 以及 loadbalancer 完成功能。