標籤:pre ssi 創新 用戶端 問題 基礎架構 restart 附加 llb
1、基礎架構
1.1 Master
Master節點上面主要由四個模組組成:APIServer、scheduler、controller manager、etcd。
APIServer。APIServer負責對外提供RESTful的Kubernetes API服務,它是系統管理指令的統一入口,任何對資源進行增刪改查的操作都要交給APIServer處理後再提交給etcd。如架構圖中所示,kubectl(Kubernetes提供的用戶端工具,該工具內部就是對Kubernetes API的調用)是直接和APIServer互動的。
schedule。scheduler的職責很明確,就是負責調度pod到合適的Node上。如果把scheduler看成一個黑匣子,那麼它的輸入是pod和由多個Node組成的列表,輸出是Pod和一個Node的綁定,即將這個pod部署到這個Node上。Kubernetes目前提供了調度演算法,但是同樣也保留了介面,使用者可以根據自己的需求定義自己的調度演算法。
controller manager。如果說APIServer做的是“前台”的工作的話,那controller manager就是負責“後台”的。每個資源一般都對應有一個控制器,而controller manager就是負責管理這些控制器的。比如我們通過APIServer建立一個pod,當這個pod建立成功後,APIServer的任務就算完成了。而後面保證Pod的狀態始終和我們預期的一樣的重任就由controller manager去保證了。
etcd。etcd是一個高可用的KVStore for Redis系統,Kubernetes使用它來儲存各個資源的狀態,從而實現了Restful的API。
1.2 Node
每個Node節點主要由三個模組組成:kubelet、kube-proxy、runtime。
runtime。runtime指的是容器運行環境,目前Kubernetes支援docker和rkt兩種容器。
kube-proxy。該模組實現了Kubernetes中的服務發現和反向 Proxy功能。反向 Proxy方面:kube-proxy支援TCP和UDP串連轉寄,預設基於Round Robin演算法將用戶端流量轉寄到與service對應的一組後端pod。服務發現方面,kube-proxy使用etcd的watch機制,監控叢集中service和endpoint對象資料的動態變化,並且維護一個service到endpoint的映射關係,從而保證了後端pod的IP變化不會對訪問者造成影響。另外kube-proxy還支援session affinity。
kubelet。Kubelet是Master在每個Node節點上面的agent,是Node節點上面最重要的模組,它負責維護和管理該Node上面的所有容器,但是如果容器不是通過Kubernetes建立的,它並不會管理。本質上,它負責使Pod得運行狀態與期望的狀態一致。
至此,Kubernetes的Master和Node就簡單介紹完了。下面我們來看Kubernetes中的各種資源/對象。
2、Pod
Pod 是Kubernetes的基本操作單元,也是應用啟動並執行載體。整個Kubernetes系統都是圍繞著Pod展開的,比如如何部署運行Pod、如何保證Pod的數量、如何訪問Pod等。另外,Pod是一個或多個機關容器的集合,這可以說是一大創新點,提供了一種容器的組合的模型。
2.1 基本操作
建立 |
kubectl create -f xxx.yaml |
查詢 |
kubectl get pod yourPodName kubectl describe pod yourPodName |
刪除 |
kubectl delete pod yourPodName |
更新 |
kubectl replace /path/to/yourNewYaml.yaml |
2.2 Pod與容器
在Docker中,容器是最小的處理單元,增刪改查的對象是容器,容器是一種虛擬化技術,容器之間是隔離的,隔離是基於Linux Namespace實現的。而在Kubernetes中,Pod包含一個或者多個相關的容器,Pod可以認為是容器的一種延伸擴充,一個Pod也是一個隔離體,而Pod內部包含的一組容器又是共用的(包括PID、Network、IPC、UTS)。除此之外,Pod中的容器可以訪問共同的資料捲來實現檔案系統的共用。
2.3 鏡像
在kubernetes中,鏡像的下載策略為:
Always:每次都下載最新的鏡像
Never:只使用本地鏡像,從不下載
IfNotPresent:只有當本地沒有的時候才下載鏡像
Pod被分配到Node之後會根據鏡像下載策略進行鏡像下載,可以根據自身叢集的特點來決定採用何種下載策略。無論何種策略,都要確保Node上有正確的鏡像可用。
2.4 其他設定
通過yaml檔案,可以在Pod中設定:
啟動命令,如:spec-->containers-->command;
環境變數,如:spec-->containers-->env-->name/value;
連接埠橋接,如:spec-->containers-->ports-->containerPort/protocol/hostIP/hostPort(使用hostPort時需要注意連接埠衝突的問題,不過Kubernetes在調度Pod的時候會檢查宿主機連接埠是否衝突,比如當兩個Pod均要求綁定宿主機的80連接埠,Kubernetes將會將這兩個Pod分別調度到不同的機器上);
Host網路,一些特殊情境下,容器必須要以host方式進行網路設定(如接收物理機網路才能夠接收到的組播流),在Pod中也支援host網路的設定,如:spec-->hostNetwork=true;
資料持久化,如:spec-->containers-->volumeMounts-->mountPath;
重啟策略,當Pod中的容器終止退出後,重啟容器的策略。這裡的所謂Pod的重啟,實際上的做法是容器的重建,之前容器中的資料將會丟失,如果需要持久化資料,那麼需要使用資料卷進行持久化設定。Pod支援三種重啟策略:Always(預設策略,當容器終止退出後,總是重啟容器)、OnFailure(當容器終止且異常退出時,重啟)、Never(從不重啟);
2.5 Pod生命週期
Pod被分配到一個Node上之後,就不會離開這個Node,直到被刪除。當某個Pod失敗,首先會被Kubernetes清理掉,之後ReplicationController將會在其它機器上(或本機)重建Pod,重建之後Pod的ID發生了變化,那將會是一個新的Pod。所以,Kubernetes中Pod的遷移,實際指的是在新Node上重建Pod。以下給出Pod的生命週期圖。
生命週期回呼函數:PostStart(容器建立成功後調研該回呼函數)、PreStop(在容器被終止前調用該回呼函數)。以下樣本中,定義了一個Pod,包含一個JAVA的web應用程式容器,其中設定了PostStart和PreStop回呼函數。即在容器建立成功後,複製/sample.war到/app檔案夾中。而在容器終止之前,發送HTTP請求到http://monitor.com:8080/waring,即向監控系統發送警告。具體樣本如下:
………..containers:- image: sample:v2 name: war lifecycle: posrStart: exec: command: - “cp” - “/sample.war” - “/app” prestop: httpGet: host: monitor.com psth: /waring port: 8080 scheme: HTTP
3、Replication Controller
Replication Controller(RC)是Kubernetes中的另一個核心概念,應用託管在Kubernetes之後,Kubernetes需要保證應用能夠持續運行,這是RC的工作內容,它會確保任何時間Kubernetes中都有指定數量的Pod在運行。在此基礎上,RC還提供了一些更進階的特性,比如滾動升級、升級復原等。
3.1 RC與Pod的關聯——Label
RC與Pod的關聯是通過Label來實現的。Label機制是Kubernetes中的一個重要設計,通過Label進行對象的弱關聯,可以靈活地進行分類和選擇。對於Pod,需要設定其自身的Label來進行標識,Label是一系列的Key/value對,在Pod-->metadata-->labeks中進行設定。
Label的定義是任一的,但是Label必須具有可標識性,比如設定Pod的應用程式名稱和版本號碼等。另外Lable是不具有唯一性的,為了更準確的標識一個Pod,應該為Pod設定多個維度label。如下:
"release" : "stable", "release" : "canary"
"environment" : "dev", "environment" : "qa", "environment" : "production"
"tier" : "frontend", "tier" : "backend", "tier" : "cache"
"partition" : "customerA", "partition" : "customerB"
"track" : "daily", "track" : "weekly"
舉例,當你在RC的yaml檔案中定義了該RC的selector中的label為app:my-web,那麼這個RC就會去關注Pod-->metadata-->labeks中label為app:my-web的Pod。修改了對應Pod的Label,就會使Pod脫離RC的控制。同樣,在RC運行正常的時候,若試圖繼續建立同樣Label的Pod,是建立不出來的。因為RC認為副本數已經正常了,再多起的話會被RC刪掉的。
3.2 Auto Scaling
Auto Scaling是指適應負載變化,以彈性可伸縮的方式提供資源。反映到Kubernetes中,指的是可根據負載的高低動態調整Pod的副本數量。調整Pod的副本數是通過修改RC中Pod的副本是來實現的,樣本命令如下:
擴容Pod的副本數目到10
$ kubectl scale relicationcontroller yourRcName --replicas=10
縮容Pod的副本數目到1
$ kubectl scale relicationcontroller yourRcName --replicas=1
3.3 滾動升級
滾動升級是一種平滑過渡的升級方式,通過逐步替換的策略,保證整體系統的穩定,在初始升級的時候就可以及時發現、調整問題,以保證問題影響度不會擴大。Kubernetes中滾動升級的命令如下:
$ kubectl rolling-update my-rcName-v1 -f my-rcName-v2-rc.yaml --update-period=10s
升級開始後,首先依據提供的定義檔案建立V2版本的RC,然後每隔10s(--update-period=10s)逐步的增加V2版本的Pod副本數,逐步減少V1版本Pod的副本數。升級完成之後,刪除V1版本的RC,保留V2版本的RC,及實現滾動升級。
升級過程中,發生了錯誤中途退出時,可以選擇繼續升級。Kubernetes能夠智能的判斷升級中斷之前的狀態,然後緊接著繼續執行升級。當然,也可以進行回退,命令如下:
$ kubectl rolling-update my-rcName-v1 -f my-rcName-v2-rc.yaml --update-period=10s --rollback
回退的方式實際就是升級的逆操作,逐步增加V1.0版本Pod的副本數,逐步減少V2版本Pod的副本數。
4、Job
從程式的運行形態上來區分,我們可以將Pod分為兩類:長時運行服務(jboss、mysql等)和一次性任務(資料計算、測試)。RC建立的Pod都是長時啟動並執行服務,而Job建立的Pod都是一次性任務。
在Job的定義中,restartPolicy(重啟策略)只能是Never和OnFailure。Job可以控制一次性任務的Pod的完成次數(Job-->spec-->completions)和並發執行數(Job-->spec-->parallelism),當Pod成功執行指定次數後,即認為Job執行完畢。
5、Service
為了適應快速的業務需求,微服務架構已經逐漸成為主流,微服務架構的應用需要有非常好的服務編排支援。Kubernetes中的核心要素Service便提供了一套簡化的服務代理和發現機制,天然適應微服務架構。
5.1 原理
在Kubernetes中,在受到RC調控的時候,Pod副本是變化的,對於的虛擬IP也是變化的,比如發生遷移或者伸縮的時候。這對於Pod的訪問者來說是不可接受的。Kubernetes中的Service是一種抽象概念,它定義了一個Pod邏輯集合以及訪問它們的策略,Service同Pod的關聯同樣是居於Label來完成的。Service的目標是提供一種橋樑, 它會為訪問者提供一個固定訪問地址,用於在訪問時重新導向到相應的後端,這使得非 Kubernetes原生應用程式,在無須為Kubemces編寫特定代碼的前提下,輕鬆訪問後端。
Service同RC一樣,都是通過Label來關聯Pod的。當你在Service的yaml檔案中定義了該Service的selector中的label為app:my-web,那麼這個Service會將Pod-->metadata-->labeks中label為app:my-web的Pod作為分發請求的後端。當Pod發生變化時(增加、減少、重建等),Service會及時更新。這樣一來,Service就可以作為Pod的訪問入口,起到Proxy 伺服器的作用,而對於訪問者來說,通過Service進行訪問,無需直接感知Pod。
需要注意的是,Kubernetes分配給Service的固定IP是一個虛擬IP,並不是一個真實的IP,在外部是無法定址的。真實的系統實現上,Kubernetes是通過Kube-proxy組件來實現的虛擬IP路由及轉寄。所以在之前叢集部署的環節上,我們在每個Node上均部署了Proxy這個組件,從而實現了Kubernetes層級的虛擬轉寄網路。
5.2 Service代理外部服務
Service不僅可以代理Pod,還可以代理任意其他後端,比如運行在Kubernetes外部Mysql、Oracle等。這是通過定義兩個同名的service和endPoints來實現的。樣本如下:
mysql-service.yaml
apiVersion: v1kind: Servicemetadata: name: mysqlspec: ports: - port: 3306targetPort: 3306protocol: TCP
mysql-endpoints.yaml
apiVersion: v1kind: Endpointsmetadata: name: mysqlsubsets:- addresses: - ip: 192.168.31.22 ports: 3306 protocol: TCP
基於檔案建立完Service和Endpoints之後,在Kubernetes的Service中即可查詢到自訂的Endpoints。
5.3 Service內部負載平衡
當Service的Endpoints包含多個IP的時候,及服務代理存在多個後端,將進行請求的負載平衡。預設的負載平衡策略是輪訓或者隨機(有kube-proxy的模式決定)。同時,Service上通過設定Service-->spec-->sessionAffinity=ClientIP,來實現基於源IP地址的會話保持。
5.4 發布Service
Service的虛擬IP是由Kubernetes虛擬出來的內部網路,外部是無法定址到的。但是有些服務又需要被外部存取到,例如web前段。這時候就需要加一層網路轉寄,即外網到內網的轉寄。Kubernetes提供了NodePort、LoadBalancer、Ingress三種方式。
NodePort,在之前的Guestbook樣本中,已經延時了NodePort的用法。NodePort的原理是,Kubernetes會在每一個Node上暴露出一個連接埠:nodePort,外部網路可以通過(任一Node)[NodeIP]:[NodePort]訪問到後端的Service。
LoadBalancer,在NodePort基礎上,Kubernetes可以請求底層雲平台建立一個負載平衡器,將每個Node作為後端,進行服務分發。該模式需要底層雲平台(例如GCE)支援。
Ingress,是一種HTTP方式的路由轉寄機制,由Ingress Controller和HTTPProxy 伺服器組合而成。Ingress Controller即時監控Kubernetes API,即時更新HTTPProxy 伺服器的轉寄規則。HTTPProxy 伺服器有GCE Load-Balancer、HaProxy、Nginx等開源方案。
6、Deployment
Kubernetes提供了一種更加簡單的更新RC和Pod的機制,叫做Deployment。通過在Deployment中描述你所期望的叢集狀態,Deployment Controller會將現在的叢集狀態在一個可控的速度下逐步更新成你所期望的叢集狀態。Deployment主要職責同樣是為了保證pod的數量和健康,90%的功能與Replication Controller完全一樣,可以看做新一代的Replication Controller。但是,它又具備了Replication Controller之外的新特性:
Replication Controller全部功能:Deployment繼承了上面描述的Replication Controller全部功能。
事件和狀態查看:可以查看Deployment的升級詳細進度和狀態。
復原:當升級pod鏡像或者相關參數的時候發現問題,可以使用復原操作復原到上一個穩定的版本或者指定的版本。
版本記錄: 每一次對Deployment的操作,都能儲存下來,給予後續可能的復原使用。
暫停和啟動:對於每一次升級,都能夠隨時暫停和啟動。
多種升級方案:Recreate----刪除所有已存在的pod,重新建立新的; RollingUpdate----滾動升級,逐步替換的策略,同時滾動升級時,支援更多的附加參數,例如設定最大不可用pod數量,最小升級間隔時間等等。
6.1 滾動升級
相比於RC,Deployment直接使用kubectl edit deployment/deploymentName 或者kubectl set方法就可以直接升級(原理是Pod的template發生變化,例如更新label、更新鏡像版本等操作會觸發Deployment的滾動升級)。操作樣本——首先 我們同樣定義一個nginx-deploy-v1.yaml的檔案,副本數量為2:
apiVersion: extensions/v1beta1kind: Deploymentmetadata: name: nginx-deploymentspec: replicas: 3 template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.7.9 ports: - containerPort: 80
建立deployment:
$ kubectl create -f nginx-deploy-v1.yaml --recorddeployment "nginx-deployment" created$ kubectl get deploymentsNAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGEnginx-deployment 3 0 0 0 1s$ kubectl get deploymentsNAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGEnginx-deployment 3 3 3 3 18s
正常之後,將nginx的版本進行升級,從1.7升級到1.9。第一種方法,直接set鏡像:
$ kubectl set image deployment/nginx-deployment2 nginx=nginx:1.9deployment "nginx-deployment2" image updated
第二種方法,直接edit:
$ kubectl edit deployment/nginx-deploymentdeployment "nginx-deployment2" edited
最後介紹下Deployment的一些基礎命令:
$ kubectl describe deployments #查詢詳細資料,擷取升級進度$ kubectl rollout pause deployment/nginx-deployment2 #暫停升級$ kubectl rollout resume deployment/nginx-deployment2 #繼續升級$ kubectl rollout undo deployment/nginx-deployment2 #升級復原
關於多重升級,舉例,當你建立了一個nginx1.7的Deployment,要求副本數量為5之後,Deployment Controller會逐步的將5個1.7的Pod啟動起來;當啟動到3個的時候,你又發出更新Deployment中Nginx到1.9的命令;這時Deployment Controller會立即將已啟動的3個1.7Pod殺掉,然後逐步啟動1.9的Pod。Deployment Controller不會等到1.7的Pod都啟動完成之後,再依次殺掉1.7,啟動1.9。
6.2 升級復原
升級完成之後,若發現新版本不穩定,或不符合業務需求,可進行後援動作。假設我們在剛剛完成升級的nginx1.9中發現了錯誤,那麼可以通過以下命令進行復原。
$ kubectl set image deployment/nginx-deployment nginx=nginx:1.91deployment "nginx-deployment" image updated$ kubectl rollout status deployments nginx-deployment Waiting for rollout to finish: 2 out of 3 new replicas have been updated...
Kubernetes基礎概念總結