Kubernetes是Google開源的一款容器編排工具,它是誕生在Google內部運行N多年的博格系統之上的產物,因此其成熟度從其誕生初期就廣泛受到業界的關注,並且迅速成為編排工具市場的主流,其社區活躍度非常高,版本迭代速度也很驚人,它的主要作用是對Docker容器做編排工作,當然,Docker只是容器工具的一種引擎,K8s可支持多種容器引擎,但從目前來說Docker容器引擎是具有絕對優勢的,容器需要編排,也很容易理解,因為我們最核心要跑到業務通常都是LNMT/P的不同形式的擴展,但NMT/P他們的運行是有先后順序的,也就是說MySQL要先啟動,然后是Tomcat或PHP,最后是Nginx,而控制這種順序就需要有容器編排工具來幫我們實現,另外,我們的業務希望7x24小時在線,如何保障?靠人是很難做到實時的,但編排工具可以,K8s幫我們實現了很多控制器,這控制器可以幫我們監控容器運行的狀態,並自動幫我們重建(在容器時代重啟就是重建)容器,並且還可以在容器處理能力不足時,自動根據我們定義的擴展規則,自動創建新Pod(k8s中最小單元,每個Pod中可有一個或多個容器),並且在壓力下去后,自動刪除Pod等等功能。
另外這里是K8s的中文官方文檔zh站點:
https://k8smeetup.github.io/docs/
Kubernetes:
它至少需要3個Master節點
Master節點的主要組件:
API Server: 主要用來接收其它組件發來的請求,並作出相應的處理.
Scheduler: 主要負責挑選出一個最佳node節點來運行pod,它挑選合適的node,通常分兩個階段,
第一個階段:是先通過初步篩選, 根據運行pod的最大要求,如: 4G內存, 6顆CPU等需求,來做
初步篩選,假如從20台中選出了3台, 則進入第二階段,在從這3台中選出一台最符合的節點,
這時就需要綜合考量各種因素,最后將選出了一台最佳運行節點告訴給API Server,在由
Master節點負責調度Pod在該node節點上運行起來。
Controller:它是負責監控Node上運行的Pod是否正常工作,若它發現自己監控的某個Pod故障了,
它會向API Server發出通告,並要求Master在其它節點上再重新啟動一個相同的Pod,
然后將故障的Pod Kill掉。
Controller-Manager:它是負責監控所有Controller是否正常工作的,在Kubernetes集群中,有很多
個功能各異的Controller, 監控Pod健康狀態的Controller只是其中之一,Controller-Manager
它用於監控這些Controller工作狀態的,一旦Controller故障,它將重啟一個新的Controller來
代替它工作。
但是若Controller-Manager故障怎么辦? 其實Master在創建時,要求最少要有3個節點,每個節點都會啟動一個Controller-Manager,啟動一個為主Controller-Manager,其它兩個或多個為備用的Controller-Manager,一旦主Controller-Manager故障,則備用的Controller-Manager將代替它繼續工作。
Node0:
Pod:它是Kubernetes中最基本的單元,一個Pod其實是一個容器的抽象,或叫容器的殼,它內部
其實就是一個或多個容器。一個容器中只能運行一個應用程序,所以有時一個應用程序需要
強依賴另一個應用程序一起工作,如:ELK中要收集每個應用的日志,它就需要在每個應用
節點上部署自己的日志收集器,如Logstash, 那么對於Nginx,它的日志要放入ELK中,它就需要
和Logstash放到一起,但一個容器中只能運行一個應用程序,所以就需要在一個Pod中運行
兩個容器,來完成這個需求,所以在K8s系統中,將一個Pod做為一個整體,一個基本原子來管理。
Label Selector:在一個Kubernetes集群中,需要管理的Pod有很多,它們被調度到不同的Node節點上
運行,這么多Pod運行在不同的Node節點上,怎么對它們做管理? 通過字符串名稱?那么一個
Pod運行過程中故障,又被重啟到其它Node上,那么它的字符串名稱必然要改變,那么這又怎么
能唯一標示一個Pod? 所以這就需要用到Label Selector(標簽選擇器),實際上,Pod在K8s系統
中它們都有一類標簽,如:將運行Nginx的Pod都打一個App=Nginx的標簽,將運行HAProxy的Pod
都打上App=HAProxy,等等...那么在查找所有運行Nginx的Pod時,就可以通過標簽選擇器,通過
條件App, 並且其值為Nginx來查詢,就可以將所有是App=Nginx的Pod都標記出來,進行管理操作了。
Kubelet:它運行在Node上,接受APIServer發來的啟動,停止或刪除Pod請求,並按照請求,在Node實際執行
操作的守護進程。
Docker: 是實際Pod的運行環境提供者.
Pod:
自主式Pod: 它也是向API Server發請求,APIServer再通過Scheduler選擇最佳Node節點,最后有kubelet在
docker環境中創建Pod,但是一旦Node節點宕機,則該Pod將消失。因此不建議實行這種方式。
控制器管理的Pod:
控制器又分為以下幾個:
1. ReplicationController(副本控制器): 它是早期的Pod管理器,它負責接收用戶請求,來創建精確指定數量的Pod,
如用戶請求創建2個Nginx Pod,它會自動向API Server發請求,API Server在讓Scheduler選擇
最佳創建的Node節點,來創建兩個Pod,假如當前創建的一個Pod在Node3上, 結果Node3運行
一段時間后宕機了,這時ReplicationController會發現副本數量不夠了,它會再次請求API Server
由它控制這Scheduler重新選擇一個最佳Node節點,來重新創建一個Pod,這樣就能保證Pod 的
數量始終能夠達到用戶期望的個數。
它還支持滾動更新:簡單說就是假如現在我們的鏡像升級了,需要用新版鏡像來啟動Pod,
這時副本控制器會請求API Server使用新的鏡像來創建Pod, API依然是調度Scheduler,
選擇最佳節點,kubelet根據最新鏡像創建新Pod,這時Pod有三個,副本控制器此時會將
舊的Pod 刪除,然后再請求API Server創建新Pod,最后,再將舊Pod刪除,這樣就完成滾動
更新了,當然它還支持回滾操作。
以下為新版本的控制器:
2.ReplicaSet:副本集控制器
Deployment: ReplicaSet不直接使用,一般使用Deployment來管理無狀態的應用。
HPA(HorizontalPodAutoscaler: 水平Pod自動伸縮控制器):
在實際工作中當我們定義了一組Pod, 假如說為2個Pod,平時它們都能應付用戶較小規模的訪問量,但
某一時刻用戶訪問量突然增加, 2個Pod不足以應付,這時HPA控制,還能自己根據定義,如兩個Pod的CPU使用
率要控制在60%左右,HPA經過計算,若有滿足CPU利用率高於60%,需要再增加2個Pod,則它將自動再創建
兩個Pod來承載用戶訪問流量,當訪問量下去了,4個Pod的CPU使用率都很低,則HPA將自動銷毀多余的2個Pod.
3. StatefulSet:有狀態副本集控制器
4. DaemonSet: 若需要在一個特定的Node節點上運行一個Pod時,需要使用它。
5. Job:它用於定義一個僅需要運行一次作業的Pod, 如: 我們需要啟動一個Pod來負責清理垃圾,就可以定義一個
job,若job執行完成Pod退出,這是正常期望,若Pod運行過程中故障退出,但清理工作沒有完成,則Job將會再
次請求創建新的Pod來完成剩余的清理工作。
Ctonjob: 運行周期性作業.
這些控制器都是為了完成用戶期望的運行方式,而產生的。
服務自動發現:
問題: 作為容器的Pod是為客戶端提供某種服務的,如Nginx等, 但是Pod在運行過程中不可避免的會出問題,因此
就需要將有問題的Pod銷毀,在創建新的Pod,而新Pod的主機名和IP都將改變,那前端的客戶端要如何正常
訪問到這些提供服務的Pod?
K8s中的解決方案:
提供一個自動發現服務,它對於前端的客戶端來說,它是一個代理,對於后端Pod來說,它是調度器,自動發現服務是怎么工作的? 它實際上是借助於Label Selector,自動發現服務先將自己管理的Pod標簽,交給Label Selector,它會找到所有包含此標簽的Pod,然后自動發現服務,再去探測找到的每個Pod的IP和端口,並將它們作為自己可調度的服務Pod。
那自動發現服務其本質是什么? 它實際上是一個ipvs規則, 早期使用的是iptables的目標端口映射規則,但其負載均衡能力太差,在新版的k8s中就改用ipvs的NAT規則了。但需要注意 無論是iptables的DNAT規則,還是ipvs的NAT規則,它們面向客戶端都有一個地址, 即客戶端訪問這個地址時,iptables會將去往這個地址的流量做DNAT,轉換為其后端的Pod的IP和端口, ipvs也一樣,它也是將訪問該地址的流量轉換為后端Pod的IP和端口, 那么這個地址就是前端客戶端需要明確知道的,而且它是固定的;但是這些地址是ping不通的!但它們可被解析,因為這些地址僅作為規則使用,沒有配置在任何接口上,也就意味者它們沒有TCP/IP協議棧的支持。
另外,客戶端訪問這些Service(即自動發現服務)是通過名稱訪問的,而解析這些名稱的DNS是K8s中的基礎服務!這些DNS被稱為AddOns(附件)類組件。
K8s系統的主要組件示意圖:

