當(dāng)我們的web應(yīng)用跑在容器中,如何擴(kuò)容?如何管理容器間的調(diào)用,負(fù)載均衡?自己手動新建nginx管理?自己手動改代碼完成?不用。已經(jīng)有大牛為我們造好了輪子---Kubernetes,它是一個容器控制平臺。
Kubernetes 通過一個簡單的 API 提供底層基礎(chǔ)設(shè)施的抽象,我們可以向該 API 發(fā)送請求。這些請求可以讓 Kubernetes 盡最大能力應(yīng)對。例如,可以簡單地要求“Kubernetes 添加映像 x 的 4 個容器。”然后 Kubernetes 會找出使用中的節(jié)點(diǎn),并在內(nèi)添加新的容器。
這對開發(fā)人員來說意味著什么?意味著開發(fā)人員不需要在意節(jié)點(diǎn)的數(shù)目,也不需要在意從哪里運(yùn)行容器以及如何與它們交流。開發(fā)人員不需要管理硬件優(yōu)化,或擔(dān)心節(jié)點(diǎn)關(guān)閉(它們將遵循墨菲法則),因?yàn)樾碌墓?jié)點(diǎn)會添加到 Kubernetes 集群。同時 Kubernetes 會在其他運(yùn)行的節(jié)點(diǎn)中添加容器。Kubernetes 會發(fā)揮最大的作用。
在圖中我們看到了一些新東西:
API服務(wù)器:與集群交互的唯一方式。負(fù)責(zé)啟動或停止另外一個容器,或檢查當(dāng)前狀態(tài),日志等;
Kubelet:監(jiān)視節(jié)點(diǎn)內(nèi)的容器,并與主節(jié)點(diǎn)交流;
Pod:初始階段我們可以把 pod 當(dāng)成容器。
Pod
Kubernetes 給我們最小的可部署計算單元 Pod 。它可以理解為一個邏輯宿主機(jī),可以啟動一個或者多個容器,這些容器共享同一個端口空間,他們可以通過 localhost 交流,與其他 Pod 內(nèi)容器的交流可以通過結(jié)合 Pod 的 IP 完成。
一個 Pod 內(nèi)的容器共享同一個卷、同一個 IP、端口空間、IPC 命名空間。
注:容器有個自己獨(dú)立的文件系統(tǒng),盡管他們可以通過 Kubernetes 的資源卷共享數(shù)據(jù)
pod.yaml文件編寫方式:
apiVersion: v1
kind: Pod
metadata:
name: sa-frontend
labels:
app: sa-frontend
spec:
containers:
- image: rinormaloku/sentiment-analysis-frontend
name: sa-frontend
ports:
- containerPort: 80
- kind:指定我們想創(chuàng)建的 Kubernetes 資源的類型。這里是 Pod。
- name:定義該資源的名字。我們在這里命名為 sa-frontend。
- spec:該對象定義了資源應(yīng)有的狀態(tài)。Pod Spec 中最重要的屬性是容器的數(shù)組。
- image:是指我們希望在本 Pod 中啟動的容器的映像。
- name:Pod 中容器中唯一的名字。
- containerPort:是指容器監(jiān)聽的端口號。
終端輸入
kubectl apply -f pod.yaml
創(chuàng)建pod
Service
Kubernetes 服務(wù)資源可以作為一組提供相同服務(wù)的 Pod 的入口。這個資源肩負(fù)發(fā)現(xiàn)服務(wù)和平衡 Pod 之間負(fù)荷的重任。
在 Kubernetes 集群內(nèi),我們擁有提供不同服務(wù)的 Pod(前端、Spring 網(wǎng)絡(luò)應(yīng)用和 Flask Python 應(yīng)用程序)。所以這里的問題是:服務(wù)如何知道該處理哪個 Pod?例如:它如何生成這些 Pod 的終端列表?
這個問題可以用標(biāo)簽來解決,具體分兩個步驟:
- 給所有服務(wù)處理的對象 Pod 貼上標(biāo)簽(label);
- 在服務(wù)中使用一個選擇器(selector),該選擇器定義了所有貼有標(biāo)簽的對象 Pod。

