一、控制器說明
Pod 的分類:
- 自主式 Pod:該類型的 Pod 無論是異常退出還是正常退出都不會被創建,也就是說沒有對應的管理者。
- 控制器管理的 Pod:該類型 Pod 在控制器的生命周期里,控制器始終要維持 Pod 的副本數,日常中基本都是使用該類型 Pod ,因為自主式 Pod 不能保證穩定性等之類的問題。
Deployment 介紹
Deployment 是為 Pod 和 ReplicaSet 提供了一個 聲明式定義方法,也就是你只要負責描述 Deployment 中的目標狀態,而 Deployment 控制器會去對 ReplicaSet 進行操作使其變成期望的狀態。
Deployment 是用來取代以前的 ReplicationController 達到更方便的管理應用。
典型的應用場景如下:
-
定義 Deployment 來創建 ReplicaSet 和 Pod
-
滾動升級和回滾應用
-
擴容和縮容
-
暫停和繼續 Deployment
Deployment 創建 RS 流程圖如下:
這里針對上面第一點強調一下,Deployment 不是直接管理或者創建 Pod,而是通過創建 ReplicaSet 來創建和管理 Pod。
創建 Deployment 時名稱為 nginx-Deploy,RS 也會被創建出來,名稱為 nginx-Deploy-xxx,xxx為隨機碼。
DaemonSet 介紹
DaemonSet 確保全部(或者一些)節點上運行 一個 Pod 的副本。 當有節點加入集群時, 也會為他們 新增一個 Pod 。 當有節點從集群移除時,這些 Pod 也會被回收。刪除 DaemonSet 將會刪除它創建的 所有 Pod。
上述簡介摘自官方
如果需要多個 Pod 運行在每個 Node 上的話,可以定義多個 DaemonSet 的方案來實現。
DaemonSet 典型應用場景:
-
運行集群存儲,例如在每個 Node 上運行
glusterd
、ceph
等 -
每個 Node 上運行日志收集,例如
fluentd
、logstash
等 -
每個 Node 上運行監控程序,例如
Prometheus Node Exporter
、collectd
等
StatefulSet 介紹
StatefulSet 是用來管理 有狀態服務,為了解決有狀態服務的問題,而 Deployment 和 ReplicaSet 更適用於無狀態服務的部署。
StatefulSet 為每個 Pod 維護了一個有粘性的 ID,無論怎么調度,每個 Pod 都有一個永久不變的 ID。
StatefulSet 應用場景:
- 穩定的、唯一的網絡標識符。
- 穩定的、持久的存儲。
- 有序的、優雅的部署和縮放。
- 有序的、自動的滾動更新。
Job 介紹
Job 負載批處理任務,僅執行一次的任務,它能夠保證批處理任務的一個或者多個 Pod 成功執行結束。
可以設置 Job 執行成功的數值,Job 跟蹤記錄成功完成的 Pod 個數,當數量達到指定的成功個數閾值時,任務結束。
我們不需要擔心程序是否執行成功,如果 Jod 沒有以0代碼
成功退出的話,它會重新執行這個程序。
CronJob 介紹
CronJob 就像 Linux 的 crontab。 它用 Cron 格式進行編寫, 在給定時間點只運行一次、周期性地在給定的調度時間執行 Job。
典型應用場景:
創建周期性運行的 Jod,最常用的是 數據庫備份。
二、控制器創建實例測試
RS 與 Deployment 實例測試
在 K8s 新版本中,官方不再使用 ReplicationControler(RC),而是使用 ReplicaSet(RS)代替 RC,其實 RS 和 RC 本質沒什么不同,只是 RS 多了一個支持集合式的 selector。
支持集合式的 selector 作用:
在創建 Pod 的時候會為它打上標簽(tag),也會為 Pod 里面的容器打上標簽,當需要刪除容器或者進行其他操作的時候,可以通過標簽來進行相關操作。
接下來我們演示一下 RS 標簽的作用
rs_frontend.yaml
資源清單如下:
apiVersion: apps/v1
kind: ReplicaSet
metadata: # RS 元素信息
name: frontend # RS 名稱
labels: # 自定義標簽
app: guestbook # RS 標簽
tier: frontend # RS 標簽
spec:
replicas: 3 # Pod 副本數
selector: # 選擇標簽
matchLabels: # 匹配標簽
tier: frontend # 匹配 frontend 標簽
template: # Pod 模板
metadata: # Pod 元素信息
labels: # 自定義標簽
tier: frontend # 標簽 frontend
spec:
containers:
- name: mynginx # 容器名稱
image: hub.test.com/library/mynginx:v1 # 鏡像地址
RS 創建
[root@k8s-master01 ~]# kubectl create -f rs_frontend.yaml
replicaset.apps/frontend created
查看 Pod 和 RS 狀態
查看 Pod 選擇標簽,這三個 Pod 的標簽都是frontend
接下來修改其中一個 Pod 標簽測試
[root@k8s-master01 ~]# kubectl label pod frontend-8wsl2 tier=frontend1 --overwrite
pod/frontend-8wsl2 labeled
再次查看 Pod 狀態及標簽
此時已經變成四個 Pod ,因為 RS 是通過
frontend
標簽進行 Pod 匹配,RS 檢測到frontend
標簽的 Pod 此時少了一個,所以會新創建一個屬於自己的標簽 Pod 出來,從而滿足期望值。而此時
frontend-8wsl2
這個 Pod 已經不屬於 RS 的控制范圍之內了,因為它的標簽是frontend1
。
把 RS 給刪除后可以更直觀的看出標簽的作用
[root@k8s-master01 ~]# kubectl delete rs frontend
replicaset.apps "frontend" deleted
[root@k8s-master01 ~]# kubectl get pod --show-labels
其他的三個 Pod 都被刪除了,只有標簽為
frontend1
Pod 沒有被刪除,因為該 Pod 標簽不匹配 RS ,所以 RS 就不會對該 Pod 進行任何操作。
Deployment 實例測試
下面是 Deployment 示例。實際是創建了一個 ReplicaSet,負責啟動三個 Nginx Pod。
nginx-deployment.yaml
資源清單如下
apiVersion: apps/v1
kind: Deployment
metadata: # Deployment 元素信息
name: nginx-deployment # Deployment 名稱
labels: # 自定義標簽
app: nginx # Deployment 標簽
spec:
replicas: 3 # Pod 副本數
selector:
matchLabels:
app: nginx # 匹配 frontend 標簽
template:
metadata:
labels:
app: nginx # Pod 標簽 frontend
spec:
containers:
- name: mynginx
image: hub.test.com/library/mynginx:v1 # 鏡像地址
ports:
- containerPort: 80
創建 Deployment
[root@k8s-master01 ~]# kubectl apply -f nginx-deployment.yaml --record
deployment.apps/nginx-deployment created
--record 記錄命令,方便回滾的時候方便查看每次 revision 變化。
查看 Deployment、RS、Pod 狀態,全部都已經Running
查看 Pod 詳細信息,訪問測試
[root@k8s-master01 ~]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-deployment-644f95f9bc-fb6wv 1/1 Running 0 7m2s 10.244.1.63 k8s-node01 <none> <none>
nginx-deployment-644f95f9bc-hbhj7 1/1 Running 0 7m2s 10.244.2.46 k8s-node02 <none> <none>
nginx-deployment-644f95f9bc-j8q2k 1/1 Running 0 7m2s 10.244.1.64 k8s-node01 <none> <none>
Deployment 擴容功能
[root@k8s-master01 ~]# kubectl scale deployment nginx-deployment --replicas=10
可以看到此時已經擴容到 10 個 Pod ,Deployment 擴容非常簡單,一個命令就可以水平擴容,從而緩解應用對外提供的壓力。
上面是手動擴容的,哪能不能根據 Pod 的負載情況來進行自動擴容縮呢?
是可以的,K8s 提供了 HPA 功能,詳細可以看 我這篇筆記 。
Deployment 更新鏡像操作
[root@k8s-master01 ~]# kubectl set image deployment/nginx-deployment nginx=hub.test.com/library/mynginx:v2
nginx 為容器名稱
查看 RS 狀態,此時已經創建新的 RS,但是舊的 RS 還保留着,后續可以進行回滾操作
訪問其中一個 Pod 測試
Deployment 回滾操作
[root@k8s-master01 ~]# kubectl rollout undo deployment/nginx-deployment
deployment.apps/nginx-deployment rolled back
已經回滾到之前的 RS 的版本
[root@k8s-master01 ~]# kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-deployment-5cf56df4d6 0 0 0 8m2s
nginx-deployment-644f95f9bc 10 10 10 37m
默認是回滾到上一個版本,訪問測試
還可以滾動或者回滾到指定版本
查看版本信息
[root@k8s-master01 ~]# kubectl rollout history deployment/nginx-deployment
回滾到指定版本命令如下,這里就不做測試
[root@k8s-master01 ~]# kubectl rollout undo deployment/nginx-deployment --to-revision=3
版本清理策略
可以在 Deployment 中設置 .spec.revisionHistoryLimit
字段以指定保留此 Deployment 的多少個舊有 ReplicaSet。其余的 ReplicaSet 將在后台被垃圾回收。 默認情況下,此值為 10 。
DaemonSet 實例測試
daemonset.yaml
資源清單如下
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: daemonset-example
labels:
app: daemonset
spec:
selector:
matchLabels:
name: daemonset-example
template:
metadata:
labels:
name: daemonset-example
spec:
containers:
- name: mynginx
image: hub.test.com/library/mynginx:v1
創建 DaemonSet
[root@k8s-master01 ~]# kubectl create -f daemonset.yaml
daemonset.apps/daemonset-example created
查看 DaemonSet Pod 狀態
分別在兩個 Node 上一個 Pod ,因為 K8s 里面有個 污點的概念 ,所以 Master 上不會被創建,可以自行去了解一下,后續的文章中也會講到。
把其中一個 Node 上的 Pod 刪除,它會自動創建一個新的 Pod 來滿足 DaemonSet 的期望值,每個 Node 上一個副本,如圖所示。
Job 實例測試
job.yaml
資源清單,它負責計算 π 到小數點后 2000 位,並將結果打印出來。
apiVersion: batch/v1
kind: Job
metadata:
name: pi # Job 名稱
spec:
template:
spec:
containers:
- name: pi # Pod 名稱
image: perl # 鏡像名稱
command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"]
# 計算圓周率,計算小數點后 2000 位
restartPolicy: Never # 重啟策略,永不重啟
backoffLimit: 4 # 設置重試次數,達到后將 Job 標記為失敗
創建 Job 並查看狀態
[root@k8s-master01 ~]# kubectl create -f job.yaml
job.batch/pi created
[root@k8s-master01 ~]# kubectl get pod -w
可以看到 Job 從 Running 到 Completed 的一個過程,該 Job 已經完成了計算。
查看具體結果
其他參數配置
.spec.completions
標志 Job 需要成功完成 Pod 個數,才視為整個 Job 完成。(默認1)
.spec.parallelism
標志 Pod 並行運行個數。(默認1)
.spec.activeDeadlineSeconds
標志 Job 的整個生命期,一旦 Job 運行時間達到設定值,則所有運行中的 Pod 都會被終止。(秒數值)
CronJob 實例測試
cronjob.yaml
資源清單示例如下
apiVersion: batch/v1
kind: CronJob
metadata:
name: hello
spec:
schedule: "*/1 * * * *" # 每分鍾執行一次
jobTemplate: # 指定需要運行的任務
spec:
template:
spec:
containers:
- name: hello
image: hub.test.com/library/busybox:latest
imagePullPolicy: IfNotPresent # 默認值,本地有則使用本地鏡像就不拉取
command:
- /bin/sh
- -c
- date; echo Hello from the Kubernetes cluster
restartPolicy: OnFailure # 重啟策略,不失敗則不重啟
大家如果設置定時計划任務不確定時間的時候,可以通過這個小工具網站進行驗證。
crontab 執行時間計算:https://tool.lu/crontab/
創建 CronJob
[root@k8s-master01 ~]# kubectl apply -f cronjob.yaml
cronjob.batch/hello created
查看 CronJob 狀態
[root@k8s-master01 ~]# kubectl get cronjob
NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE
hello */1 * * * * False 0 21s 21m
查看 Job 運行狀態,默認是保存三個成功的 Pod 記錄
查看其中一個 Pod 日志,可以看到每分鍾執行一個,符合我們預期設置要求。
[root@k8s-master01 ~]# kubectl logs hello-27053804-jc6jd
Wed Jun 9 08:44:00 UTC 2021
Hello from the Kubernetes cluster
[root@k8s-master01 ~]# kubectl logs hello-27053805-hfr5l
Wed Jun 9 08:45:00 UTC 2021
Hello from the Kubernetes cluster
其他參數配置
.spec.successfulJobsHistoryLimit
設置保存執行成功的 Job 數量(默認3)
.spec.failedJobsHistoryLimit
設置保存失敗的 Job 數量(默認1)
.spec.concurrencyPolicy
並發策略(默認Allow)
當讀到這里的時候,你會發現 StatefulSet
還有進行實例測試,原因是 StatefulSet 需要跟 K8s 存儲配合使用,所以后續講到存儲部署的時候再進行演示。