注:
Service: 就是自動發現服務
Controller:是用於控制Pod的生存周期的,每個Controller只負責控制一部分Pod,一旦Pod出故障,它將自動請求APIServer在創建新的Pod替換故障Pod.
Pod: 如Nginx、Tomcat等Pod,它們要訪問其它Pod,都需要知道該Pod的前端代理(Service)是誰,所以在配置時,需要明確告訴它們,如:Nginx要代理用戶請求至Tomcat,它需要知道Tomcat的前端Service的域名,而這個域名是事先告知Nginx的,這是固定的,Nginx會先去訪問DNS的Serivce,獲取域名的解析地址后,在去訪問Tomcat的前端Service。Tomcat訪問后端MySQL也一樣。因此DNS服務是K8s中的基礎服務,必須要有。
注: 若service的域名和IP若發生改變,DNS會自動觸發修改相應的A記錄。
在K8s系統中:
需要手動創建的組件有: serivce, controller
另外: K8s系統若部署在機房中,那么它就必須有一組邊緣物理主機上配置公網IP,以便能接入外部流量進來。
當然,也可以在K8s外部單獨部署調度器,由調度器將流量發到K8s內網中。但這時調度器將不在K8s的可管理范圍了,所以圖中給出的是,K8s運行在雲系統上的情況,使用這些雲系統中的LBaaS,來創建虛擬調度器,這樣K8s就可以調用底層雲的API來管理這些虛擬調度器了。
K8s的三種網絡模型:
1. 一個Pod內多個容器時,它們之間的通信,靠本地環回(lo)
2. Pod間通信要通過service來完成.
在Docker中,容器之間通信要借助兩次NAT轉換才行,即NodeA上的容器要訪問NodeB上的容器,它們是先將請求發給網關(通常是docker0橋),然后docker0在將流量轉發出去前,要先做一次SNAT,接着到達NodeB后,還需要做DNAT,才能進入NodeB中的容器中,實現容器間通信。但在K8s中,這就太麻煩了,而且也會讓通信變動更混亂,因為NodeA上的容器根本不知道訪問的NodeB上的容器節點是誰,所以就變成這樣:Pod將請求發給網關(docker0),docker0與物理網卡是橋接,當docker0要向目標發請求時,它通過查詢本地的iptables規則 或 ipvs規則得知目標的地址,因此將流量轉發給目標,目標收到請求后,做出響應,返回給它的前端service,service在將請求代理給本地Pod.簡單示意圖:
NodeA【Pod--->docker0-->Service--->】-------------->NodeB【--->docker0--->Pod】
3. Service成為訪問的關鍵了,但service它只是規則,它怎么能自動監控Pod的改變? 它怎么會出現在所有Node上?所以這里還有一個在Node上的守護進程,kube-proxy
kube-proxy: 它是用於管理Service的,用戶手動創建service后,后續的管理都有kube-proxy來完成。
它會自動監控着service后端的Pod是否發生改變,若發生改變,它會立即通知API Server,
API Server收到通知后,它會將這個消息通告給所有關聯的訂閱者,如 kube-proxy, 每個Node上
的kube-proxy收到這個通告消息后,它們會自動將這個消息反映在本地的iptables 或 ipvs規則中。
API Server: 它會接收K8s集群中所有動態變化的信息,所有變化都要先通知API Server,那API Server的數據存儲在哪里?為了避免API Server故障導致數據丟失,這些數據又需要存放在一個共享存儲中.這個共享存儲就是etcd.
注:etcd: 它是一個Key-Value存儲的數據庫,類似於Redis,但它功能更強大,它支持更多協調機制.

