Kubernetes應用管理器OpenKruise之CloneSet

OpenKruise

OpenKruise 是 Kubernetes 的一個標準擴展,它能夠配合原生 Kubernetes 使用,併爲管理應用容器、sidecar、鏡像分發等方面提供更增強大和高效的能力。html

核心功能

  • 原地升級
    原地升級是一種能夠避免刪除、新建 Pod 的升級鏡像能力。它比原生 Deployment/StatefulSet 的重建 Pod 升級更快、更高效,而且避免對 Pod 中其餘不須要更新的容器形成干擾。node

  • Sidecar 管理
    支持在一個單獨的 CR 中定義 sidecar 容器,OpenKruise 可以幫你把這些 Sidecar 容器注入到全部符合條件的 Pod 中。這個過程和 Istio 的注入很類似,可是你能夠管理任意你關心的 Sidecar。nginx

  • 跨多可用區部署
    定義一個跨多個可用區的全局 workload,容器,OpenKruise 會幫你在每一個可用區建立一個對應的下屬 workload。你能夠統一管理他們的副本數、版本、甚至針對不一樣可用區採用不一樣的發佈策略。git

CRD 列表

CloneSet
提供更加高效、肯定可控的應用管理和部署能力,支持優雅原地升級、指定刪除、發佈順序可配置、並行/灰度發佈等豐富的策略,能夠知足更多樣化的應用場景。

Advanced StatefulSet
基於原生 StatefulSet 之上的加強版本,默認行爲與原生徹底一致,在此以外提供了原地升級、並行發佈(最大不可用)、發佈暫停等功能。

SidecarSet
對 sidecar 容器作統一管理,在知足 selector 條件的 Pod 中注入指定的 sidecar 容器。

UnitedDeployment
經過多個 subset workload 將應用部署到多個可用區。

BroadcastJob
配置一個 job,在集羣中全部知足條件的 Node 上都跑一個 Pod 任務。

Advanced DaemonSet
基於原生 DaemonSet 之上的加強版本,默認行爲與原生一致,在此以外提供了灰度分批、按 Node label 選擇、暫停、熱升級等發佈策略。

AdvancedCronJob
一個擴展的 CronJob 控制器,目前 template 模板支持配置使用 Job 或 BroadcastJob。

以上在官方文檔都有介紹,本文主要着重實戰,先講CloneSet,其餘控制器後面會陸續更新。。。github

部署Kruise到Kubernetes集羣

這裏使用helm來安裝Kruise
一、如今kruise Chartshell

wget https://github.com/openkruise/kruise/releases/download/v0.7.0/kruise-chart.tgz
tar -zxf kruise-chart.tgz
cd kruise
[root@ kruise]# ls -l
total 16
-rw-r--r-- 1 root root  311 Dec 20 15:09 Chart.yaml
-rw-r--r-- 1 root root 4052 Dec 20 15:09 README.md
drwxr-xr-x 2 root root 4096 Dec 23 10:18 templates
-rw-r--r-- 1 root root  659 Dec 20 15:09 values.yaml

二、修改values.yaml,默認不用修改也行
三、執行部署json

[root@qd01-stop-k8s-master001 kruise]# kubectl create ns kruise
namespace/kruise created
[root@qd01-stop-k8s-master001 kruise]# helm install kruise -n kruise -f values.yaml  .
W1223 10:22:13.562088 1589994 warnings.go:67] apiextensions.k8s.io/v1beta1 CustomResourceDefinition is deprecated in v1.16+, unavailable in v1.22+; use apiextensions.k8s.io/v1 CustomResourceDefinition
。。。。。。。
NAME: kruise
LAST DEPLOYED: Wed Dec 23 10:22:12 2020
NAMESPACE: kruise
STATUS: deployed
REVISION: 1
TEST SUITE: None
這裏會看到一堆的deprecated信息,由於新版的kubernetes對CRD的版本會淘汰,能夠根據本身的集羣版本修改CRD的API版本便可

