目錄
- 一、看圖說K8S
- 二、K8S的概念和術語
- 三、K8S集群組件
- 1、Master組件
- 2、Node組件
- 3、核心附件
- 四、K8S的網絡模型
- 五、Kubernetes的核心對象詳解
- 1、Pod資源對象
- 2、Controller
- 3、Service
一、看圖說K8S
先從一張大圖來觀看一下K8S是如何運作的,再具體去細化K8S的概念、組件以及網絡模型。
從上圖,我們可以看到K8S組件和邏輯及其復雜,但是這並不可怕,我們從宏觀上先了解K8S是怎么用的,再進行庖丁解牛。從上圖我們可以看出:
- Kubernetes集群主要由Master和Node兩類節點組成
- Master的組件包括:apiserver、controller-manager、scheduler和etcd等幾個組件,其中apiserver是整個集群的網關。
- Node主要由kubelet、kube-proxy、docker引擎等組件組成。kubelet是K8S集群的工作與節點上的代理組件。
- 一個完整的K8S集群,還包括CoreDNS、Prometheus(或HeapSter)、Dashboard、Ingress Controller等幾個附加組件。其中cAdivsor組件作用於各個節點(master和node節點)之上,用於收集及收集容器及節點的CPU、內存以及磁盤資源的利用率指標數據,這些統計數據由Heapster聚合后,可以通過apiserver訪問。
要了解K8S的所有組件,沒去走一遍,永遠不知道它是怎么跑起來的,那么下面就帶着幾個新手疑問來看K8S
- 1、K8S是如何對容器編排?
在K8S集群中,容器並非最小的單位,K8S集群中最小的調度單位是Pod,容器則被封裝在Pod之中。由此可知,一個容器或多個容器可以同屬於在一個Pod之中。
- 2、Pod是怎么創建出來的?
Pod並不是無緣無故跑出來的,它是一個抽象的l邏輯概念,那么Pod是如何創建的呢?Pod是由Pod控制器進行管理控制,其代表性的Pod控制器有Deployment、StatefulSet等。這里我們先有這樣的一個概念,后面再詳細解刨。
- 3、Pod資源組成的應用如何提供外部訪問的?
Pod組成的應用是通過Service這類抽象資源提供內部和外部訪問的,但是service的外部訪問需要端口的映射,帶來的是端口映射的麻煩和操作的繁瑣。為此還有一種提供外部訪問的資源叫做Ingress。
- 4、Service又是怎么關聯到Pod呢?
在上面說的Pod是由Pod控制器進行管理控制,對Pod資源對象的期望狀態進行自動管理。而在Pod控制器是通過一個YAML的文件進行定義Pod資源對象的。在該文件中,還會對Pod資源對象進行打標簽,用於Pod的辨識,而Servcie就是通過標簽選擇器,關聯至同一標簽類型的Pod資源對象。這樣就實現了從service-->pod-->container的一個過程。
- 5、Pod的怎么創建邏輯流程是怎樣的?
- (1)客戶端提交創建請求,可以通過API Server的Restful API,也可以使用kubectl命令行工具。支持的數據類型包括JSON和YAML。
- (2)API Server處理用戶請求,存儲Pod數據到etcd。
- (3)調度器通過API Server查看未綁定的Pod。嘗試為Pod分配主機。
- (4)過濾主機 (調度預選):調度器用一組規則過濾掉不符合要求的主機。比如Pod指定了所需要的資源量,那么可用資源比Pod需要的資源量少的主機會被過濾掉。
- (5)主機打分(調度優選):對第一步篩選出的符合要求的主機進行打分,在主機打分階段,調度器會考慮一些整體優化策略,比如把容一個Replication Controller的副本分布到不同的主機上,使用最低負載的主機等。
- (6)選擇主機:選擇打分最高的主機,進行binding操作,結果存儲到etcd中。
- (7)kubelet根據調度結果執行Pod創建操作: 綁定成功后,scheduler會調用APIServer的API在etcd中創建一個boundpod對象,描述在一個工作節點上綁定運行的所有pod信息。運行在每個工作節點上的kubelet也會定期與etcd同步boundpod信息,一旦發現應該在該工作節點上運行的boundpod對象沒有更新,則調用Docker API創建並啟動pod內的容器。
從上面的幾個疑問,大致了解了K8S怎么工作的,那么現在再從三個面去了解Kubernetes,分別是Kubernetes概念和術語、集群組件、網絡模型。
二、K8S的概念和術語
Kubernetes是利用共享網絡將多個物理機或者虛擬機組成一個集群,在各個服務器之間進行通信,該集群是配置Kubernetes的所有租金啊啊、功能和負載的物理平台。
一個Kubernetes集群由master和node組成。如下圖:
- Master:是集群的網關和中樞樞紐,主要作用:暴露API接口,跟蹤其他服務器的健康狀態、以最優方式調度負載,以及編排其他組件之間的通信。單個的Master節點可以完成所有的功能,但是考慮單點故障的痛點,生產環境中通常要部署多個Master節點,組成Cluster。
- Node:是Kubernetes的工作節點,負責接收來自Master的工作指令,並根據指令相應地創建和銷毀Pod對象,以及調整網絡規則進行合理路由和流量轉發。生產環境中,Node節點可以有N個。
Kubernetes從宏觀上看分為2個角色:Master和Node,但是在Master節點和Node節點上都存在着多個組件來支持內部的業務邏輯,其包括:運行應用、應用編排、服務暴露、應用恢復等等,在Kubernetes中這些概念被抽象為Pod、Service、Controller等資源類型。先來了解一下這些常用概念和術語:
(1)Pod
從上圖,我們可以看到K8S並不直接地運行容器,而是被一個抽象的資源對象--Pod所封裝,它是K8S最小的調度單位。這里要注意的是,Pod可以封裝一個活多個容器!同一個Pod中共享網絡名稱空間和存儲資源,而容器之間可以通過本地回環接口:lo 直接通信,但是彼此之間又在Mount、User和Pid等名稱空間上保持了隔離。
(2)資源標簽(Label)
標簽(Label)是將資源進行分類的標識符,就好像超市的商品分類一般。資源標簽具體化的就是一個鍵值型(key/values)數據,相信了解redis的友友應該知道什么是鍵值數據。使用標簽是為了對指定對象進行辨識,比如Pod對象。標簽可以在對象創建時進行附加,也可以創建后進行添加或修改。要知道的是一個對象可以有多個標簽,一個標簽頁可以附加到多個對象。如圖:
(3)標簽選擇器(Selector)
有標簽,當然就有標簽選擇器,它是根據Label進行過濾符合條件的資源對象的一種 機制。比如將含有標簽
role: backend
的所有Pod對象挑選出來歸並為一組。通常在使用過程中,會通過標簽對資源對象進行分類,然后再通過標簽選擇器進行篩選,最常見的應用就是講一組這樣的Pod資源對象創建為某個Service的端點。如圖:
(4)Pod控制器(Controller)
雖然Pod是K8S的最小調度單位,但是K8S並不會直接地部署和管理Pod對象,而是要借助於另外一個抽象資源--Controller進行管理。其實一種管理Pod生命周期的資源抽象,並且它是一類對象,並非單個的資源對象,其中包括:ReplicationController、ReplicaSet、Deployment、StatefulSet、Job等。
以Deployment為例,它負責確保定義的Pod對象的副本數量符合預期的設置,這樣用戶只需要聲明應用的期望狀態,控制器就會自動地對其進行管理。如圖:
- (5)服務資源(Service)
Service是建立在一組Pod對象之上的資源對象,在前面提過,它是通過標簽選擇器選擇一組Pod對象,並為這組Pod對象定義一個統一的固定訪問入口(通常是一個IP地址),如果K8S存在DNS附件(如coredns)它就會在Service創建時為它自動配置一個DNS名稱,用於客戶端進行服務發現。
通常我們直接請求Service IP,該請求就會被負載均衡到后端的端點,即各個Pod對象,從這點上,是不是有點像負載均衡器呢,因此Service本質上是一個4層的代理服務,另外Service還可以將集群外部流量引入至集群,這就需要節點對Service的端口進行映射了。
- (6)存儲卷(Volume)
在使用容器時,我們知道,當數據存放於容器之中,容器銷毀后,數據也會隨之丟失。這就是需要一個外部存儲,以保證數據的持久化存儲。而存儲卷就是這樣的一個東西。
存儲卷(Volume)是獨立於容器文件系統之外的存儲空間,常用於擴展容器的存儲空間並為其提供持久存儲能力。存儲卷在K8S中的分類為:臨時卷、本地卷和網絡卷。臨時卷和本地卷都位於Node本地,一旦Pod被調度至其他Node節點,此類型的存儲卷將無法被訪問,因為臨時卷和本地卷通常用於數據緩存,持久化的數據通常放置於持久卷(persistent volume)之中。
- (7)Name和Namespace
名稱(Name)是K8S集群中資源對象的標識符,通常作用於名稱空間(Namespace),因此名稱空間是名稱的額外的限定機制。在同一個名稱空間中,同一類型資源對象的名稱必須具有唯一性。
名稱空間通常用於實現租戶或項目的資源隔離,從而形成邏輯分組。關於此概念可以參考:https://www.jb51.net/article/136411.htm
如圖:創建的Pod和Service等資源對象都屬於名稱空間級別,未指定時,都屬於默認的名稱空間
default
- (8)注解(Annotation)
Annotation是另一種附加在對象上的一種鍵值類型的數據,常用於將各種非標識型元數據(metadata)附加到對象上,但它並不能用於標識和選擇對象。其作用是方便工具或用戶閱讀及查找。
- (9)Ingress
K8S將Pod對象和外部的網絡環境進行了隔離,Pod和Service等對象之間的通信需要通過內部的專用地址進行,如果需要將某些Pod對象提供給外部用戶訪問,則需要給這些Pod對象打開一個端口進行引入外部流量,除了Service以外,Ingress也是實現提供外部訪問的一種方式。
三、K8S集群組件
1、Master組件
- 1、API Server
K8S對外的唯一接口,提供HTTP/HTTPS RESTful API,即kubernetes API。所有的請求都需要經過這個接口進行通信。主要負責接收、校驗並響應所有的REST請求,結果狀態被持久存儲在etcd當中,所有資源增刪改查的唯一入口。
- 2、etcd
負責保存k8s 集群的配置信息和各種資源的狀態信息,當數據發生變化時,etcd會快速地通知k8s相關組件。etcd是一個獨立的服務組件,並不隸屬於K8S集群。生產環境當中etcd應該以集群方式運行,以確保服務的可用性。
etcd不僅僅用於提供鍵值數據存儲,而且還為其提供了監聽(watch)機制,用於監聽和推送變更。在K8S集群系統中,etcd的鍵值發生變化會通知倒API Server,並由其通過watch API向客戶端輸出。
- 3、Controller Manager
負責管理集群各種資源,保證資源處於預期的狀態。Controller Manager由多種controller組成,包括replication controller、endpoints controller、namespace controller、serviceaccounts controller等 。由控制器完成的主要功能主要包括生命周期功能和API業務邏輯,具體如下:
- 生命周期功能:包括Namespace創建和生命周期、Event垃圾回收、Pod終止相關的垃圾回收、級聯垃圾回收及Node垃圾回收等。
- API業務邏輯:例如,由ReplicaSet執行的Pod擴展等。
- 4、調度器(Schedule)
資源調度,負責決定將Pod放到哪個Node上運行。Scheduler在調度時會對集群的結構進行分析,當前各個節點的負載,以及應用對高可用、性能等方面的需求。
2、Node組件
Node主要負責提供容器的各種依賴環境,並接受Master管理。每個Node有以下幾個組件構成。
- 1、Kubelet
kubelet是node的agent,當Scheduler確定在某個Node上運行Pod后,會將Pod的具體配置信息(image、volume等)發送給該節點的kubelet,kubelet會根據這些信息創建和運行容器,並向master報告運行狀態。
- 2、Container Runtime
每個Node都需要提供一個容器運行時(Container Runtime)環境,它負責下載鏡像並運行容器。目前K8S支持的容器運行環境至少包括Docker、RKT、cri-o、Fraki等。
- 3、Kube-proxy
service在邏輯上代表了后端的多個Pod,外借通過service訪問Pod。service接收到請求就需要kube-proxy完成轉發到Pod的。每個Node都會運行kube-proxy服務,負責將訪問的service的TCP/UDP數據流轉發到后端的容器,如果有多個副本,kube-proxy會實現負載均衡,有2種方式:LVS或者Iptables
3、核心附件
K8S集群還依賴一組附件組件,通常是由第三方提供的特定應用程序。如下圖:
- 1、KubeDNS
在K8S集群中調度並運行提供DNS服務的Pod,同一集群內的其他Pod可以使用該DNS服務來解決主機名。K8S自1.11版本開始默認使用CoreDNS項目來為集群提供服務注冊和服務發現的動態名稱解析服務。
- 2、Dashboard
K8S集群的全部功能都要基於Web的UI,來管理集群中的應用和集群自身。
- 3、Heapster
容器和節點的性能監控與分析系統,它收集並解析多種指標數據,如資源利用率、生命周期時間,在最新的版本當中,其主要功能逐漸由Prometheus結合其他的組件進行代替。
- 4、Ingress Controller
Service是一種工作於4層的負載均衡器,而Ingress是在應用層實現的HTTP(S)的負載均衡。不過,Ingress資源自身並不能進行流量的穿透,,它僅僅是一組路由規則的集合,這些規則需要通過Ingress控制器(Ingress Controller)發揮作用。目前該功能項目大概有:Nginx-ingress、Traefik、Envoy和HAproxy等。如下圖就是Nginx-ingress的應用,具體可以查看博文:https://www.cnblogs.com/linuxk/p/9706720.html
四、K8S的網絡模型
K8S的網絡中主要存在4種類型的通信:
- ①同一Pod內的容器間通信
- ②各個Pod彼此間的通信
- ③Pod和Service間的通信
- ④集群外部流量和Service之間的通信
K8S為Pod和Service資源對象分別使用了各自的專有網絡,Pod網絡由K8S的網絡插件配置實現,而Service網絡則由K8S集群進行指定。如下圖:
K8S使用的網絡插件需要為每個Pod配置至少一個特定的地址,即Pod IP。Pod IP地址實際存在於某個網卡(可以是虛擬機設備)上。
而Service的地址卻是一個虛擬IP地址,沒有任何網絡接口配置在此地址上,它由Kube-proxy借助iptables規則或ipvs規則重定向到本地端口,再將其調度到后端的Pod對象。Service的IP地址是集群提供服務的接口,也稱為Cluster IP。
Pod網絡和IP由K8S的網絡插件負責配置和管理,具體使用的網絡地址可以在管理配置網絡插件時進行指定,如10.244.0.0/16網絡。而Cluster網絡和IP是由K8S集群負責配置和管理,如10.96.0.0/12網絡。
從上圖進行總結起來,一個K8S集群包含是三個網絡。
- (1)節點網絡:各主機(Master、Node、ETCD等)自身所屬的網絡,地址配置在主機的網絡接口,用於各主機之間的通信,又稱為節點網絡。
- (2)Pod網絡:專用於Pod資源對象的網絡,它是一個虛擬網絡,用於為各Pod對象設定IP地址等網絡參數,其地址配置在Pod中容器的網絡接口上。Pod網絡需要借助kubenet插件或CNI插件實現。
- (3)Service網絡:專用於Service資源對象的網絡,它也是一個虛擬網絡,用於為K8S集群之中的Service配置IP地址,但是該地址不會配置在任何主機或容器的網絡接口上,而是通過Node上的kube-proxy配置為iptables或ipvs規則,從而將發往該地址的所有流量調度到后端的各Pod對象之上。
五、Kubernetes的核心對象詳解
1、Pod資源對象
Pod資源對象是一種集合了一個或多個應用容器、存儲資源、專用ip、以及支撐運行的其他選項的邏輯組件。如下圖:Pod其實就是一個應用程序運行的單一實例,它通常由共享資源且關系緊密的一個或2多個應用容器組成。
Kubernetes的網絡模型要求每個Pod的IP地址同一IP網段,各個Pod之間可以使用IP地址進行通信,無論這些Pod運行在集群內的哪個節點上,這些Pod對象都類似於運行在同一個局域網內的虛擬機一般。
我們可以將每一個Pod對象類比為一個物理主機或者是虛擬機,那么運行在同一個Pod對象中的多個進程,也就類似於跑在物理主機上的獨立進程,而不同的是Pod對象中的各個進程都運行在彼此隔離的容器當中,而各個容器之間共享兩種關鍵性資源:網絡和存儲卷。
- 網絡:每一個Pod對象都會分配到一個Pod IP地址,同一個Pod內部的所有容器共享Pod對象的Network和UTS名稱空間,其中包括主機名、IP地址和端口等。因此,這些容器可以通過本地的回環接口lo進行通信,而在Pod之外的其他組件的通信,則需要使用Service資源對象的Cluster IP+端口完成。
- 存儲卷:用戶可以給Pod對象配置一組存儲卷資源,這些資源可以共享給同一個Pod中的所有容器使用,從而完成容器間的數據共享。存儲卷還可以確保在容器終止后被重啟,或者是被刪除后也能確保數據的持久化存儲。
一個Pod代表着某個應用程序的特定實例,如果我們需要去擴展這個應用程序,那么就意味着需要為該應用程序同時創建多個Pod實例,每個實例都代表着應用程序的一個運行副本。而這些副本化的Pod對象的創建和管理,都是由一組稱為Controller的對象實現,比如Deployment控制器對象。
當創建Pod時,我們還可以使用Pod Preset對象為Pod注入特定的信息,比如Configmap、Secret、存儲卷、卷掛載、環境變量等。有了Pod Preset對象,Pod模板的創建就不需要為每個模板顯示提供所有信息。
基於預定的期望狀態和各個節點的資源可用性,Master會把Pod對象調度至選定的工作節點上運行,工作節點從指向的鏡像倉庫進行下載鏡像,並在本地的容器運行時環境中啟動容器。Master會將整個集群的狀態保存在etcd中,並通過API Server共享給集群的各個組件和客戶端。
2、Controller
在K8S的集群設計中,Pod是一個有生命周期的對象。那么用戶通過手工創建或者通過Controller直接創建的Pod對象會被調度器(Scheduler)調度到集群中的某個工作節點上運行,等到容器應用進程運行結束之后正常終止,隨后就會被刪除。而需要注意的是,當節點的資源耗盡或者故障,也會導致Pod對象的回收。
而K8S在這一設計上,使用了控制器實現對一次性的Pod對象進行管理操作。比如,要確保部署的應用程序的Pod副本數達到用戶預期的數目,以及基於Pod模板來重建Pod對象等,從而實現Pod對象的擴容、縮容、滾動更新和自愈能力。例如,在某個節點故障,相關的控制器會將運行在該節點上的Pod對象重新調度到其他節點上進行重建。
控制器本身也是一種資源類型,其中包括Replication、Controller、Deployment、StatefulSet、DaemonSet、Jobs等等,它們都統稱為Pod控制器。如下圖的Deployment就是這類控制器的代表實現,是目前用於管理無狀態應用的Pod控制器。
Pod控制器的定義通常由期望的副本數量、Pod模板、標簽選擇器組成。Pod控制器會根據標簽選擇器來對Pod對象的標簽進行匹配篩選,所有滿足選擇條件的Pod對象都會被當前控制器進行管理並計入副本總數,確保數目能夠達到預期的狀態副本數。
需要注意的是,在實際的應用場景中,在接收到的請求流量負載低於或接近當前已有Pod副本的承載能力時,需要我們手動修改Pod控制器中的期望副本數量以實現應用規模的擴容和縮容。而在集群中部署了HeapSet或者Prometheus的這一類資源監控組件時,用戶還可以通過HPA(HorizontalPodAutoscaler)來計算出合適的Pod副本數量,並自動地修改Pod控制器中期望的副本數,從而實現應用規模的動態伸縮,提高集群資源的利用率。
K8S集群中的每個節點上都運行着cAdvisor,用於收集容器和節點的CPU、內存以及磁盤資源的利用率直播數據,這些統計數據由Heapster聚合之后可以通過API server訪問。而HorizontalPodAutoscaler基於這些統計數據監控容器的健康狀態並作出擴展決策。
3、Service
我們知道Pod對象有Pod IP地址,但是該地址無法確保Pod對象重啟或者重建之后保持不變,這會帶來集群中Pod應用間依賴關系維護的麻煩。比如前段Pod應用無法基於固定的IP地址跟中后端的Pod應用。
而Service資源就是在被訪問的Pod對象中添加一個有着固定IP地址的中間層,客戶端向該地址發起訪問請求后,由相關的Service資源進行調度並代理到后端的Pod對象。
Service並不是一個具體的組件,而是一個通過規則定義出由多個Pod對象組成而成的邏輯集合,並附帶着訪問這組Pod對象的策略。Service對象挑選和關聯Pod對象的方式和Pod控制器是一樣的,都是通過標簽選擇器進行定義。如下圖:
Service IP是一種虛擬IP,也稱為Cluster IP,專用於集群內通信,通常使用專有的地址段,如:10.96.0.0/12網絡,各Service對象的IP地址在該范圍內由系統動態分配。
集群內的Pod對象可直接請求這類Cluster IP,比如上圖中來自Pod client的訪問請求,可以通過Service的Cluster IP作為目標地址進行訪問,但是在集群網絡中是屬於私有的網絡地址,僅僅可以在集群內部訪問。
而需要將集群外部的訪問引入集群內部的常用方法是通過節點網絡進行,其實現方法如下:
- 通過工作節點的IP地址+端口(Node Port)接入請求。
- 將該請求代理到相應的Service對象的Cluster IP的服務端口上,通俗地說:就是工作節點上的端口映射了Service的端口。
- 由Service對象將該請求轉發到后端的Pod對象的Pod IP和 應用程序的監聽端口。
因此,類似於上圖來自Exxternal Client的集群外部客戶端,是無法直接請求該Service的Cluster IP,而是需要實現經過某一工作節點(如 Node Y)的IP地址,着了請求需要2次轉發才能到目標Pod對象。這一類訪問的缺點就是在通信效率上有一定的延時。