service.yaml文件編寫方式:
apiVersion: v1
kind: Service
metadata:
name: sa-frontend-lb
spec:
type: LoadBalancer
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: sa-frontend
- kind:服務(wù);
- type:指定類型,我們選擇 LoadBalancer,因?yàn)槲覀兿肫胶?Pod 之間的負(fù)荷;
- ports:指定服務(wù)獲取請求的端口;
- protocol:定義交流;#5 targetPort:可以將來訪的請求轉(zhuǎn)發(fā)到這個端口;
- selector:包含選擇pod屬性的對象;
- app:sa-frontend定義了哪個是目標(biāo) Pod,只有擁有標(biāo)簽“app: sa-frontend”的才是目標(biāo) Pod。
終端輸入
kubectl apply -f service.yaml
創(chuàng)建service
Deployment
Kubernetes 部署可以幫助每一個應(yīng)用程序的生命都保持相同的一點(diǎn):那就是變化。此外,只有掛掉的應(yīng)用程序才會一塵不變,否則,新的需求會源源不斷地涌現(xiàn),更多代碼會被開發(fā)出來、打包以及部署。這個過程中的每一步都有可能出錯。
部署資源可以自動化應(yīng)用程序從一版本升遷到另一版本的過程,并保證服務(wù)不間斷,如果有意外發(fā)生,它可以讓我們迅速回滾到前一個版本。
現(xiàn)在我們有兩個 Pod 和一個服務(wù)開放,而且它們之間有負(fù)載均衡。我們提到過現(xiàn)有的 Pod 還遠(yuǎn)遠(yuǎn)不夠完美。需要分開管理每一個 Pod(創(chuàng)建、更新、刪除和監(jiān)視他們的情況)??焖俑潞脱杆倩貪L根本不可能!這樣是不行的,部署 Kubernetes 資源可以解決這里的每個問題。

deployment.yaml文件編寫方式:
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: sa-frontend
spec:
replicas: 2
minReadySeconds: 15
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
maxSurge: 1
template:
metadata:
labels:
app: sa-frontend
spec:
containers:
- image: rinormaloku/sentiment-analysis-frontend
imagePullPolicy: Always
name: sa-frontend
ports:
- containerPort: 80
- kind:部署;
- replicas:是部署 Spec 對象的一個屬性,定義了我們想運(yùn)行多少的 Pod。所以是 2;
- type:指定從當(dāng)前版本升遷到下個版本的時候,部署使用的策略。此處的策略 RollingUpdate 可以保證部署期間服務(wù)不間斷;
- maxUnavailable:是 RollingUpdate 對象的一個屬性,定義了在升級的時候,最大允許停止的 Pod 數(shù)量(與希望的狀態(tài)相比)。對我們的部署來說,我們有 2 個副本,這意味著在一個 Pod 停止后,我們還會有另外一個 Pod 運(yùn)行,所以可以保證應(yīng)用程序可訪問;
- maxSurge:是 RollingUpdate 對象的另一個屬性,定義了添加到部署的最大 Pod 數(shù)量(與希望的狀態(tài)相比)。對我們的部署來說,這意味著在向新版本遷移的時候,我們可以加一個 Pod,那么我們可以同時擁有個 3 個 Pod;
- template:指定 Pod 的模板,部署在創(chuàng)建新 Pod 的時候,會用到該模板。很可能這個非常相似的 Pod 會立即吸引你;
- app: sa-frontend:根據(jù)模板創(chuàng)建的 Pod 將被貼上該標(biāo)簽;
- imagePullPolicy:當(dāng)設(shè)置成 Always 的時候,每一次新部署都會重新獲取容器映像。
終端輸入
kubectl apply -f deployment.yaml
創(chuàng)建deployment