四、檢查kruise部署狀態api

[root@qd01-stop-k8s-master001 kruise]# helm ls -n kruise
NAME    NAMESPACE       REVISION        UPDATED                                 STATUS          CHART           APP VERSION
kruise  kruise          1               2020-12-23 10:22:12.963651877 +0800 CST deployed        kruise-0.7.0               

能夠看到,集羣中有的kruise crd類型
[root@qd01-stop-k8s-master001 kruise]# kubectl get crd|grep  kruise
advancedcronjobs.apps.kruise.io                       2020-12-23T02:22:13Z
broadcastjobs.apps.kruise.io                          2020-12-23T02:22:13Z
clonesets.apps.kruise.io                              2020-12-23T02:22:13Z
daemonsets.apps.kruise.io                             2020-12-23T02:22:13Z
sidecarsets.apps.kruise.io                            2020-12-23T02:22:13Z
statefulsets.apps.kruise.io                           2020-12-23T02:22:13Z
uniteddeployments.apps.kruise.io                      2020-12-23T02:22:13Z

下面咱們開始來使用這些管理器app

CloneSet

CloneSet 控制器提供了高效管理無狀態應用的能力,它能夠對標原生的 Deployment,但 CloneSet 提供了不少加強功能。
一、咱們先建立一個簡單的CloneSet,yaml以下ide

apiVersion: apps.kruise.io/v1alpha1
kind: CloneSet
metadata:
  labels:
    app: nginx-alpine
  name: nginx-alpine
spec:
  replicas: 5
  selector:
    matchLabels:
      app: nginx-alpine
  template:
    metadata:
      labels:
        app: nginx-alpine
    spec:
      containers:
      - name: nginx
        image: nginx:alpine

二、部署

[root@qd01-stop-k8s-master001 demo]# kubectl apply -f  CloneSet.yaml
cloneset.apps.kruise.io/nginx-alpine created

[root@qd01-stop-k8s-master001 demo]# kubectl get po |grep nginx
nginx-alpine-29g7n                          1/1     Running   0          45s
nginx-alpine-bvgqm                          1/1     Running   0          45s
nginx-alpine-q9tlw                          1/1     Running   0          45s
nginx-alpine-s2t46                          1/1     Running   0          44s
nginx-alpine-sslvf                          1/1     Running   0          44s
從輸出結果看,和原生的Deployment沒有啥區別
#注意,這裏若是get deployment是看不到nginx-alpine這個應用的,須要get cloneset才能看到
[root@qd01-stop-k8s-master001 demo]# kubectl get deployment
[root@qd01-stop-k8s-master001 demo]# kubectl get cloneset
NAME           DESIRED   UPDATED   UPDATED_READY   READY   TOTAL   AGE
nginx-alpine   5         5         5               5       5       2m16s

CloneSet 容許用戶配置 PVC 模板 volumeClaimTemplates,用來給每一個 Pod 生成獨享的 PVC,這是 Deployment 所不支持的。 若是用戶沒有指定這個模板,CloneSet 會建立不帶 PVC 的 Pod。

三、如今來建立一個帶有 PVC 模板的例子

apiVersion: apps.kruise.io/v1alpha1
kind: CloneSet
metadata:
  labels:
    app: nginx-2
  name: nginx-2
spec:
  replicas: 5
  selector:
    matchLabels:
      app: nginx-2
  template:
    metadata:
      labels:
        app: nginx-2
    spec:
      containers:
      - name: nginx
        image: nginx:alpine
        volumeMounts:
        - name: data-vol
          mountPath: /usr/share/nginx/html
  volumeClaimTemplates:
    - metadata:
        name: rbd
      spec:
        accessModes: [ "ReadWriteOnce" ]
        storageClassName: rbd
        resources:
          requests:
            storage: 2Gi

部署

