轉載請注明出處:葡萄城官網,葡萄城為開發者提供專業的開發工具、解決方案和服務,賦能開發者。
第一章:Docker與k8s的恩怨情仇(一)—成為PaaS前浪的Cloud Foundry
第二章:Docker與k8s的恩怨情仇(二)—用最簡單的技術實現“容器”
第三章:Docker與k8s的恩怨情仇(三)—后浪Docker來勢洶洶
第四章:Docker與k8s的恩怨情仇(四)-雲原生時代的閉源落幕
Docker與k8s的恩怨情仇(五)——Kubernetes的創新
在上節中,我們為大家介紹了Pod的基礎內容,Kubernetes如何站在上帝視角上處理容器和容器之間的關系。但僅僅有Pod卻還不夠,對於大部分用戶而言如何調度和管理自己的應用才是真正核心的問題,而對這一內容的解決方案才是Kubernetes最終極大殺器。
Pod間的編排管理
讓我們從一個例子出發,假設現在的用戶需求是:
以3機負載均衡的形式部署一個私有雲客戶的活字格應用,應該如何實現呢?
Docker的“古典”做法
在活字格開發組之前開發的版本中,實現方法大概是這樣:使用三個不同的物理機,先把用戶的應用run成容器,然后安裝在在這三個物理機上,在三台服務器之外再買一個負載均衡服務,最后通過域名解析配置,將流量分別導向三個不同的服務機。
聽起來似乎也挺簡單的。
但是在現實中,我們會遇到考慮其他問題,比如: 如果我們只有兩台服務器呢?如果有一台服務器中的container掛了呢?如果兩台服務器CPU跑滿了呢?
這些調度方面的內容看起來很簡單,但是實現起來卻需要長時間的編碼和調試。而且一通輸出之后,最終做出來也可能只是個Docker Swarm而已。
Kubernetes里的容器編排
現在我們把上述需求看做是我們最終的目標,來看kubernetes是如何一步一步進行容器編排從而解決了這個問題。相信大家看完這部分內容之后,以上問題便會迎刃而解。
Kubernetes所做的容器編排核心內容其實是Pod編排,如何讓這些Pod配合起來協同工作,則是編排的核心。在上一節中我們一起了解了kubernetes所做的是將各種關系進行了抽象,這些關系本質其實是Pod之間的關系。kubernetes將Pod的關系抽象成了以下幾種,並且為這些關系定義了相對的控制器便於進行編排管理:
l 無狀態Pod副本之間的協同關系——Deployment
l 有狀態Pod副本之間的拓撲關系——StatefulSet
l 容器化守護進程——DaemonSet
l 離線業務——Job和CronJob
這些概念看起來可能讓你有些不知所雲,其實這些內容只是不同上述的控制器對Pod的不同的管理方式而已。
限於篇幅和對這部分內容的理解深度,這里我們將只分享活字格公有雲版開發組中最多使用到kubernetes最常用的一種控制器——Deployment。
Deployment控制器功能介紹
我們先解釋什么是控制器:控制器是kubernetes中管理待編排對象的程序,我們把一個對象管理另一個對象的模式稱為控制器模式。
kubernetes中的所有待編排對象都是通過控制器模式管理的。
其核心就是一個死循環,在循環中不停地判斷當前編排對象的狀態,如果不滿足預期狀態就更新它,如下的偽代碼就是描述一個控制器的工作原理:
Deployment控制器的功能是:維護多個相同的無狀態Pod副本以規定的數量運行,並且支持水平擴展以及滾動更新。
有了這個控制,為了實現我們的最終需求——負載均衡中的活字格服務,這個Pod就可以通過Deployment管理。我們可以通過Deployment讓我們的Pod在kubernetes集群中始終以3個副本的形式存在。
只需要用Deployment來編排我們定義的Pod,並且要求副本數量是3,Deployment控制循環中就會不停地判斷我們的Pod的副本數量是否是3,如果不是,就會觸發水平擴展功能進行調整,最終達到滿足期望狀態(副本數==3)。
Deployment工作原理演示
介紹了這么多,我們從實例出發為大家演示Deployment是如何工作的。
由於活字格的鏡像配置過於復雜,因此這里我們通過一個Nginx的多副本配置來感受一下Deployment控制器的控制結果。
我們可以通過以下yaml定義一個維護了3個nginx副本的deployment:
其實Kubernetes在最初的版本中只有ReplicaSet這種控制器模式,控制的是多副本Pod編排邏輯,后來出現了滾動更新邏輯,為了解決滾動更新的需求,在ReplicaSet基礎上擴展出了Deployment。
apiVersion: apps/v1
kind: Deployment
metadata:
name: sample-deployment-nginx
spec:
selector:
matchLabels:
app: sample-deployment-nginx
replicas: 3
template:
metadata:
labels:
app: sample-deployment-nginx
spec:
containers:
- name: sample-nginx
image: nginx:1.9.1
ports:
- containerPort: 80
這里出現了三個特殊字段:
1. selector:選擇器,類似於js中的選擇器,其功能就是選擇指定的pod運行,這個實例中我們指定所有app==sample-deployment-nginx的pod才會被這個Deployment所部署
2. replicas:指明這個Deployment維護的副本個數
3. template:控制器中提供了template這個語法,可以讓我們直接在控制器的yaml中直接編寫所需要編排的Pod信息
編寫完這個sample-deployment-nginx.yaml后,執行一下:
kubectl apply -f sample-deployment-nginx.yaml
這個三副本的控制器就被成功運行了,使用該指令查看運行結果:
kubectl get pods -l app=sample-deployment-nginx
可以看到3副本Pod已經成功在kubernetes中運行了
如果這時我們執行以下命令刪除podname==sample-deployment-nginx-54545f95cd-wtllm的副本
kubectl delete pod sample-deployment-nginx-54545f95cd-wtllm
可以自動生成一個新的pod來維持replicas==3:
通過上述實例,我們可以看到Deployment控制器對副本數量的控制結果,其實是ReplicaSet控制器在控制副本的數量。Deployment是ReplicaSet控制器的控制器,這種多層之間相互控制的模式在kubernetes也十分常見,其之間的關系如下圖所示:
至此,一個deployment管理pod的所有功能都已經展示完成了,可以看到kubernetes中控制器管理之間的精巧關系:多個控制器協同工作,既保證精准控制,也能拆分進程阻塞從而提升性能。
其他控制器的介紹
當你理解了deployment控制器,就很容易理解其他控制器的工作原理。
在這里我們簡單做個說明,為大家介紹其他控制器的控制邏輯:
l StatefulSet:控制滿足有拓撲狀態或者持久化存儲的Pod,拓撲狀態的意思就是Pod之間存在明確的先后生成關系,持久化存儲就是當副本被刪除或者修改了,其內部保存的數據還會存在
l DaemonSet:守護進程控制器,是一個Node(服務器節點)僅能存在一個的Pod,比如系統的日志采集器等就應該用這種方式調度
l Job與CronJob:Job就是任務調度,一個Pod在調度完成后就結束了不會再有新的任務產生,Job用於維護一個任務Pod運行中的各種狀態正常,異常狀態重啟等。對應的CronJob就是定時任務,使用過Quartz的同學一定不陌生
總結
綜上,kubernetes中就是通過上述的各種控制器維護所有Pod的編排工作的,並且其還提供了完善的API可以讓用戶自行定義滿足自己需求的各種Pod編排控制器。但是對於deployment本文只是簡單的展示了一些常用的功能點,其內部還有滾動更新的最大資源、金絲雀發布和灰度發布等各種功能需要繼續細致的學習。
本章中以活字格為例,為大家介紹了k8s容器編排部分的實現。在下節中我們將繼續為大家分享,為了實現這個終極需求的另一部分——如何實現 “人與狗的交往過程”。