ReplicaSet 与 Deployment 控制器

在上一篇笔记中整理了 Pod 相关知识点,在实际工作中我们不会直接使用 Pod 而是通过更高级的控制器来创建并管理 Pod 资源。

这一篇主要整理 K8S 中的 ReplicaSet 和 Deployment 两个控制器相关知识点,以及如何通过 YAML 去定义资源清单。

ReplicaSet 控制器

ReplicaSet (简称 RS)的作用就是控制 Pod 的副本数量一直处于期望状态,多了就删除,少了就创建。ReplicaSet 会一直监听 Pod 的状态,当 Pod 因为某些原因故障减少或者增加的时候,ReplicaSet 会自动帮我们来管理 Pod 。

和 Pod 一样我们仍然还是通过 YAML 文件来描述我们的 ReplicaSet 资源对象,如下 YAML 文件是一个常见的 ReplicaSet 定义:(rs-demo.yaml)

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: rs-demo
spec:
  replicas: 3 # rs 控制 Pod 副本的数量
  selector: # rs 管理的是具有 app=nginx 标签的 Pod
    matchLabels:
      app: nginx
  template: # 定义 Pod 模板,与直接编写 Pod yaml 一样的语法
    metadata:
      labels: # 定义 Pod 的标签,必须带有上面 selector 中定义的 app:nginx否则 rs 没有办法管理
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.18
        imagePullPolicy: IfNotPresent
        ports:
        - name: http
          containerPort: 80

上面的 YAML 文件结构和我们定义 Pod 看上去基本没什么变化,只不过是将定义 Pod 的内容写到的 template 里面,主要有三块内容需要注意:

  • replicas:期望的 Pod 副本数量
  • selector:标签选择器,就是说我们定义的这个 ReplicaSet 用于控制带有什么标签的 Pod,在我们定义 Pod 模板的时候该 Pod 需要定义这个标签。
  • template:Pod 模板,实际上就是我们定义 Pod 的内容,因为现在不是直接创建 Pod 而是由 RS 来帮我们创建。

上面就是我们定义的一个普通的 ReplicaSet 资源清单文件,ReplicaSet 控制器会通过定义的 Label Selector 标签去查找集群中的 Pod 对象如下图:

然后创建 RS 资源

[root@k8s-master k8s-yaml]# kubectl apply -f rs-demo.yaml 
replicaset.apps/rs-demo created
[root@k8s-master k8s-yaml]# kubectl get rs rs-demo
NAME      DESIRED   CURRENT   READY   AGE
rs-demo   3         3         3       25s

然后可以通过查看 Pod 是否被创建出来

[root@k8s-master k8s-yaml]# kubectl get pod -l app=nginx
NAME            READY   STATUS    RESTARTS   AGE
rs-demo-85gpk   1/1     Running   0          7m36s
rs-demo-mtd9k   1/1     Running   0          7m36s
rs-demo-t98df   1/1     Running   0          7m36s

通过 Pod 名字可以看出来,第一部分 rs-demo 就是我们定义的 RS 的名字。通过查看 Pod 的描述信息也可以看到它归属的控制器信息

[root@k8s-master k8s-yaml]# kubectl describe pod rs-demo-85gpk
Name:         rs-demo-85gpk
Namespace:    default
Priority:     0
Node:         k8s-node01/192.168.101.101
Start Time:   Mon, 12 Jul 2021 13:16:34 +0800
Labels:       app=nginx
Annotations:  <none>
Status:       Running
IP:           10.244.1.10
IPs:
  IP:           10.244.1.10
Controlled By:  ReplicaSet/rs-demo # 在这里你可以看到由 rs-demo 这个 ReplicaSet 控制

如果你手动删除其中一个 Pod,RS 也会自动创建出来

[root@k8s-master k8s-yaml]# kubectl delete pod rs-demo-85gpk
pod "rs-demo-85gpk" deleted
[root@k8s-master k8s-yaml]# kubectl get pod -l app=nginx
NAME            READY   STATUS    RESTARTS   AGE
rs-demo-khqbs   1/1     Running   0          5s
rs-demo-mtd9k   1/1     Running   0          9m52s
rs-demo-t98df   1/1     Running   0          9m52s

通过查看 RS 的详细信息也可以看到它创建 Pod 的信息