[root@qd01-stop-k8s-master001 demo]# kubectl apply -f  CloneSet.yaml
cloneset.apps.kruise.io/nginx-2 created
[root@qd01-stop-k8s-master001 demo]# kubectl get pv|grep data-vol
pvc-0fde19f3-ea4b-47e0-81be-a8e43812e47b   2Gi        RWO            Delete           Bound    default/data-vol-nginx-2-t55h8                  rbd                     83s
pvc-72accf10-57a6-4418-a1bc-c64633b84434   2Gi        RWO            Delete           Bound    default/data-vol-nginx-2-t49mk                  rbd                     82s
pvc-8fc8b9a5-afe8-446a-9190-08fcee0ec9f6   2Gi        RWO            Delete           Bound    default/data-vol-nginx-2-jw2zp                  rbd                     84s
pvc-c9fba396-e357-43e8-9510-616f698da765   2Gi        RWO            Delete           Bound    default/data-vol-nginx-2-b5fdd                  rbd                     84s
pvc-e5302eab-a9f2-4a71-a5a3-4cd43205e8a0   2Gi        RWO            Delete           Bound    default/data-vol-nginx-2-l54dz                  rbd                     84s
[root@qd01-stop-k8s-master001 demo]# kubectl get po|grep nginx
nginx-2-b5fdd                               1/1     Running   0          97s
nginx-2-jw2zp                               1/1     Running   0          97s
nginx-2-l54dz                               1/1     Running   0          97s
nginx-2-t49mk                               1/1     Running   0          96s
nginx-2-t55h8                               1/1     Running   0          96s

從部署結果能夠看到,每一個pod都建立了一個PVC,這個是原生的Deployment不能實現的。

注意:

每一個被自動建立的 PVC 會有一個 ownerReference 指向 CloneSet,所以 CloneSet 被刪除時,它建立的全部 Pod 和 PVC 都會被刪除。
每一個被 CloneSet 建立的 Pod 和 PVC,都會帶一個 apps.kruise.io/cloneset-instance-id: xxx 的 label。關聯的 Pod 和 PVC 會有相同的 instance-id,且它們的名字後綴都是這個 instance-id。
若是一個 Pod 被 CloneSet controller 縮容刪除時,這個 Pod 關聯的 PVC 都會被一塊兒刪掉。
若是一個 Pod 被外部直接調用刪除或驅逐時,這個 Pod 關聯的 PVC 還都存在;而且 CloneSet controller 發現數量不足從新擴容時,新擴出來的 Pod 會複用原 Pod 的 instance-id 並關聯原來的 PVC。
當 Pod 被重建升級時,關聯的 PVC 會跟隨 Pod 一塊兒被刪除、新建。
當 Pod 被原地升級時,關聯的 PVC 會持續使用。

四、指定 Pod 縮容
當一個 CloneSet 被縮容時,有時候用戶須要指定一些 Pod 來刪除。這對於 StatefulSet 或者 Deployment 來講是沒法實現的,由於 StatefulSet 要根據序號來刪除 Pod,而 Deployment/ReplicaSet 目前只能根據控制器裏定義的排序來刪除。
CloneSet 容許用戶在縮小 replicas 數量的同時,指定想要刪除的 Pod 名字。

如今咱們來修改上面例子的部署文件,指定刪除nginx-2-t55h8這個Pod

apiVersion: apps.kruise.io/v1alpha1
kind: CloneSet
metadata:
  labels:
    app: nginx-2
  name: nginx-2
spec:
  replicas: 4
  scaleStrategy:
    podsToDelete:
    - nginx-2-t55h8

而後更新yaml文件

[root@qd01-stop-k8s-master001 demo]# kubectl apply -f CloneSet.yaml
cloneset.apps.kruise.io/nginx-2 configured

[root@qd01-stop-k8s-master001 demo]# kubectl get po|grep nginx
nginx-2-b5fdd                               1/1     Running   0          11m
nginx-2-jw2zp                               1/1     Running   0          11m
nginx-2-l54dz                               1/1     Running   0          11m
nginx-2-t49mk                               1/1     Running   0          11m