注:
API Server和etcd直接使用HTTP協議通信
API Server和其Client也是HTTP協議通信
API Server與kubelet 和 kube-proxy的通信也是HTTP協議.
為了避免數據被盜取,必須在它們之間都啟用CA認證機制,即使用HTTPS協議.
基於以上所有基礎,現在將其簡略如下圖:
這就是K8s的三種網絡模型.

注:
此圖中顯示的三種網絡:
節點網絡: 是構建K8s集群時,我們自行需要構建的物理網絡.
Service網絡 和 Pod網絡則需要通過CNI(容器網絡接口)來引入第三方網絡插件來實現.
因為K8s並沒有提供網絡支持功能.
在K8s的CNI規范中, 它要求網絡插件需要實現:網絡管理 和 網絡策略.
網絡管理: 即給Pod配置IP地址等.
網絡策略: 它是用來實現K8s的網絡名稱空間之間是否能夠互相通信,在一個k8s網絡名稱空間中,是否允許Pod和Pod之間互相通信等.這些控制策略都是由iptables規則實現的,實際上。
k8s的網絡名稱空間:
這個網絡名稱空間是K8s提供的管理邊界,即 我們可以定義多個網絡名稱空間,每個網絡名稱空間可做為不同的項目 或 不同的租戶使用, 比如: A公司 申請了兩個網絡名稱
空間,一個做為開發環境,一個作為生產環境, 當我們不需要當前這個生產環境了,要使用升級后的生產環境,我們只需要刪除現有生產環境的這個網絡名稱空間即可,所以
說k8s的網絡名稱空間實際上提供了一個管理邊界。但這兩個網絡名稱空間中的Pod是在同一個網絡中的,它們是可以互相通信的,所以,網絡策略是用來決定它們之間是否能通信的。
CNI:
目前實行CNI規范的產品有很多,以下為比較知名的產品:
flannel: 它是一個比較簡單的CNI實現,它僅實現了網絡配置.
calico: 它是一個非常復雜的CNI實現,它實現了網絡配置 和 網絡策略, 並且它內部實現了三層網絡隧道進行路由通信,其路由協議為BGP.
canel: 它是flannel 和 calico的組合體項目,它使用了flannel網絡配置的簡單,又整合了calico的網絡策略.
