1 Deployment
1.1 什麼是deployment
Deployment(簡稱為deploy)是Kubernetes控制器的一種高級別實現,他構建於ReplicaSet控制器之上。
我們只需要描述Deployment中的目標Pod期望狀態,而Deployment控制器以受控速率更改實際狀態,使其變為期望狀態,也就是説,後期我們部署應用不直接使用Pod和ReplicaSet,
而是使用Deployment控制器來調用ReplicaSet來實現,Deployment控制器在ReplicaSet原有基礎上,添加了部分特性:
- 事件和狀態查看:可以通過特定的命令查看Deployment對象的更新進度和狀態;
- 版本記錄:將Deployment對象的更新操作都進行保存,以便後續執行回滾操作使用;
- 多種更新方案:Recreate重建,可以實現單批次更新所有Pod。RollingUpdate可以實現多批次逐步替換Pod;
1.2 deployment組成部分
Deployment資源對象的格式和ReplicaSet幾乎一致,Deployment控制器也包含了3個基本的組成部分:
- selector 標籤選擇器:匹配並關聯Pod對象,並對授其管控的Pod對象計數;
- replicas 期望的副本數:期望在集羣中所運行的Pod對象數量;
- template Pod模板:實際上就是定義Pod內容,相當於把一個Pod的描述以模板形式嵌入到了ReplicaSet;
1.3 deployment配置示例
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-nginx
namespace: default
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
2 Deployment場景實踐
2.1 場景説明
運行一個demoapp的應用,部署3個副本,然後通過service來實現負載均衡
- 創建Deployment資源,部署三個副本;
- 創建Service資源,通過標籤選擇器選擇對應的Pod,以實現負載均衡;
- 使用curl命令驗證集羣高可用;
2.2 創建應用集羣
cat deploy-demoapp.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-demoapp
spec:
replicas: 3
selector:
matchLabels:
app: demoapp
template:
metadata:
labels:
app: demoapp
spec:
containers:
- name: nginx
image: nginx:latest
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
lifecycle:
postStart:
exec:
command: ["sh", "-c", "echo demoapp v1.0!! NodeName: ${node_name} PodIP: ${pod_ip} > /usr/share/nginx/html/index.html"]
env:
- name: pod_ip
valueFrom:
fieldRef:
fieldPath: status.podIP
- name: node_name
valueFrom:
fieldRef:
fieldPath: spec.nodeName
2.3 檢查集羣狀態
1、檢查集羣的Deployment
- NAME: 列出了集羣中Deployment的名稱;
- READY: 顯示應用程序的可用的"副本"數。顯示的模式是"就緒個數/期望個數";
- UP-TO-DATE: 顯示為了達到期望狀態已經更新的副本數;
- AVAILABLE: 顯示應用可供用户使用的副本數;
- AGE: 顯示應用程序運行的時間;
2、檢查集羣的ReplicaSet
- NAME: 列出名稱空間中ReplicaSet的名稱;
- DESIRED: 顯示應用的期望副本個數,即在創建Deployment時所定義的值。此為期望狀態;
- CURRENT: 顯示當前運行狀態中的副本個數;
- READY: 顯示應用中有多少副本可以為用户提供服務;
- AGE: 顯示應用已經運行的時間長度
注意ReplicaSet的名稱被格式化為[Deployment名稱]-[隨機字符串]
3、檢查集羣的Pod,所創建的ReplicaSet確保總是存在三個Pod。
2.4 創建Service
cat service-demoapp.yml
apiVersion: v1
kind: Service
metadata:
name: svc-demoapp
spec:
selector:
app: demoapp
ports:
- port: 80
targetPort: 80
查看對應的service地址
2.5 驗證集羣高可用
2.6 水平伸縮
修改replicas對應的副本數即可。
1、命令方式修改
kubectl scale deploy deploy-demoapp --replicas=6
2、通過yaml來實現
kubectl edit deploy deploy-demoapp
3 Deployment重建策略
3.1 什麼是Recreate
重建(Recreate),當更新策略設定為Recreate,在更新鏡像時,它會先殺死正在運行的Pod,等徹底殺死以後,重新創建新的RS,然後啓動對應的Pod,那麼在這個更新過程中,會造成服務一段時間無法提供服務;
第一步:同時殺死所有舊版本的Pod,此時Pod無法正常對外提供服務;
第二步:創建新的RS,啓動新的Pod;
第三步:等待Pod就緒,對外提供服務;
3.2 Recreate實踐
1、創建deploy資源,然後將更新策略設定為Recreate,而後修訂鏡像版本
cat deploy-recreate.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-nginx
spec:
strategy:
type: Recreate
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.42
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
2、觀察更新過程
將nginx鏡像版本修改為1.43
通常只有當應用的新舊版本不兼容(例如依賴的後端數據的格式不同且無法兼容)時才會使用Recreate重建策略。
4 Deployment滾動更新
4.1 什麼是滾動更新
滾動更新(RollingUpdate),一次僅更新一批Pod,當更新的Pod就緒後,再更新另一批,直到全部更新完成為止;該策略實現了不間斷服務的目標,在更新過程中可能會出現不同的應用版本並存,同時提供服務的情況。
第一步:創建新的ReplicaSet,然後根據新的鏡像運行新的Pod;
第二步:刪除舊的Pod,啓動新的Pod,新Pod就緒後,繼續刪除酒Pod,啓動新Pod;
第三步:持續第二步過程,一直到所有Pod都被更新成功;
4.2 滾動更新實踐
1、準備yml文件
cat deploy-rollingupdate.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-nginx
spec:
strategy:
type: RollingUpdate
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.43
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
2、觀察更新過程
4.3 應用回退實踐
有些時候,想要回滾Deployment。例如,當Deployment不穩定進入反覆崩潰狀態。默認情況下,Deployment的所有上線記錄都保留在系統中,以便可以隨時回滾。
可以通過修改revisionHistoryLimit調整保留的數量,默認10條。
1、首先檢查Deployment上線的歷史版本
kubectl rollout history deploy deploy-nginx
2、查看每個version對應的具體信息
3、確認要回退的revision,然後執行回退命令即可
kubectl rollout undo deploy deploy-nginx --to-revisinotallow=1
原先的版本1變成了新的版本3
5 Deployment更新策略
Deployment會在.spec.strategy.type=RollingUpdate時。採取滾動更新的方式更新Pod。可以指定maxUnavailable和maxSurge來控制滾動更新的過程
maxSurge:最大可用Pod
用來指定可以創建超出期望Pod個數的Pod數量。可以是數字,也可以是百分比(例如10%),此字段的默認值為25%。
例如,當此值為20%時,啓動滾動更新後,會立即對新的ReplicaSet擴容,同時保證新舊Pod的總數不超過所需Pod總數的120%。一旦舊Pod被殺死,新的ReplicaSet可以進一步擴容,同時確保更新期間任何時候運行中的Pod總數最多為所需Pod總數的120%。計算公式:10+(10*20%)=12
maxUnavailable:最大不可用Pod
用來指定更新過程中不可用的Pod的個數上限。可以是數字,也可以是百分比(例如10%),此字段的默認值為25%
例如,當此值設置為20%時,滾動更新開始時立即將舊ReplicaSet縮容到期望Pod個數的80%,然後新Pod準備就緒後,繼續縮容舊有的ReplicaSet,然後對新的ReplicaSet擴容,確保在更新期間可用的Pod總數在任何時候都是所需的Pod個數的80%。計算公式:10-(10*20%)=8
和maxUnavailable兩個屬性協同工作,可組合定義出三種不同的策略完成多批次的應用更新。
- 先增新,後減舊:將maxSurge設置為30%,將maxUnavailable的值設置為0;
- 先減舊,後增新:將maxUnavailable設置為30%,將maxSurge的值設置為0;
- 同時增減,將maxSurge和maxUnavailable分別設定為20%,期望是12Pod,至少就緒8個Pod;
5.1 maxSurge
5.2 maxUnavailable
5.3 maxSurge和maxUnavailable
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-nginx
spec:
strategy:
rollingUpdate:
maxSurge: 20%
maxUnavailable: 20%
type: RollingUpdate
replicas: 10
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.42
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
5.4 minReadySeconds
Deployment支持使用.spec.minReadySeconds字段來控制滾動更新的速度,默認值為0,表示新建的Pod對象一旦"就緒"將立即被視作可用,隨後即可開始下一輪更新過程。如果設定了spec.minReadySeconds: 3即表示新建的Pod對象至少要成功運行多久才會被視作可用,即就緒之後海耀等待指定的3s才能開始下一批次的更新。在一個批次內新建的所有Pod就緒後在轉為可用狀態前,更新操作會被堵塞,並且任何一個Pod就緒探測失敗,都會導致滾動更新被終止。
因此,為minReadySeconds設定一個合理的值,不僅能夠減緩更新的速度,還能夠讓Deployment提前發現一部分程序因為Bug導致的升級故障。
5.5 revisionHistoryLimit
Deployment保留一部分更新歷史中舊版本的ReplicaSet對象,當我們執行回滾操作的時候,就直接使用舊版本的ReplicaSet,在Deployment資源保存歷史版本數量有spec.revisionHistoryLimit屬性進行定義。
5.6 progressDeadlineSeconds
滾動更新故障超時時長,默認為600秒,k8s在升級過程中有可能由於各種原因升級卡住(這個時候還沒有明確的升級失敗),比如在拉取被牆的鏡像、權限不夠等錯誤。如果配置progressDeadlineSeconds,當達到了時間如果還卡着,則會上報這個異常情況,這個時候Deployment狀態就會被標記為False,並且註明原因。但是它並不會阻止Deployment繼續進行卡住後面的升級操作。
6 Deployment實現灰度發佈
灰度發佈(又名金絲雀發佈)是指黑與白之間,能夠平滑過渡的一種發佈方式,在上面可以進行A/B Testing
首先讓所有用户使用產品特性A(舊版本);
其次讓一部分人開始使用產品特性B(新版本),前端服務將通過選擇標籤的相同子集來覆蓋兩套副本,這樣,流量會被轉發到兩個應用;
最後如果用户對產品特性B沒有反對意見,那麼逐步擴充新版本,逐步縮減舊版本,直到新版本達到期望應用數量,舊版本下線;
使用灰度發佈的模式,可以及時發現問題,調整問題,以減少影響的範圍,保證整體系統的穩定運行。
如果新版本沒有問題,那麼逐步擴大新版本的訪問流量,然後減少舊版本的訪問流量。
最後刪除舊版本的Deployment,或者將ReplicaSet副本數設定為0,至此所有的流量都進入新版本。
6.1 部署1.0版本應用
cat deploy-demoapp10.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-demoapp10
spec:
replicas: 3
selector:
matchLabels:
app: demoapp
version: v10
template:
metadata:
labels:
app: demoapp
version: v10
spec:
containers:
- name: demoapp
image: nginx:latest
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
lifecycle:
postStart:
exec:
command: ["sh", "-c", "echo demoapp v1.0!! NodeName: ${node_name} PodIP: ${pod_ip} > /usr/share/nginx/html/index.html"]
env:
- name: pod_ip
valueFrom:
fieldRef:
fieldPath: status.podIP
- name: node_name
valueFrom:
fieldRef:
fieldPath: spec.nodeName
6.2 部署負載均衡服務
cat service-demoapp.yml
apiVersion: v1
kind: Service
metadata:
name: svc-demoapp
spec:
selector:
app: demoapp
ports:
- port: 80
targetPort: 80
6.3 部署1.1版本應用
cat deploy-demoapp11.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-demoapp11
spec:
replicas: 1#部署一個副本作為灰度應用
selector:
matchLabels:
app: demoapp
version: v11
template:
metadata:
labels:
app: demoapp
version: v11
spec:
containers:
- name: demoapp
image: nginx:latest
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
lifecycle:
postStart:
exec:
command: ["sh", "-c", "echo demoapp v1.1!! NodeName: ${node_name} PodIP: ${pod_ip} > /usr/share/nginx/html/index.html"]
env:
- name: pod_ip
valueFrom:
fieldRef:
fieldPath: status.podIP
- name: node_name
valueFrom:
fieldRef:
fieldPath: spec.nodeName
6.4 測試新老版本共存
6.5 控制新老版本流量
1、逐步增加1.1版本的數量
2、逐步減少1.0版本的數量