Kubernetes是什么?
他是一個全新的基於容器技術分布式架構領先方案;
他也是一個開放的開發平台;
他也是一個完備的分布式系統支撐平台;
Kubernetes的基本慨念和術語
-
Master
Kubernetes 里的Master 指的是集群控制節點,每個Kubernetes 集群里需要有一個 Master 節點負責整個集群的管理和控制,基本上Kuberneter所有的控制命令都發給它,他來負責具體的執行過程,我們后面所執行的所有命令基本上都是在Master節點上運行的。Masteer通常會占用一個獨立的服務器(高可用部署建議用三台服務器);
Master節點上運行着一組關鍵進程
a). Kubernetes API Server(kube-apiserver):提供了HTTP Rest 接口的關鍵進程,是Kubernetes里所有資源增、刪、改、查等操作的統一入口,也是集群控制的入口進程。
b). Kubernetes Controller Manager(kub-controller-manager):Kubernetes 里所有資源對象的自動化控制中心,可以理解為資源對象的“大總管”;
c). Kubernetes Scheduer(kub-scheduler):負責資源調度(pod調度)的進程;
d). Masternetes 節點上還需要啟動一個etcd服務,因為Kubernetes 上所有的資源對象全部保存在etcd中的;
-
Node
除了Mater節點外,Kubernetes集群中其他機器的節點被稱為Node節點,在較早的版本中也被稱為Minion。與Master一樣,Node節點可以是一台物理機,也可以是一台虛擬機。Node節點才是Kubernetes集群中的工作負載節點,每個Node節點都會被Master分配一些工作負載(Docker容器),當某個Node宕機時,其上的工作負載會被Master節點自動轉移到其他節點上去的。
每個Node節點上都都運行着一組關鍵進程
a)kubelet:負責Pod 對應的容器的創建、啟停等任務,同時與Master 節點密切協作,實現集群管理的基本功能。
b)kube-proxy:實現Kubernetes Server 的通信與負載均衡機制的重要組件。
c)Docker Engine(docker):Docker 引擎,負責本機的容器創建和管理工作。
Node節點可以在運行期間動態的增加到Kubernetes集群中,前提是這個節點上已經正確安裝、配置和啟動了上述關鍵進程,在默認的情況下kubelet會向Master注冊自己,這也是Kubernetes推薦的Node 管理方式。一旦Node 被納入集群管理范圍,kubelet進程就會定時向Master節點匯報自身的情況,例如操作系統、Docker版本、機器的CPU和內存情況,以及當時有哪些Pod在運行等,這樣Master可以獲知每個Node 的資源使用情況,並實現高效均衡的資源調度策略。而某個Node 超過指定時間不上報信息時,會被Master判定為”失聯“,Node的狀態被標記為不可用(Not Ready),隨后Master會觸發”工作負載大轉移“的自動流程。
我們可以通過執行以下命令查看集群中有多少個Node:
# kubectl get nodes

然后通過kubectl describe node <node-name>查看某個Node 節點的詳細信息:

-
Pod
Pod的基本組成:
每個Pod都有一個特殊地被稱為”根容器“的Pause的容器。Pause容器對應的鏡像屬於Kubernetes平台的一部分,除了Pause容器,每個Pod還包含一個或多個緊密相關的用戶業務容器。
通過kubectl get pods查看所有pod列表