如今看輸入結果,已經沒有nginx-2-t55h8這個Pod了
這個功能很實用,好比某臺機器故障了,或者負載過高,你想刪除指定的pod。

五、升級功能

CloneSet 提供了和 Advanced StatefulSet 相同的 3 個升級方式,默認爲 ReCreate:

ReCreate: 控制器會刪除舊 Pod 和它的 PVC,而後用新版本從新建立出來。
InPlaceIfPossible: 控制器會優先嚐試原地升級 Pod,若是不行再採用重建升級。目前,只有修改 spec.template.metadata.* 和 spec.template.spec.containers[x].image 這些字段才能夠走原地升級。
InPlaceOnly: 控制器只容許採用原地升級。所以,用戶只能修改上一條中的限制字段,若是嘗試修改其餘字段會被 Kruise 拒絕。

如今咱們來嘗試原地升級Pod功能,把nginx鏡像由nginx:alpine 升級爲 nginx:latest
首先修改yaml文件,這裏只粘貼出文件的修改的部分

apiVersion: apps.kruise.io/v1alpha1
kind: CloneSet
...
spec:
  replicas: 4
  updateStrategy:
    type: InPlaceIfPossible
    inPlaceUpdateStrategy:
      gracePeriodSeconds: 10
......
    spec:
      containers:
      - name: nginx
        image: nginx

執行升級

[root@qd01-stop-k8s-master001 demo]# kubectl apply -f CloneSet.yaml
cloneset.apps.kruise.io/nginx-2 configured
使用 kubectl describe查看升級過程
Events:
  Type     Reason                  Age                From                     Message
  ----     ------                  ----               ----                     -------
  Warning  FailedScheduling        59m                default-scheduler        0/22 nodes are available: 22 pod has unbound immediate PersistentVolumeClaims.
  Warning  FailedScheduling        59m                default-scheduler        0/22 nodes are available: 22 pod has unbound immediate PersistentVolumeClaims.
  Warning  FailedScheduling        59m                default-scheduler        0/22 nodes are available: 22 pod has unbound immediate PersistentVolumeClaims.
  Normal   Scheduled               59m                default-scheduler        Successfully assigned default/nginx-2-l54dz to qd01-stop-k8s-node007.ps.easou.com
  Normal   SuccessfulAttachVolume  59m                attachdetach-controller  AttachVolume.Attach succeeded for volume "pvc-e5302eab-a9f2-4a71-a5a3-4cd43205e8a0"
  Normal   Pulling                 58m                kubelet                  Pulling image "nginx:alpine"
  Normal   Pulled                  58m                kubelet                  Successfully pulled image "nginx:alpine" in 6.230045975s
  Normal   Killing                 55s                kubelet                  Container nginx definition changed, will be restarted
  Normal   Pulling                 55s                kubelet                  Pulling image "nginx"
  Normal   Pulled                  26s                kubelet                  Successfully pulled image "nginx" in 29.136659264s
  Normal   Created                 23s (x2 over 58m)  kubelet                  Created container nginx
  Normal   Started                 23s (x2 over 58m)  kubelet                  Started container nginx

從輸出能夠看到,Container nginx definition changed, will be restarted,Pod並無刪除在重建,而是在原來的基礎上直接更新了鏡像文件,並重啓了服務。
原地升級減小了刪除重建環節,節省了升級時間和資源調度頻率。。。

六、Partition 分批灰度
Partition 的語義是 保留舊版本 Pod 的數量或百分比,默認爲 0。這裏的 partition 不表示任何 order 序號。

在發佈過程當中設置了 partition:
	若是是數字,控制器會將 (replicas - partition) 數量的 Pod 更新到最新版本。
	若是是百分比,控制器會將 (replicas * (100% - partition)) 數量的 Pod 更新到最新版本。

如今我將上面的例子的 image 更新爲 nginx:1.19.6-alpine 而且設置 partition=3

