一、Kubernetes簡介
Kubernetes是Google於2014年開源的一個容器編排工具,使用Google自己的go語言編寫,由Borg衍生而來。Borg是Google內部已經運行近十年的容器編排工具,由於docker的橫空出世,導致Google原本准備作為秘密武器的容器技術胎死腹中。計划被打亂,容器層面已經痛失良機,慢人一步,只有在編排工具層面下手了,Google當機立斷,基於Brog的邏輯編寫了Kubernetes,開源並捐給了CNCF(雲遠程計算基金會),由於Google近十年的使用經驗,所以Kubernetes一出世就橫掃了其它編排工具,時至今日,地位依然穩固。
Kubernetes源於希臘語,有“舵”或“飛行員”的意思。k8s,是由Kubernetes中間的八個字母縮寫為數字8得來的。Google采用這個名字的深意就是:既然你docker把自己定位成馱着集裝箱在大海上遨游的鯨魚,那么我就以Kubernetes掌舵大航海時代的話語權,鯨魚必須按照我設定的路線巡游。
Kubernetes的一大亮點就是自動化,在Kubernetes的解決方案中,一個服務可以自我擴展、自我診斷,並且容易升級,在收到服務擴容的請求后,Kubernetes會觸發調度流程,最終在選定的目標節點上啟動相應數量的服務實例副本,這些實例在啟動成功后會自動加入負載均衡器中並生效,Kubernetes會定時巡查每個服務的所有實例的可用性,確保服務實例的數量與預期的數量一致,當它發現某個實例不可用時,會自動重啟或在其它節點上重建該實例,整個過程無需額外的人工操作。 ——來自《Kubernetes權威指南》

二、Kubernetes對象
k8s的api是一種RESTful風格的API,在這種設計風格下,數據也好、服務也罷,一切都可以稱之為資源(resources)。在k8s中將這些資源實例化后稱之為對象。比如Pod在沒有使用之前就是一個抽象的概念,可以稱之為資源,你指定為Pod創建了容器之后,就可以稱之為對象。
基礎對象
-
Pod:
-
k8s最小部署單元是Pod,一個Pod可以包含一個或多個容器。
-
每個Pod都會被分配一個集群內專用的IP地址,成為Pod IP,同一Pod內部的所有容器共享Pod對象的Network、IPC、UTS名稱空間(主機名、網絡設備、網絡協議等),因此這些容器可以通過本地回環接口lo進行通信,而與Pod外的其它組件通信需要借助Service的Cluster IP機器相應的端口完成。此外,還可以通過共享存儲卷(Volume)來完成同一Pod內容器的數據共享,利用持久化存儲能保證容器被修改或者被刪除后數據不丟失。
-
一個Pod對象代表一個應用程序的特定實例,如果需要擴展應用程序,比如需要多台做負載或者高可用,那就意味着要為這個應用程序創建多個Pod實例,也就是需要多個副本,這時候就需要借助控制器(Controller)實現,例如deployment控制器對象,這個后面有介紹。
-
Pod分為普通Pod和靜態Pod。
- 普通Pod一旦被創建,就會被放入etcd中存儲,隨后會被Master調度到某個Node上並進行綁定,隨后會被對應Node上的kubelet實例化成一組容器並啟動起來。如果Pod所在的Node宕機了,Master會將這個Node上的所有Pod重新調度到其它Node節點上。
- 靜態Pod不會存儲到etcd中,而是存放在某個Node節點上的一個具體文件中,並且只在此Node上啟動運行。
-
-
Service:Service是一組Pod的抽象,每個Service都擁有一個唯一指定的名字,並被分配一個虛擬IP(Cluster IP、Service IP或VIP),Service通過代理后端Pod對外或者對內提供訪問,就好比nginx和后端服務的關系。來自這個IP的請求都會經過調度后轉發給后端Pod中的容器。Service對象挑選、關聯Pod對象的方式跟控制器一樣,都要基於Label Selector進行定義。Service主要有如下三種類型,此三種類型中,每一種都要以前一種為基礎才能實現,而且LoadBalancer類型需要協同集群外部的組件才能實現,且此外部組件不受k8s集群管控。
- 第一種是僅用於集群內部通信的Cluster IP類型。
- 第二種是接收集群外部請求的NodePort類型,他工作於每個節點的主機IP之上。
- 第三種是LoadBalancer類型,它可以把外部請求負載均衡至多個Node主機IP的NodePort之上。
-
Label:標簽用於區分對象,使用標簽引用對象而不再是IP地址。Label以鍵值對的形式存在,每個對象可以有多個標簽,通過標簽可以關聯對象。
- 假設Service代理一個或者多個Pod,但是某一個Pod因故障被刪重新調度出一個新Pod,那么這個Pod的IP可能會發生改變,因為容器的IP是隨機的。那Service怎么能知道這個新Pod的IP呢。這時使用標簽就可以完美的解決問題。k8s中的Pod,所謂一個蘿卜一個坑,只要不是手動刪除Pod,那么這個Pod一定會一直存在,down掉會重啟,故障會重建。在最初創建Pod時,它的Label就已經寫死了,當然后面是可以手動改的。比如app:nginx。所以即便重建了Pod,IP變了,Label不會變。Service通過LabelSelector去找Label為app:nginx的服務依然能夠找到。
-
Ingress:給Service提供外部訪問功能。
-
Namespace:可以抽象理解為對象的集合。比如將集群內部的對象划分到不同得到項目組或用戶組。比如Pods、Services都是屬於某一個Namespace的(默認是default)。
-
Volume:數據卷,共享Pod中使用的數據。
高級對象
k8s中,集群級別的大多數功能都是通過幾個被稱為控制器的進程執行實現的,這幾個進程被集成與kube-controller-manager守護進程中。由控制器完成的功能主要包括生命周期功能和API業務邏輯,如下:
- 生命周期功能:包括Namespace創建和生命周期、Event垃圾回收、Pod中止相關的垃圾回收、級聯垃圾回收及Node垃圾回收。
- API業務邏輯:例如有ReplicaSet指定的Pod擴展等。
控制器的種類基本如下:
- ReplicationController:簡稱RC。在舊版的k8s中,只有RC對象,使用它來確保Pod以用戶指定的副本數量運行。容器異常或者缺少都會自動處理。
- ReplicaSet:ReplicaSet 是 ReplicationController 的替代物。因此作用基本相同,RC與RS唯一區別就是支持LableSelector不同,RS支持基於集合的標簽。官方建議使用Deployment來自動管理RS,因為有些功能RS不支持,Deployment支持。
- Deployment:Pod控制器,它支持版本記錄、回滾、暫停升級等高級特性。Pod是不可以被直接創建的,需要先創建控制器,然后由控制器去創建Pod。每個Pod都對應一個deployment控制器。
- StatefulSet:為了解決有狀態服務的問題(對應 Deployments 和 ReplicaSets是為無狀態服務而設計)。
- DaemonSet:保證在每個Node節點上都運行一個Pod,常用來部署一些集群的日志、監控等應用。比如fluentd、logstash、prometheus等。
- Job:一次性任務,運行完后Pod銷毀,不再自動重建。
- CronJob:定時任務
三、Kubernetes組件
Kubernetes的結構略微復雜,我會從大的層面一點點往下拆分敘述。整個Kubernetes集群大致划分為四部分:Clients,Master,Node,Registry。k8s本身其實就Master和Node兩部分。
- Master:是Kubernetes集群的管理節點,是提供集群資源訪問與管理的唯一入口。
- Node:是Kubernetes集群運行Pod的服務節點,實質上也就是運行容器。
- Registry:容器的運行需要依賴於鏡像。
- Clients:編程接口,圖形化接口,命令行接口。我們通過這些接口向Master發請求來管理容器,比如創建、刪除等操作,我們稱發起請求者為管理客戶端(Clients)。