[root@k8s-master k8s-yaml]# kubectl describe rs rs-demo
Name:         rs-demo
Namespace:    default
Selector:     app=nginx
Labels:       <none>
Annotations:  <none>
Replicas:     3 current / 3 desired
Pods Status:  3 Running / 0 Waiting / 0 Succeeded / 0 Failed
Pod Template:
  Labels:  app=nginx
  Containers:
   nginx:
    Image:        nginx:1.18
    Port:         80/TCP
    Host Port:    0/TCP
    Environment:  <none>
    Mounts:       <none>
  Volumes:        <none>
Events:
  Type    Reason            Age   From                   Message
  ----    ------            ----  ----                   -------
  Normal  SuccessfulCreate  11m   replicaset-controller  Created pod: rs-demo-85gpk
  Normal  SuccessfulCreate  11m   replicaset-controller  Created pod: rs-demo-mtd9k
  Normal  SuccessfulCreate  11m   replicaset-controller  Created pod: rs-demo-t98df
  Normal  SuccessfulCreate  73s   replicaset-controller  Created pod: rs-demo-khqbs

另外可以通过查看 Pod 的描述信息,这里面也会有它所属的 RS 信息在 ownerReferences 这一段信息中

$ kubectl get pod rs-demo-khqbs -o yaml
  ownerReferences:
  - apiVersion: apps/v1
    blockOwnerDeletion: true
    controller: true
    kind: ReplicaSet
    name: rs-demo
    uid: a4cbb228-8490-47f3-9d45-d45dfedf789c

如果你需要减少或者增加 Pod 的副本数量,可以通过修改 YAML 文件中的 replicas 的数量,比如我这里增加到 5

[root@k8s-master k8s-yaml]# kubectl apply -f rs-demo.yaml 
replicaset.apps/rs-demo configured
[root@k8s-master k8s-yaml]# kubectl get pods -l app=nginx
NAME            READY   STATUS    RESTARTS   AGE
rs-demo-khqbs   1/1     Running   0          13m
rs-demo-mtd9k   1/1     Running   0          23m
rs-demo-p94j9   1/1     Running   0          7s
rs-demo-q795z   1/1     Running   0          7s
rs-demo-t98df   1/1     Running   0          23m

当你要彻底删除 Pod 时候,你只能通过删除 RS 对象

kubectl delete rs rs-demo -n default
# 或者
kubectl delete -f rs-demo.yaml

Deployment 控制器

Deployment 控制器是我在工作中使用最多的一个控制器,它会自动管理 ReplicaSet 然后由 ReplicaSet 去管理 Pod ,并且 Deployment 支持滚动更新。

定义一个 Deployment 和定义一个 ReplicaSet 方法完全一致,只不过就是把 kind 换成 Deployment,下面定义几个最简单的 Deployment 资源(deploy-demo.yaml)

apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-demo
  namespace: default
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.18
        imagePullPolicy: IfNotPresent
        ports:
        - name: nginx
          containerPort: 80

然后创建资源

[root@k8s-master k8s-yaml]# kubectl apply -f deploy-demo.yaml 
deployment.apps/deploy-demo created

创建完成后查看 Pod

[root@k8s-master k8s-yaml]# kubectl get pods -l app=nginx
NAME                           READY   STATUS    RESTARTS   AGE
deploy-demo-865958cf45-58jj6   1/1     Running   0          22s
deploy-demo-865958cf45-6pvj9   1/1     Running   0          22s
deploy-demo-865958cf45-87kjk   1/1     Running   0          22s

然后我们查看一个 Pod 的详细信息

[root@k8s-master k8s-yaml]# kubectl describe pod deploy-demo-865958cf45-58jj6
Name:         deploy-demo-865958cf45-58jj6
Namespace:    default
Priority:     0
Node:         k8s-node02/192.168.101.102
Start Time:   Mon, 12 Jul 2021 13:44:17 +0800
Labels:       app=nginx
              pod-template-hash=865958cf45
Annotations:  <none>
Status:       Running
IP:           10.244.2.18
IPs:
  IP:           10.244.2.18
Controlled By:  ReplicaSet/deploy-demo-865958cf45

可以看到 Controlled By: ReplicaSet/deploy-demo-865958cf45 这说明还是由 RS 来控制着 Pod 资源。然后我们再来查看这个 RS 的信息

