kubernetes 簡介
一個迅速過一遍kubernetes 非常不錯的資源:
基于Kubernetes構建Docker集群管理詳解
kubernetes 出現原因
目前企業級應用出現的問題:
- 粗放型的技術團隊中開發人員直接與機器、操作系統打交道,無運維人員造成了大量的時間開銷,同時運維人員不了解相應的應用,出問題需要多方同時到位,進行解決。
- 系統的可用性和穩定性很難得到保證
- 分布式應用及分布式系統門檻很高,需要長期的技術積累。
kubernetes 的出現即為了解決該問題,為各種各樣的開發完成的微服務能夠迅速服務千萬用戶的訪問。
解決上述問題即是kubernetes的設計目的:
- 隱藏資源管理和錯誤處理,用戶開發者僅需要關注應用的開發。
- 服務高可用、高可靠。
- 可將負載運行在由成千上萬的機器聯合而成的集群中,同時實現彈性伸縮。
Kubernetes對計算資源進行了更高層次的抽象,通過將容器進行細致的組合,將最終的應用服務交給用戶。
Kubernetes在模型建立之初就考慮了容器跨機連接的要求,支持多種網絡解決方案,同時在Service層次構建集群范圍的SDN網絡。其目的是將服務發現和負載均衡放置到容器可達的范圍,這種透明的方式便利了各個服務間的通信,并為微服務架構的實踐提供了平臺基礎。而在Pod層次上,作為Kubernetes可操作的最小對象,其特征更是對微服務架構的原生支持。
kubernetes 一次完整的工作流
說工作流之前附上參考鏈接:k8s 工作流參考鏈接
三個維度認識kubernetes
關于上圖需要補充兩點:
- 操作對象是基本對象,是k8s及用戶直接操作的對象單元。
- apiservver里面包含REST對象,其中REST對象起到了服務注冊的作用。
操作對象
Kubernetes以RESTFul形式開放接口,用戶可操作的REST對象有三個:
- pod:是Kubernetes最基本的部署調度單元,可以包含container,邏輯上表示某種應用的一個實例。比如一個web站點應用由前端、后端及數據庫構建而成,這三個組件將運行在各自的容器中,那么我們可以創建包含三個container的pod。
- service:是pod的路由代理抽象,用于解決pod之間的服務發現問題。因為pod的運行狀態可動態變化(比如切換機器了、縮容過程中被終止了等),所以訪問端不能以寫死IP的方式去訪問該pod提供的服務。service的引入旨在保證pod的動態變化對訪問端透明,訪問端只需要知道service的地址,由service來提供代理。
- replicationController:是pod的復制抽象,用于解決pod的擴容縮容問題。通常,分布式應用為了性能或高可用性的考慮,需要復制多份資源,并且根據負載情況動態伸縮。通過replicationController,我們可以指定一個應用需要幾份復制,Kubernetes將為每份復制創建一個pod,并且保證實際運行pod數量總是與該復制數量相等(例如,當前某個pod宕機時,自動創建新的pod來替換)。
可以看到,service和replicationController只是建立在pod之上的抽象,最終是要作用于pod的,那么它們如何跟pod聯系起來呢?這就要引入label的概念:label其實很好理解,就是為pod加上可用于搜索或關聯的一組key/value標簽,而service和replicationController正是通過label來與pod關聯的。如下圖所示,有三個pod都有label為"app=backend",創建service和replicationController時可以指定同樣的label:"app=backend",再通過label selector機制,就將它們與這三個pod關聯起來了。例如,當有其他frontend pod訪問該service時,自動會轉發到其中的一個backend pod。
REST對象會寫入到etcd中
功能組件
如下圖所示是官方文檔里的集群架構圖,一個典型的master/slave(minion)模型。
master運行三個組件:
- apiserver:作為kubernetes系統的入口,封裝了核心對象的增刪改查操作,以RESTFul接口方式提供給外部客戶和內部組件調用。它維護的REST對象將持久化到etcd(一個分布式強一致性的key/value存儲)。
- scheduler:負責集群的資源調度,為新建的pod分配機器。這部分工作分出來變成一個組件,意味著可以很方便地替換成其他的調度器。
- controller-manager:負責執行各種控制器,目前有兩類:
- endpoint-controller:定期關聯service和pod(關聯信息由endpoint對象維護),保證service到pod的映射總是最新的。
- replication-controller:定期關聯replicationController和pod,保證replicationController定義的復制數量與實際運行pod的數量總是一致的。
slave(稱作minion)運行兩個組件:
- kubelet:負責管控docker容器,如啟動/停止、監控運行狀態等。它會定期從etcd獲取分配到本機的pod,并根據pod信息啟動或停止相應的容器。同時,它也會接收apiserver的HTTP請求,匯報pod的運行狀態。
- proxy:負責為pod提供代理。它會定期從etcd獲取所有的service,并根據service信息創建代理。當某個客戶pod要訪問其他pod時,訪問請求會經過本機proxy做轉發。
更簡單kubernetes架構圖:
工作流
上文已經提到了Kubernetes中最基本的三個操作對象:pod, replicationController及service。下面分別從它們的對象創建出發,通過時序圖來描述Kubernetes各個組件之間的交互及其工作流。
簡述createPod的過程:
- 客戶端提交創建請求,可以通過API Server的Restful API,也可以使用kubectl命令行工具。支持的數據類型包括JSON和YAML。
- API Server處理用戶請求,存儲Pod數據到etcd。
- 調度器通過API Server查看未綁定的Pod。嘗試為Pod分配主機。
- 過濾主機 (調度預選):調度器用一組規則過濾掉不符合要求的主機。比如Pod指定了所需要的資源量,那么可用資源比Pod需要的資源量少的主機會被過濾掉。
- 主機打分(調度優選):對第一步篩選出的符合要求的主機進行打分,在主機打分階段,調度器會考慮一些整體優化策略,比如把容一個Replication Controller的副本分布到不同的主機上,使用最低負載的主機等。
- 選擇主機:選擇打分最高的主機,進行binding操作,結果存儲到etcd中。
- kubelet根據調度結果執行Pod創建操作: 綁定成功后,scheduler會調用APIServer的API在etcd中創建一個boundpod對象,描述在一個工作節點上綁定運行的所有pod信息。運行在每個工作節點上的kubelet也會定期與etcd同步boundpod信息,一旦發現應該在該工作節點上運行的boundpod對象沒有更新,則調用Docker API創建并啟動pod內的容器。
kubernetes 相應的組件實現及原理
Kubernetes node有運行應用容器必備的服務,而這些都是受Master的控制。
每次個節點上當然都要運行Docker。Docker來負責所有具體的映像下載和容器運行。
Kubernetes主要由以下幾個核心組件組成:
etcd保存了整個集群的狀態;
- apiserver提供了資源操作的唯一入口,并提供認證、授權、訪問控制、API注冊和發現等機制;
- controller manager負責維護集群的狀態,比如故障檢測、自動擴展、滾動更新等;
- scheduler負責資源的調度,按照預定的調度策略將Pod調度到相應的機器上;
- kubelet負責維護容器的生命周期,同時也負責Volume(CVI)和網絡(CNI)的管理;
- Container runtime負責鏡像管理以及Pod和容器的真正運行(CRI);
- kube-proxy負責為Service提供cluster內部的服務發現和負載均衡;
除了核心組件,還有一些推薦的Add-ons:
- kube-dns負責為整個集群提供DNS服務
- Ingress Controller為服務提供外網入口
- Heapster提供資源監控
- Dashboard提供GUI
- Federation提供跨可用區的集群
- Fluentd-elasticsearch提供集群日志采集、存儲與查詢
幾個主要的組件
kubelet
kubelet負責管理pods和它們上面的容器,images鏡像、volumes、etc。
kube-proxy
每一個節點也運行一個簡單的網絡代理和負載均衡(詳見services FAQ )(PS:官方 英文)。 正如Kubernetes API里面定義的這些服務(詳見the services doc)(PS:官方 英文)也可以在各種終端中以輪詢的方式做一些簡單的TCP和UDP傳輸。
服務端點目前是通過DNS或者環境變量( Docker-links-compatible 和 Kubernetes{FOO}_SERVICE_HOST 及 {FOO}_SERVICE_PORT 變量都支持)。這些變量由服務代理所管理的端口來解析。
Kubernetes控制面板
Kubernetes控制面板可以分為多個部分。目前它們都運行在一個master 節點,然而為了達到高可用性,這需要改變。不同部分一起協作提供一個統一的關于集群的視圖。
etcd
所有master的持續狀態都存在etcd的一個實例中。這可以很好地存儲配置數據。因為有watch(觀察者)的支持,各部件協調中的改變可以很快被察覺。
etcd為了提高可靠性,可以使用多個master節點:
參考鏈接:搭建含三個master節點的kubernetes集群
需要注意的地方有:
- kube-scheduler、kube-controller-manager 和 kube-apiserver 三者的功能緊密相關;
同時只能有一個 kube-scheduler、kube-controller-manager 進程處于工作狀態,如果運行多個,則需要通過選舉產生一個 leader;(raft算法)
Kubernetes API Server
API服務提供Kubernetes API (PS:官方 英文)的服務。這個服務試圖通過把所有或者大部分的業務邏輯放到不兩只的部件中從而使其具有CRUD特性。它主要處理REST操作,在etcd中驗證更新這些對象(并最終存儲)。
Scheduler
調度器把未調度的pod通過binding api綁定到節點上。調度器是可插拔的,并且我們期待支持多集群的調度,未來甚至希望可以支持用戶自定義的調度器。
Kubernetes控制管理服務器
所有其它的集群級別的功能目前都是由控制管理器所負責。例如,端點對象是被端點控制器來創建和更新。這些最終可以被分隔成不同的部件來讓它們獨自的可插拔。
replicationcontroller(PS:官方 英文)是一種建立于簡單的 pod API之上的一種機制。一旦實現,我們最終計劃把這變成一種通用的插件機制。
kubernetes 常用名詞解釋與在整體架構中的作用
Pod
K8s有很多技術概念,同時對應很多API對象,最重要的也是最基礎的是微服務Pod。Pod是在K8s集群中運行部署應用或服務的最小單元,它是可以支持多容器的。Pod的設計理念是支持多個容器在一個Pod中共享網絡地址和文件系統,可以通過進程間通信和文件共享這種簡單高效的方式組合完成服務。Pod對多容器的支持是K8s最基礎的設計理念。比如你運行一個操作系統發行版的軟件倉庫,一個Nginx容器用來發布軟件,另一個容器專門用來從源倉庫做同步,這兩個容器的鏡像不太可能是一個團隊開發的,但是他們一塊兒工作才能提供一個微服務;這種情況下,不同的團隊各自開發構建自己的容器鏡像,在部署的時候組合成一個微服務對外提供服務。
Pod是K8s集群中所有業務類型的基礎,可以看作運行在K8s集群中的小機器人,不同類型的業務就需要不同類型的小機器人去執行。目前K8s中的業務主要可以分為長期伺服型(long-running)、批處理型(batch)、節點后臺支撐型(node-daemon)和有狀態應用型(stateful application);分別對應的小機器人控制器為Deployment、Job、DaemonSet和PetSet,本文后面會一一介紹。
復制控制器(Replication Controller,RC)
RC是K8s集群中最早的保證Pod高可用的API對象。通過監控運行中的Pod來保證集群中運行指定數目的Pod副本。指定的數目可以是多個也可以是1個;少于指定數目,RC就會啟動運行新的Pod副本;多于指定數目,RC就會殺死多余的Pod副本。即使在指定數目為1的情況下,通過RC運行Pod也比直接運行Pod更明智,因為RC也可以發揮它高可用的能力,保證永遠有1個Pod在運行。RC是K8s較早期的技術概念,只適用于長期伺服型的業務類型,比如控制小機器人提供高可用的Web服務。
服務(Service)
RC、RS和Deployment只是保證了支撐服務的微服務Pod的數量,但是沒有解決如何訪問這些服務的問題。一個Pod只是一個運行服務的實例,隨時可能在一個節點上停止,在另一個節點以一個新的IP啟動一個新的Pod,因此不能以確定的IP和端口號提供服務。要穩定地提供服務需要服務發現和負載均衡能力。服務發現完成的工作,是針對客戶端訪問的服務,找到對應的的后端服務實例。在K8s集群中,客戶端需要訪問的服務就是Service對象。每個Service會對應一個集群內部有效的虛擬IP,集群內部通過虛擬IP訪問一個服務。在K8s集群中微服務的負載均衡是由Kube-proxy實現的。Kube-proxy是K8s集群內部的負載均衡器。它是一個分布式代理服務器,在K8s的每個節點上都有一個;這一設計體現了它的伸縮性優勢,需要訪問服務的節點越多,提供負載均衡能力的Kube-proxy就越多,高可用節點也隨之增多。與之相比,我們平時在服務器端做個反向代理做負載均衡,還要進一步解決反向代理的負載均衡和高可用問題。
任務(Job)
Job是K8s用來控制批處理型任務的API對象。批處理業務與長期伺服業務的主要區別是批處理業務的運行有頭有尾,而長期伺服業務在用戶不停止的情況下永遠運行。Job管理的Pod根據用戶的設置把任務成功完成就自動退出了。成功完成的標志根據不同的spec.completions策略而不同:單Pod型任務有一個Pod成功就標志完成;定數成功型任務保證有N個任務全部成功;工作隊列型任務根據應用確認的全局成功而標志成功。
kubernetes 配置文件寫法
kubernentes 使用實例
一個非常不錯的kubernentes的例子:
參考鏈接
kubernetes 后面新加入了許多新的特性,但是通常一般來說主要定義三個kind,包括
service,rc,pod
service 用來服務注冊
rc 用來保持一定量的副本
pod 用來指明啟動的docker鏡像。
kubernetes 與fabric結合
從 fabric 的配置文件說起:
k8s上面部署kubernentes文章主要分為幾個步驟:
- 基礎設施:網絡、共享存儲。網絡解決的問題是通過docker.sock創建的容器k8s訪問不到。pv和pvc解決的是共享存儲的問題。
- 組件劃分 namespace隔離 分為幾個部分,幾個pod。這塊和fabric關系比較緊密,決定了fabric的模板文件如何去寫。
- 源代碼
附錄
Kubernetes支持2種服務發現方式,環境變量和DNS。 其中環境變量是默認支持的,但是環境變量方式存在限制: Pod必須在Service之后創建,DNS則沒有這個限制。
簡單描述一句話:
創建service.yaml之后,仍需要獲取Service的Cluster-IP,再結合Port訪問服務。
雖然Service解決了Pod的服務發現和負載均衡問題,但存在著類似的問題:不提前知道Service的cluster-IP,還是需要改程序或配置啊。看到這里有沒有感覺身體被掏空?
service 比pod強了一點是service有個虛擬ip,它是不會改變的,訪問的時候通過serviceIp:port即可完成訪問。
但是service cluster IP還是必須查的。
kube-dns可以解決Service的發現問題,k8s將Service的名稱當做域名注冊到kube-dns中,通過Service的名稱就可以訪問其提供的服務。
一個service的實例。
{
"kind": "Service",
"apiVersion": "v1",
"metadata": {
"name": "my-service"
},
"spec": {
"selector": {
"app": "MyApp"
},
"ports": [
{
"protocol": "TCP",
"port": 80,
"targetPort": 9376
}
]
}
}
在yaml的配置文件中,Kubernetes 提供了一種新的部署,名為deployment,它繼承了絕大多數rc的特性,并且提供了更強的功能。
pv和pvc
在kubernentes整合fabric中用到了pv和pvc,它們二者的區別是:
PersistentVolume(pv)和PersistentVolumeClaim(pvc)是k8s提供的兩種API資源,用于抽象存儲細節。管理員關注于如何通過pv提供存儲功能而無需
關注用戶如何使用,同樣的用戶只需要掛載pvc到容器中而不需要關注存儲卷采用何種技術實現。