Master的組件
Master節點有四個核心組件,每一個組件都是單獨的服務,下面組件中只有etcd不是k8s自己提供,它只是k8s的主要組成部分,etcd也是CNCF的成員。
-
kube-apiserver:是整個k8s集群對外提供服務的唯一接口,它提供請求過濾、訪問控制等機制,是各組件的協調者,此API是聲明式的(簡單說就是用戶想要什么規格的容器直接跟kube-apiserver說就行了,過程不用你管)。用戶的合法請求會被API放行,然后存入etcd中。
- 是否合法指的是:etcd就好像公司領導,kuber-apiserver就是門口保安,領導規定,必須什么樣的人你能放進來。k8s將etcd所能接受的數據規格范式加以封裝定義在了kube-apiserver中,符合規格才能放行。
- 程序的編程范式包括聲明式和命令式:聲明式強調結果;命令式強調過程。
-
kube-scheduler:資源調度器。kube-apiserver收到新建Pod的請求,識別其合法並存入etcd,然后kube-scheduler去watch kube-apiserver知道此需求,根據預定的調度策略評估出一個最合適Node節點來運行Pod,如果沒有最合適,那就隨機,最后會把調度的結果記錄在etcd中。
-
kube-controller:控制器。就好比人類的大腦一樣,負責維護集群的狀態、故障檢測與恢復、自動擴展、節點狀態等等。kube-controller有一個control loop的機制,它會循環檢測集群中Pod的狀態,假如Nginx啟的不是預期的80端口,那就由kube-controller來控制容器重啟、重建,直到達到預期效果為止。
-
replication-controller:管理維護Replication Controller,關聯Replication Controller和Pod,保證Replication Controller定義的Pod副本數量與實際運行Pod數量一致。
-
etcd:是一個鍵值(key:value)格式的存儲系統。k8s集群中所有狀態信息都需要持久化存儲在etcd中,etcd是獨立的服務組件,並不隸屬於集群本身。etcd不僅提供鍵值數據存儲,還為集群提供了監聽機制,用於監聽和推送變更,在k8s中,etcd鍵值發生變化會通知到API server,並由其通過watch api向客戶端輸出。
-
舉例:用戶發送新建Nginx容器的請求給kube-apiserver,kube-apiserver識別其合法后以鍵值對的方式存入etcd,kube-scheduler和kube-controller通過watch kube-apiserver知道此需求,然后kube-scheduler負責資源分配並決定容器運行在哪個Node上,至於運行時所需的鏡像及運行的健康狀態的維護都由kube-controller來負責,kube-controller會循環將當前容器的狀態與watch到的用戶預期的需求做對比,看是否匹配。
-
k8s watch功能:k8s提供的watch功能是建立在etcd之上的。早期的k8s架構中kube-apiserver、kube-controller、kube-scheduler、Kubelet等都是直接去watch etcd的,但是隨着實例的增多,對etcd造成的壓力也越來越大,因此,現在是當etcd中的鍵值發生變化時,通知kube-apiserver,其它的組件需要watch時去直接找kube-apiserver,這樣大大減小了etcd的壓力。
-