[root@k8s-master k8s-yaml]# kubectl describe rs deploy-demo-865958cf45
Name:           deploy-demo-865958cf45
Namespace:      default
Selector:       app=nginx,pod-template-hash=865958cf45
Labels:         app=nginx
                pod-template-hash=865958cf45
Annotations:    deployment.kubernetes.io/desired-replicas: 3
                deployment.kubernetes.io/max-replicas: 4
                deployment.kubernetes.io/revision: 1
Controlled By:  Deployment/deploy-demo
Replicas:       3 current / 3 desired
Pods Status:    3 Running / 0 Waiting / 0 Succeeded / 0 Failed
Pod Template:
  Labels:  app=nginx
           pod-template-hash=865958cf45
  Containers:
   nginx:
    Image:        nginx:1.18
    Port:         80/TCP
    Host Port:    0/TCP
    Environment:  <none>
    Mounts:       <none>
  Volumes:        <none>
Events:
  Type    Reason            Age    From                   Message
  ----    ------            ----   ----                   -------
  Normal  SuccessfulCreate  8m40s  replicaset-controller  Created pod: deploy-demo-865958cf45-58jj6
  Normal  SuccessfulCreate  8m40s  replicaset-controller  Created pod: deploy-demo-865958cf45-87kjk
  Normal  SuccessfulCreate  8m40s  replicaset-controller  Created pod: deploy-demo-865958cf45-6pvj9

其中有这样一个信息 Controlled By: Deployment/deploy-demo 其实就是 Pod 依赖的 RS 控制器,实际是被 Deployment 控制着呢,下图说明了 Pod、ReplicaSet、Deployment 三者之间的关系

扩展和收缩

Deployment 实现扩展和收缩功能比较简单,直接利用 ReplicaSet 就可以实现,可以使用 kubectl scale 命令来进行操作

[root@k8s-master k8s-yaml]# kubectl scale deployment deploy-demo --replicas=4
deployment.apps/deploy-demo scaled

扩展完成后查看 RS 状态

[root@k8s-master k8s-yaml]# kubectl get rs
NAME                     DESIRED   CURRENT   READY   AGE
deploy-demo-865958cf45   4         4         4       77m

滚动更新

Deployment 支持两种类型的更新方式:

  • Recreate:所有现有的 Pod 都会被删除,然后在创建新的 Pod
  • Rolling Update:滚动更新,先创建新的,在删除旧的,在更新时允许超过现有 Pod 数量。默认就是滚动更新

下面这个示例(deploy-demo.yaml)中设置了 Recreate 更新方式

apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-demo
  namespace: default
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.18
        imagePullPolicy: IfNotPresent
        ports:
        - name: nginx
          containerPort: 80

然后直接创建资源

[root@k8s-master k8s-yaml]# kubectl apply -f deploy-demo.yaml 
deployment.apps/deploy-demo created
[root@k8s-master k8s-yaml]# kubectl get deploy
NAME          READY   UP-TO-DATE   AVAILABLE   AGE
deploy-demo   3/3     3            3           14s
[root@k8s-master k8s-yaml]# kubectl get rs
NAME                     DESIRED   CURRENT   READY   AGE
deploy-demo-6dd84556d4   3         3         3       18s
[root@k8s-master k8s-yaml]# kubectl get pods 
NAME                           READY   STATUS    RESTARTS   AGE
deploy-demo-6dd84556d4-m6htf   1/1     Running   0          22s
deploy-demo-6dd84556d4-qwn46   1/1     Running   0          22s
deploy-demo-6dd84556d4-znhfz   1/1     Running   0          22s

现在更新 deploy-demo 的镜像版本,使用 kubectl set image进行操作

[root@k8s-master k8s-yaml]# kubectl set image deployment deploy-demo nginx=nginx:1.20 --record
deployment.apps/deploy-demo image updated

然后查看 Deployment 详细信息

[root@k8s-master k8s-yaml]# kubectl describe deploy deploy-demo
Name:               deploy-demo
Namespace:          default
CreationTimestamp:  Mon, 12 Jul 2021 15:37:04 +0800
Labels:             <none>
Annotations:        deployment.kubernetes.io/revision: 2
                    kubernetes.io/change-cause: kubectl set image deployment deploy-demo nginx=nginx:1.20 --record=true