為什么Pod會設計出一個全新的Pod概念並且對Pod有這樣特殊的組成結構?
原因之一:在一組容器作為一個單元的情況下,我們難以對“整體”簡單地的進行判斷及有效地進行運動。比如,一個容器死亡了,此時算是整體死亡?是N/M的死亡率?引入業務無關且不易死亡的Pause容器作為Pod的根容器,以他的狀態代表整個容器組的狀態,就簡單、巧妙的解決了這個問題。
原因之二:Pod里的uoge業務容器共享Pause容器的IP,共享Pause容器掛載的Volume,這樣既簡化了密切關聯的業務容器之間的通信問題,也很好的解決了他們之間的文件共享問題。
Kubernetes為每個Pod都分配了一個唯一的IP地址,稱為Pod IP,一個Pod里的多個容器共享Pod IP地址。Kubernetes要求底層網絡支持集群內任意兩個Pod之間的TCP/IP直接通信,這通常采用虛擬二層網絡技術來實現,例如Flannel、Open vSwitch等。因此,我們需要牢記一點:在Kubernetes中,一個Pod里的容器與另外主機上的Pod里的容器可以直接通信。
Pod其實有兩種類型:普通的Pod和靜態的Pod(Static Pod),后者比較特殊,他並不存放在Kubernetes的etcd存儲里,而是存放在某個具體的Node上的一個具體的文件中,並且只在該Node上啟動運行。而普通的Pod一旦被創建,就會被放入到etcd中存儲,隨后會被Kubernetes Master調度到某個具體的Node上進行綁定(Binding)。隨后該Pod被對應的Node上的kubelet進程實例化成一組相關的Docke容器並存儲起來。在默認情況下,當Pod里的某個容器停止時,Kubernetes會自動檢測到這個問題並且重新啟動這個Pod(重啟Pod里的所有容器),如果Pod所在的Node宕機,則會將這個Node節點上的所有Pod重新調度到其他Node節點上。
Pod、容器和Node的關系如下所示:
-
Label
Label是Kubernetes里的另外一個核心概念。一個Label是一個key=value的鍵值對,其中key與value由用戶自己指定。Label可以附加到各種資源對象上,例如Node、Pod、Service、RC等,一個資源對象可以定義任意數量的label,同一個Label也可以被添加到任意數量的資源對象上去,Label通常在資源對象定義時被確定,也可以在對象創建后動態的添加或者刪除。
我們可以通過給指定的資源對象捆綁一個或多個不同的Label來實現多維度的資源分組管理功能,以便靈活、方便的進行資源分配、調度、配置、部署等管理工作。例如:部署不同的版本的應用到不同的環境中;或者監控和分析應用(日志記錄、監控、告警)等。一些常用的Label標簽如下。
版本標簽:”release“:”stable“,”release“:“canary”....
環境標簽:”environment“:”dev“,”environment”:“qa”,“environment”:“producetion”
架構標簽:“tier”:“frontend”,“tier”:“backend”,“tier”:“middleware”
分區標簽:“partition”:“customerA”,“partition”:“customerB”....
質量管控標簽:“track”:“daily”,“track”:“weekly”
Label相當於我們熟悉的“標簽”,給某個資源對象定義一個Label,就相當於給他打了一個標簽,隨后可以通過Label Selector(標簽選擇器)查詢和篩選擁有某些Label的資源對象,Kubernetes通過這種方式實現了類似SQL的簡單又通用的對象查詢機制。
Label Selector 可以類比為SQL語句中的where查詢條件,例如,name=redis-slave這個Label Selector 作用於Pod時,可以類比為select * from pod where pod_name = 'redis-slave'這樣的語句。當前者有兩種不同的Label Selector 的表達式:基於等式的(Equality-based)和基於集合的(Set-based),前者采用“等式類”的表達式匹配標簽,下面是一些具體的例子。
name = redis-server:匹配所有具有標簽 nameredis-server的資源對象。
env != production:匹配所有不具有標簽 env=prouction 的資源對象。
而后者則使用集合操作的表達式匹配標簽,下面是一些具體的例子。
name in (redis-master,redis-slave):匹配所有具有標簽的nameredis-master或者nameredis-slave的資源對象。
name not in (php-frontend) :匹配所有不具有標簽namepho-frontend的資源對象。
可以通過多個Label Selector 表達式的組合實現復雜的條件選擇,多個表達式之間用“,”進行分割,幾個條件之間是“and”的關系,即同時滿足多個條件,比如下面的例子:
name = redis-server,env != production
Label Selector 在Kubernetes 中的重要使用場景有以下幾處。
a)kube-controller 進程通過資源對象RC上定義的Label Selector 來篩選要監控的Pod副本的數量,從而實現Pod副本的數量始終負荷預期設定的全自動流程控制。
b) kueb-proxy 進程通過Service 的 Label Selector 來選擇對應的Pod,自動建立起每個Service到對應Pod的請求轉發路由表,從而實現Servicce的智能負載均衡機制。
c)通過對某些Node 定義特定的Label,並且在Pod定義文件中使用NodeSelector這種標簽調度策略,kube-scheduler進程可以實現Pod定向調度的策略。
總結:使用Label 可以給對象創建更多組標簽,Label 和 Label Selector 共同構成了Kubernetes 系統中最核心的應用模型,使得被管理者對象能夠被精細地分組管理,同時實現了整個集群的高可用性。
-
Replication Controller
Replication Controller (簡稱RC),RC是Kubernetes的核心概念之一,簡單地說,他其實是定義了一個期望的場景,即聲明了某種Pod的副本的數量在任意時刻都符合某個預期值,所有RC的定義包括以下幾個部分:
a)Pod期待的副本數(replicas)
b)用於篩選目標Pod的Label Selector。
c)當Pod的副本數量小於預期值時,用於創建新Pod的Pod 模板(template)。
當我們定義了一個RC並提交到Kubernetes集群中以后,Master節點上的Controller Manager組件就會收到通知,定期巡檢系統當中的當前存活的目標Pod,並確保目標Pod實例數量剛好等於此RC的期望值,如果有過多的Pod副本在運行,系統就會停掉一些Pod,否則系統就會再手動創建一些Pod。可以說,通過RC,Kubernetes實現了用戶應用集群的高可用性,並且大大減少了系統管理員再傳統IT環境中需要手動完成的許多運維工作(如主機監控腳本、應用監控腳本、故障恢復腳本等)。
----通過RC,Kubernetes很容易就實現了這種高級實用的特性,被稱為“滾動升級”,具體的操作方法以后在做分析。
由於Replication Controller 與 Kubernetes代碼中的模塊Replication Controller同名,同時這個詞也無法准確表達他的本意,所以在Kubernetes v1.2時,他就升級成了另外一個概念-------Replica Set,官方解釋為“下一代的RC”,它與RC當前存在的唯一區別是:Replica Set支持基於集合的Label Selector(Set-based selector),而RC只支持基於等式的Label Selector(equality-based selector),這使得Replica Set的功能更強。
kubectl命令行使用與RC的絕大部分命令同樣也適用於Replica Set。此外,當前我們很少單獨使用Replica Set,它主要是被Deployment這個更高層級的資源對象所使用,從而形成一套完整的Pod創建、刪除、更新的編排機制。當我們使用Deplyment時,無須關心他說如何創建和維護Replica Set的,這一切都是自動發生的。
Replica Set和Deployment這兩個重要的資源對象逐步替換看之前的RC的作用,時Kubernetes v1.3里的Pod自動擴容(伸縮)這個告警功能實現的基礎,也將繼續在Kubernetes未來的版本中發揮重要作用。
總結RC(Replica Set)的一些特性和作用。
a)在大多數情況下,我們通過定義一個RC實現Pod的傳教過程及副本數量的自動過程。
b)RC里包含完整的Pod定義模板。
c)RC通過Label Selector機制實現對Pod副本的自動控制。
d)通過改變RC里的Pod的副本數量,可以實現Pod的擴容與縮容功能。
e)通過改變RC里Pod模板的鏡像版本,可以實現Pod的滾動升級功能。
-
Deployment
Deployment 是Kubernetes v1.2引入的概念,引入的目的是欸藍更好的解決Pod的編排問題。為此,Deployment 在內部使用了 Replica Set 來實現目的的,無論從Deployment 的作用與目的、它的YAML定義,還是從它的具體命令行操作來看,我們都可以把它看作RC的一次升級,兩者的相似度超過90%。
Deployment相對於RC的最大一個升級時我們可以隨時知道當前Pof“部署”的進度。實際上由於一個Po的創建、調度、綁定節點及在目標Node上啟動對應的的容器這一完整的過程需要一定的時間,所以我們期待系統啟動N個Pod副本的目標狀態,實際上是一個連續變化的“部署過程”導致的最終狀態。
Deployment典型使用場景有以下幾個:
a)創建一個Deployment對象來生成對應的Replica Set 並完成Pod副本的創建過程。
b)檢查Deployment的狀態來看部署動作是否完成(Pod副本的數量是達到預期的值)。
c)更新Deployment以創建新的Pod(比如鏡像升級)。
d)如果當前Deployment不穩定,則回滾到一個早先的Deployment版本。
e)暫停Deployment 以便一次性修改多個PodTemplateSpec 的配置項,之后再恢復Deployment,進行新的發布。
f)擴展Deployment以應對高負載。
g)查看 Deployment 的狀態,以此作為發布是否成功的標志。
h)清理不再需要的舊的 ReplicaSets。
運行下面命令可以查看 Deployment 的信息
kubectl get deployments