Node的組件
Node節點負責提供運行容器的各種依賴環境,並接受master的管理。每個Node主要由以下幾個組件構成:
- kubelet:kubelet是運行與Node上面的守護進程,他從API server接收關於Pod對象的配置信息並確保它們處於期望的狀態,kubellet會在API server上注冊當前工作節點,定期向master匯報資源使用情況,並通過cAdvisor監控頭容器和節點資源使用情況。kubelet會去watch kube-apiserver,如果發現有新任務的調度結果分到了自己這個Node節點上,便會接過來執行此任務。完成后將結果匯報給kube-apiserver。
- container runtime:每個Node都需要提供一個容器運行時(container runtime)環境,它負載下載鏡像並運行容器。k8s支持多種容器運行環境,如:docker、rkt、cri-o等等,只不過k8s標准支持的容器是docker,其它容器引擎想要與k8s配合使用,需要接入到k8s的cri接口 。因為不同容器技術的更新速度是不一樣,k8s只能以一個相對比較權威的容器技術來作為標准。
- kube-proxy:每個Node都需要一個kube-proxy守護進程,它能夠按需為service生成iptables或ipvs規則,從而捕獲訪問當前service的cluster ip的流量並將其轉發至正確的后端Pod對象。

Addons
除了上面Master和Node幾個核心組件,k8s集群還需依賴一些擴展插件來提供完整的功能,他們通常是由第三方提供的特定應用程序,如下:
- Coredns:在k8s集群中調度運行提供DNS服務的Pod。從k8s 1.11版本開始,集群默認使用CoreDNS為集群提供服務注冊和服務發現的動態名稱解析服務。
- CNI:容器網絡接口,k8s的網絡模型需要借助這類插件才能實現。比如flannel,calico等。
- Fluentd:為集群提供日志采集、存儲和查詢。
- Ingress Controller:Service是一種工作於傳輸層的負載均衡器,而Ingress是在應用層實現的HTTP(s)負載均衡機制。不過Ingress本身並不能進程“流量穿透”,它僅是一組路由規則的集合,這些規則需要通過Ingress Controller發揮作用。目前,此類可用的項目有:Nginx、Tarefik、Envoy和Haproxy等。
- Kubernetes Dashboard:管理k8s集群的圖形化界面。
四、Kubernetes網絡
如下圖所示,k8s集群包含三個網絡:
- 節點網絡:各主機自身(master、node、etcd)所屬的網絡,其地址配置於主機層面的網絡接口,不被k8s集群管理。
- Pod網絡:這是一個虛擬網絡,為各Pod對象設定IP地址等網絡參數,其地址配置於Pod內容器的網絡接口上。Pod網絡需要借助於kubenet或CNI插件實現。該插件可以部署在k8s集群之外,也可以托管在集群上。
- Service網絡:這也是一個虛擬網絡,用於為k8s集群中的service配置虛擬IP地址,這種IP沒有任何網絡接口。它是通過Node上的kube-proxy配置為iptables或ipvs規則,從而將發往此地址的所有流量調度至后端各Pod對象上。service網絡在創建k8s集群時指定,而各service的地址則在用戶創建service時動態配置。此IP是集群提供服務的接口,故也稱為Cluster IP。

五、小小建議
Kubernetes的概念還是蠻多的,不建議是一腦門扎到概念上,盡量結合實踐去理解,可以多看看官網,部分頁面是有中文支持的。在下寫的時候腦門也是嗡嗡的,可能會有不完善或者偏差的地方,未完待續吧......
參考資料
- 《Kubernetes權威指南》
- 《Kubernetes進階實戰》
- Kubernetes官網
- ywhu的博客:k8s的watch功能
寫作不易,轉載請注明出處,謝謝~~