kind: CloneSet
metadata:
  labels:
    app: nginx-2
  name: nginx-2
spec:
  replicas: 5
  updateStrategy:
    type: InPlaceIfPossible
    inPlaceUpdateStrategy:
      gracePeriodSeconds: 10
    partition: 3
  selector:
    matchLabels:
      app: nginx-2
  template:
    metadata:
      labels:
        app: nginx-2
    spec:
      containers:
      - name: nginx
        image: nginx:1.19.6-alpine

查看結果

Status:
  Available Replicas:      5
  Collision Count:         0
  Label Selector:          app=nginx-2
  Observed Generation:     6
  Ready Replicas:          5
  Replicas:                5
  Update Revision:         nginx-2-7b44cb9c8
  Updated Ready Replicas:  2
  Updated Replicas:        2
Events:
  Type    Reason                      Age    From                 Message
  ----    ------                      ----   ----                 -------
  Normal  SuccessfulUpdatePodInPlace  45m    cloneset-controller  successfully update pod nginx-2-l54dz in-place(revision nginx-2-5879fd9f7)
  Normal  SuccessfulUpdatePodInPlace  44m    cloneset-controller  successfully update pod nginx-2-t49mk in-place(revision nginx-2-5879fd9f7)
  Normal  SuccessfulUpdatePodInPlace  43m    cloneset-controller  successfully update pod nginx-2-b5fdd in-place(revision nginx-2-5879fd9f7)
  Normal  SuccessfulUpdatePodInPlace  43m    cloneset-controller  successfully update pod nginx-2-jw2zp in-place(revision nginx-2-5879fd9f7)
  Normal  SuccessfulCreate            22m    cloneset-controller  succeed to create pod nginx-2-zpp8z
  Normal  SuccessfulUpdatePodInPlace  5m22s  cloneset-controller  successfully update pod nginx-2-zpp8z in-place(revision nginx-2-7b44cb9c8)
  Normal  SuccessfulUpdatePodInPlace  4m55s  cloneset-controller  successfully update pod nginx-2-jw2zp in-place(revision nginx-2-7b44cb9c8)
  
[root@qd01-stop-k8s-master001 demo]# kubectl get pod -L controller-revision-hash
NAME                                        READY   STATUS    RESTARTS   AGE   CONTROLLER-REVISION-HASH
nginx-2-b5fdd                               1/1     Running   1          99m   nginx-2-5879fd9f7
nginx-2-jw2zp                               1/1     Running   2          99m   nginx-2-7b44cb9c8
nginx-2-l54dz                               1/1     Running   1          99m   nginx-2-5879fd9f7
nginx-2-t49mk                               1/1     Running   1          99m   nginx-2-5879fd9f7
nginx-2-zpp8z                               1/1     Running   1          19m   nginx-2-7b44cb9c8

從輸出信息咱們能夠看到,Update Revision已經更新爲nginx-2-7b44cb9c8,而Pod中只有兩個Pod升級了。
因爲咱們設置了 partition=3,控制器只升級了 2 個 Pod。
Partition 分批灰度功能完善了原生的Pod升級方式,使得升級可以進行更靈活,可以進行灰度上線。超讚。。。

七、最後再演示下發布暫停
用戶能夠經過設置 paused 爲 true 暫停發佈,不過控制器仍是會作 replicas 數量管理:

  • 首先,咱們將示例中image改成nginx:1.18.0 並設置副本數爲10,修改後更新yaml,運行結果以下:
[root@qd01-stop-k8s-master001 demo]#  kubectl get po -o=jsonpath='{range .items[*]}{"\n"}{.metadata.name}{":\t"}{range .spec.containers[*]}{.image}{", "}{end}{end}' |sort
nginx-2-7lzx9:  nginx:1.18.0, 
nginx-2-b5fdd:  nginx:1.18.0, 
nginx-2-jw2zp:  nginx:1.18.0, 
nginx-2-l54dz:  nginx:1.18.0, 
nginx-2-nknrt:  nginx:1.18.0,
nginx-2-rgmsc:  nginx:1.18.0,
nginx-2-rpr5z:  nginx:1.18.0,
nginx-2-t49mk:  nginx:1.18.0, 
nginx-2-v2bpx:  nginx:1.18.0,
nginx-2-zpp8z:  nginx:1.18.0,
  • 如今咱們修改yaml文件,將image修改成nginx:alpine 執行更新,運行以下
[root@qd01-stop-k8s-master001 demo]#  kubectl get po -o=jsonpath='{range .items[*]}{"\n"}{.metadata.name}{":\t"}{range .spec.containers[*]}{.image}{", "}{end}{end}' |sort
nginx-2-7lzx9:  nginx:1.18.0, 
nginx-2-b5fdd:  nginx:1.18.0, 
nginx-2-jw2zp:  nginx:1.18.0, 
nginx-2-l54dz:  nginx:1.18.0, 
nginx-2-nknrt:  nginx:alpine, 
nginx-2-rgmsc:  nginx:alpine, 
nginx-2-rpr5z:  nginx:alpine, 
nginx-2-t49mk:  nginx:1.18.0, 
nginx-2-v2bpx:  nginx:alpine, 
nginx-2-zpp8z:  nginx:1.18.0,
  • 如今看到,有4個pod的image已經更新爲nginx:alpine 而後咱們再次修改yaml文件,添加paused: true
spec:
  replicas: 10
  updateStrategy:
    paused: true
    type: InPlaceIfPossible
    inPlaceUpdateStrategy:
      gracePeriodSeconds: 10
  • 再次執行apply,更新yaml,再次查看更新進度,發現pod並無繼續更新了,已經暫停升級image了
[root@qd01-stop-k8s-master001 demo]#  kubectl get po -o=jsonpath='{range .items[*]}{"\n"}{.metadata.name}{":\t"}{range .spec.containers[*]}{.image}{", "}{end}{end}' |sort
nginx-2-7lzx9:  nginx:1.18.0, 
nginx-2-b5fdd:  nginx:1.18.0, 
nginx-2-jw2zp:  nginx:1.18.0, 
nginx-2-l54dz:  nginx:1.18.0, 
nginx-2-nknrt:  nginx:alpine, 
nginx-2-rgmsc:  nginx:alpine, 
nginx-2-rpr5z:  nginx:alpine, 
nginx-2-t49mk:  nginx:1.18.0, 
nginx-2-v2bpx:  nginx:alpine, 
nginx-2-zpp8z:  nginx:1.18.0,
  • 最後把paused: true取消,再次apply yaml文件,升級會繼續。。。
[root@qd01-stop-k8s-master001 demo]#  kubectl get po -o=jsonpath='{range .items[*]}{"\n"}{.metadata.name}{":\t"}{range .spec.containers[*]}{.image}{", "}{end}{end}' |sort
nginx-2-7lzx9:  nginx:alpine, 
nginx-2-b5fdd:  nginx:alpine, 
nginx-2-jw2zp:  nginx:alpine, 
nginx-2-l54dz:  nginx:alpine, 
nginx-2-nknrt:  nginx:alpine, 
nginx-2-rgmsc:  nginx:alpine, 
nginx-2-rpr5z:  nginx:alpine, 
nginx-2-t49mk:  nginx:alpine, 
nginx-2-v2bpx:  nginx:alpine, 
nginx-2-zpp8z:  nginx:alpine,

以上就是整個發佈暫停的演示,這個功能好處就是;咱們在升級的過程當中能夠隨時中斷升級。

除此以外,CloneSet還有不少特性,例如:MaxUnavailable 最大不可用數量、MaxSurge 最大彈性數量、升級順序、打散策略、生命週期鉤子等,鑑於文章篇幅,這些特性再也不演示了,有須要的能夠查看官方文檔。

相關文章
相關標籤/搜索