Selector:           app=nginx
Replicas:           3 desired | 3 updated | 3 total | 3 available | 0 unavailable
StrategyType:       Recreate
MinReadySeconds:    0
Pod Template:
  Labels:  app=nginx
  Containers:
   nginx:
    Image:        nginx:1.20
    Port:         80/TCP
    Host Port:    0/TCP
    Environment:  <none>
    Mounts:       <none>
  Volumes:        <none>
Conditions:
  Type           Status  Reason
  ----           ------  ------
  Available      True    MinimumReplicasAvailable
  Progressing    True    NewReplicaSetAvailable
OldReplicaSets:  <none>
NewReplicaSet:   deploy-demo-6dd84556d4 (3/3 replicas created)
Events:
  Type    Reason             Age   From                   Message
  ----    ------             ----  ----                   -------
  Normal  ScalingReplicaSet  111s  deployment-controller  Scaled up replica set deploy-demo-865958cf45 to 3
  Normal  ScalingReplicaSet  49s   deployment-controller  Scaled down replica set deploy-demo-865958cf45 to 0
  Normal  ScalingReplicaSet  36s   deployment-controller  Scaled up replica set deploy-demo-6dd84556d4 to 3

通过 Deployment 时间可以看到,首先将老的 RS 副本设置为了 0,这时就会删除已经存在的 Pod,然后又新创建了一个 RS 并将副本数设置为 3。

上面演示了使用 Recreate 方式去更新 Pod ,但是这种方法并不适合生产上的业务。下面通过示例演示如何使用 RollingUpdate 方式进行滚动更新:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-demo
  namespace: default
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  minReadySeconds: 5
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 1
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.18
        imagePullPolicy: IfNotPresent
        ports:
        - name: nginx
          containerPort: 80
  • minReadySeconds:表示 Kubernetes 在等待设置的时间后才进行升级,如果没有设置该值,Kubernetes 会假设该容器启动起来后就提供服务了,如果没有设置该值,在某些极端情况下可能会造成服务不正常运行,默认值就是0

  • type: RollingUpdate:表示设置更新策略为滚动更新,可以设置为RecreateRollingUpdate两个值,Recreate表示全部重新创建,默认值就是RollingUpdate

  • maxSurge:表示升级过程中最多可以比原先设置多出的 Pod 数量,例如:maxSurage=1,replicas=5,就表示Kubernetes 会先启动一个新的 Pod,然后才删掉一个旧的 Pod,整个升级过程中最多会有5+1个 Pod。

  • maxUnavailable:表示升级过程中最多有多少个 Pod 处于无法提供服务的状态,当maxSurge不为0时,该值也不能为0,例如:maxUnavaible=1,则表示 Kubernetes 整个升级过程中最多会有1个 Pod 处于无法服务的状态。

然后创建 Deployment 对象

[root@k8s-master k8s-yaml]# kubectl apply -f deploy-demo.yaml 
deployment.apps/deploy-demo created
[root@k8s-master k8s-yaml]# kubectl get pods
NAME                           READY   STATUS    RESTARTS   AGE
deploy-demo-865958cf45-9wq2b   1/1     Running   0          3m32s
deploy-demo-865958cf45-bdnng   1/1     Running   0          3m32s
deploy-demo-865958cf45-wpnsf   1/1     Running   0          3m32s

现在来更新这个 Deployment 对象的镜像版本

[root@k8s-master k8s-yaml]# kubectl set image deployment deploy-demo nginx=nginx:1.20
deployment.apps/deploy-demo image updated

更新的过程可以使用 kubectl rollout status来查看更新的状态

[root@k8s-master k8s-yaml]# kubectl rollout status deployment deploy-demo
Waiting for deployment "deploy-demo" rollout to finish: 2 out of 3 new replicas have been updated...

从上面的信息可以看出我们的滚动更新已经有两个 Pod 已经更新完成了,在滚动更新过程中,我们还可以执行如下的命令来暂停更新:

[root@k8s-master k8s-yaml]# kubectl rollout pause deployment deploy-demo
deployment.apps/deploy-demo paused

这个时候我们的滚动更新就暂停了,此时我们可以查看下 Deployment 的详细信息:

[root@k8s-master k8s-yaml]# kubectl describe deployment deploy-demo
Name:                   deploy-demo
Namespace:              default
CreationTimestamp:      Mon, 12 Jul 2021 15:51:58 +0800
Labels:                 <none>
Annotations:            deployment.kubernetes.io/revision: 2
Selector:               app=nginx
Replicas:               3 desired | 2 updated | 4 total | 4 available | 0 unavailable
StrategyType:           RollingUpdate
MinReadySeconds:        5
RollingUpdateStrategy:  1 max unavailable, 1 max surge
Pod Template:
  Labels:  app=nginx
  Containers:
   nginx:
    Image:        nginx:1.20
    Port:         80/TCP
    Host Port:    0/TCP
    Environment:  <none>
    Mounts:       <none>
  Volumes:        <none>
Conditions:
  Type           Status   Reason
  ----           ------   ------
  Available      True     MinimumReplicasAvailable
  Progressing    Unknown  DeploymentPaused
OldReplicaSets:  deploy-demo-865958cf45 (2/2 replicas created)
NewReplicaSet:   deploy-demo-6dd84556d4 (2/2 replicas created)
Events:
  Type    Reason             Age    From                   Message
  ----    ------             ----   ----                   -------
  Normal  ScalingReplicaSet  10m    deployment-controller  Scaled up replica set deploy-demo-865958cf45 to 3
  Normal  ScalingReplicaSet  3m14s  deployment-controller  Scaled up replica set deploy-demo-6dd84556d4 to 1
  Normal  ScalingReplicaSet  3m14s  deployment-controller  Scaled down replica set deploy-demo-865958cf45 to 2
  Normal  ScalingReplicaSet  3m14s  deployment-controller  Scaled up replica set deploy-demo-6dd84556d4 to 2

通过 Deployment 的 Events 事件信息可以看到滚动更新的大致流程:

  1. 首先创建了一个新的 RS 资源 deploy-demo-6dd84556d4 并且副本数是 1
  2. 设置老的 RS 资源 deploy-demo-865958cf45 将副本数从 3 改为 2,也就关闭了一个 Pod
  3. 然后新的 RS 又启动了第二个 Pod,后面因为我执行了暂停滚动更新,所有系统上当前应该存在 4 个 Pod
[root@k8s-master k8s-yaml]# kubectl get pods
NAME                           READY   STATUS    RESTARTS   AGE
deploy-demo-6dd84556d4-n4gf8   1/1     Running   0          7m44s
deploy-demo-6dd84556d4-nz8tr   1/1     Running   0          7m44s
deploy-demo-865958cf45-9wq2b   1/1     Running   0          14m
deploy-demo-865958cf45-bdnng   1/1     Running   0          14m

这 4 个 Pod 副本应该是有 2 个使用的更新以后镜像,2 个是旧版本的。通过查看 Deployment 也可以看到

[root@k8s-master k8s-yaml]# kubectl get deployment
NAME          READY   UP-TO-DATE   AVAILABLE   AGE
deploy-demo   4/3     2            4           20m

这个时候我们可以使用kubectl rollout resume来恢复我们的滚动更新:

[root@k8s-master k8s-yaml]# kubectl rollout resume deployment deploy-demo
deployment.apps/deploy-demo resumed

[root@k8s-master k8s-yaml]# kubectl rollout status deployment deploy-demo
Waiting for deployment "deploy-demo" rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for deployment spec update to be observed...
Waiting for deployment spec update to be observed...
Waiting for deployment "deploy-demo" rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for deployment "deploy-demo" rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for deployment "deploy-demo" rollout to finish: 2 of 3 updated replicas are available...
Waiting for deployment "deploy-demo" rollout to finish: 2 of 3 updated replicas are available...
deployment "deploy-demo" successfully rolled out

如果更新以后发现有问题还可以进行回滚,使用 kubectl rollout undo 默认回退到上一个版本

[root@k8s-master k8s-yaml]# kubectl rollout undo deployment deploy-demo
deployment.apps/deploy-demo rolled back

当然也可以回退到指定的版本

[root@k8s-master k8s-yaml]# kubectl rollout history  deployment deploy-demo
deployment.apps/deploy-demo 
REVISION  CHANGE-CAUSE
2         <none>
3         <none>

[root@k8s-master k8s-yaml]# kubectl rollout undo deployment deploy-demo --to-revision=2
本作品采用《CC 协议》,转载必须注明作者和本文链接
(= ̄ω ̄=)··· 暂无内容!

请勿发布不友善或者负能量的内容。与人为善,比聪明更重要!