Pod 的管理對象,除了RC和Deployment,還包括ReplicaSet、DaemonSet、StatefulSet、Job等,分別用於不同的業務場景,具體以后再分析。
-
Horizontal Pod Autoscaler
以往我們通過手動執行kubectl scale 命令,我們可以實現Pod擴容和縮容。如果僅僅至此為止,顯然不符合谷歌對Kubernetes 的定位目標----自動化、智能化。再谷歌看來,分布式系統要能夠根據當前負載的變化情況觸發水平擴展或縮容的行為,因為這一過程可能是頻繁發生的、不可預料的,所以手動控制的方式是不現實的。
-
StatefulSet
在Kubernetes 中,Pod 的管理對象RC、Deployment、DaemonSet和job都是面向無狀態的服務。但是現實中有很多服務是由狀態的,特別是一些負載的中間件集群,例如MYsQL集群、MongoDB集群、Akka集群、Zookeeper集群等,這些應用集群都有以下一些特點。
a) 每個節點都有固定的省份ID,通過這個ID,集群中的成員可以相互發現並通訊。
b) 集群的規模是比較固定的,集群規模不能隨意的變動。
c) 集群里的每個節點都是有狀態的,通常會持久化數據到永久存儲中。
d) 如果磁盤損壞,則集群里的某個節點無法正常運行,集群功能受損。
如果用RC/Deployment控制Pod副本數的方式來實現上述有狀態的集群,則我們會發現第一點是無法滿足的,因為Pod的名字是隨機產生的,Pod的ID地址也是在運行期才確定是否有變動的,我們事先無法為每個Pod確定一個唯一不便的ID,另外,為了能夠在其他節點上恢復這個失敗的節點,這中集群中的Pod需要掛接某種共享存儲,為了解決這個問題,Kubernetes v1.4版本開始引入PetSet 這個新的資源對象,並且在 v1.5版本時更名為StatefulSet,StatefulSet從本質上來說,可以看着是Deployment/RC的一個特殊變種,它有如下的一些特性:
a)StatefulSet 里的每一個Pod 都有穩定、唯一的網絡標識,可以用來發現集群內的其他成員。假設StatefulSet的名字叫kafka,那么第一個Pod叫kafka-0,第二個叫kafka-1,以此類推。
b)StatefulSet 控制的Pod副本的啟停順序是受控的,操作第n個Pod時,前n-1 個Pod已經是運行且准備好的狀態。
c)StatefulSet 里的Pod 采用穩定的持久化存儲卷,通過PV/PVC來實現,刪除Pod 時默認不會刪除與StatefulSet相關的存儲卷(為了保證數據的安全)。
-
Service
Kubernetes 里的每個Servcice 其實就是我們經常提到的微服務架構中的一個“微服務”,之前我們所說的Pod、RC等資源對象其實都是為這節所說的“服務”-----Kubernetes Service作“嫁衣”的。
后面會單獨針對Service做講解,這里首先知道有這么一個對象存在就行。
-
Volume(存儲卷)
Volume 是Pod 中能夠被多個容器訪問的共享目錄。Kubernetes 的 Volume 概念、用途和目的與Docker的Volume比較相似,但兩者不能等價。首先,Kubernetes中的Volume定義在Pod上,然后被一個Pod里的多個容器掛載到具體的文件目錄下;其次,Kubernetes中的Volume與Pod的生命周期相同,但是與容器的生命周期不相關,當容器終止或重啟時,Volume中的數據也不會丟失。最后,Kubernetes支持多種類型的Voume,例如 ClusterFS、Geph等先進的分布式文件系統。
Kuberneter 提供了非常豐富的Volume 類型:
1.emptyDir
2.hosyPath
3.gcePersistentDisk
4.awsElasticBlockStore
5.NFS
-
Persistent Volume
前面我們說的Volume是定義在Pod上的,屬於“計算資源”的一部分,而實際上。“網絡存儲”是相對獨立於“計算資源”而存在的一種實體資源。比如在使用虛擬機的情況下,我們通常會先定義一個網絡存儲,然后從中划出一個“網盤”並接到虛擬機上。Persistent Volume (簡稱 PV)和與之相關的 Persistent Volume Claim (簡稱 PVC)也起到了類似的作用。
PV可以理解成是 Kubernetes 集群中的某個網絡存儲中對應的一塊存儲,他與 Volume 很類似,但又以下區別:
a)PV只能是網絡存儲,不屬於任何 Node,但可以在每個 Node 上訪問。
b)PV 並不是定義在 Pod 上的,而是獨立於 Pod 之外定義的。
c)PV 目前支持的類型有:gcePersistentDisk、awsElasticBlockStore、AzureFile、AzureDisk、FC(Fibre Channel)、Flocker、NFS、iSCSI....等等,這里就不一一例舉了。
PV 是有狀態的對象,它有以下幾種狀態:
a)Available:空閑狀態。
b)Bound:已經綁定到某個 PVC 上。
c)Released:對應的PVC 已經刪除,但資源還沒被集群回收。
d)Failed:PV 自動回收失敗。
-
Namespace(命名空間)
Namespace(命名空間)是Kubernetes 系統中一個非常重要的概念,Namespace在很多情況下用於實現多租戶的資源隔離。Namespace 通過將集群內部的資源對象“分配”到不同的Namespace 中,形成邏輯上分組的不同項目、小組或用戶組,便於不同的分組在共享使用整個集群的資源的同時還能被分別管理。
Kubernetes 集群在啟動后,會創建一個名為“default”的Namespace,通過 kubectl可以查到:
kubectl get namespace:
-
Annotation
Annotation於 Label 類似,也使用key/value 鍵值對的形式進行定義。不同的是Label 具有嚴格的命名規范,它的定義是 Kubernetes 對象的元數據(Metadata),並且用於 Label Selector。而 Annotation 則是任意定義的“附加”信息,以便外部工具進行查找,很多時候 Kubernetes 的模塊自身會通過 Annotation 的方式標記資源對象的一些特殊信息。通常來說,用Annotation 來記錄的信息如下:
a)build信息、release信息、Docker鏡像信息等,例如時間戳、release id 號、PR 好、鏡像 hash值、docker registry 地址等。
b)日志庫、監控庫、分析庫等資源庫的地址信息。
c)程序調式工具信息,例如工具名稱、把本號等。
d)團隊的聯系信息,例如電話號碼、負責人名稱、網址等。
小結
上述這些組件是Kubernetes 系統的核心組件,他們共同組成了 Kubernetes 系統的框架和計算模型。除了上述所介紹的核心組件,在Kubernetes 中還有許多輔助配置的資源對象,例如LimitRange、ResourceQuota。另外,一些系統內部使用的對象 Binging、Event等參考Kubernetes的API文檔。