kubernete编排技术二:deployment

gq_design
发布于 2022-5-1 09:33
浏览
0收藏

作者 |  朱晋君
来源 | 君哥聊技术(ID:gh_1f109b82d301)

kubernete中的控制器模式,是指用一种对象来控制另一种对象,这个控制器是由组件kube-controller-manager来实现的。deployment就是一种控制器,用来控制pod的创建、水平扩展收缩、滚动更新。deployment是kubernete中一个对无状态pod的控制器,本文来介绍一下。

deployment简介

先回顾一下我们之前定义的yaml文件,这个文件定义了2个pod副本(replicas: 2),这个deployment的编排逻辑就是带app: springboot-mybatis这个label的数量只能有2个,超过就需要删除,少了就需要创建。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: springboot-mybatis-deployment
spec:
  selector:
    matchLabels:
      app: springboot-mybatis
  replicas: 2
  template:
    metadata:
      labels:
        app: springboot-mybatis
    spec:
      containers:
      - name: spingboot-mybatis
        imagePullPolicy: IfNotPresent
        image: zjj2006forever/springboot-mybatis:1.2
        ports:
        - containerPort: 8300

上面yaml文件中的template,被称作pod模板,而template上面的代码部分,就是控制器的定义。这儿的控制器其实就是上面的控制器部分对下面pod模板的控制。创建时,控制器会从etcd查找label是springboot-mybatis的pod个数,因为是0,所以会创建2个;如果运行过程中,有一个pod挂了,会再创建一个。

pod水平扩展和收缩

上一节的yaml文件定义了一个2个pod的deployment控制器,这样会生成2个pod。在我们实际工作中,有时会遇到突增流量,比如促销活动之类的,这时候我们可以用增加pod来应对。最直接的方式就是修改replicas,比如改为replicas: 4。但是生成环境中,这样效率太低了,我们可以执行如下命令:

kubectl scale deployment springboot-mybatis-deployment --replicas=4

之后我们查看集群上的pod,这2个AGE=10s的pod就是后来扩展出来的。

[root@master k8s]# kubectl get pods
NAME                                             READY   STATUS    RESTARTS   AGE
springboot-mybatis-deployment-5b78f66997-d5fk9   1/1     Running   0          61s
springboot-mybatis-deployment-5b78f66997-hcmm4   1/1     Running   0          10s
springboot-mybatis-deployment-5b78f66997-k5xw8   1/1     Running   0          61s
springboot-mybatis-deployment-5b78f66997-pvfdv   1/1     Running   0          11s

我们查看其中一个新pod的状态,跟之前的pod创建过程完全一样。

[root@master k8s]# kubectl describe pod springboot-mybatis-deployment-5b78f66997-hcmm4
Name:         springboot-mybatis-deployment-5b78f66997-hcmm4
Namespace:    default
Priority:     0
Node:         worker1/192.168.59.141
Start Time:   Wed, 08 Jul 2020 06:01:08 -0400
Labels:       app=springboot-mybatis
              pod-template-hash=5b78f66997
Annotations:  <none>
Status:       Running
IP:           10.244.1.25
IPs:
  IP:           10.244.1.25
Controlled By:  ReplicaSet/springboot-mybatis-deployment-5b78f66997
Containers:
  spingboot-mybatis:
    Container ID:   docker://ef433a219549b32e1d01899ea6ac581c1bfffa7d01e1c165647be52f9f79ff5b
    Image:          zjj2006forever/springboot-mybatis:1.2
    Image ID:       docker-pullable://zjj2006forever/springboot-mybatis@sha256:bf43bc9d1d4bdb33d82a206282c8f82be3679847d1011806b72e3634ebe67564
    Port:           8300/TCP
    Host Port:      0/TCP
    State:          Running
      Started:      Wed, 08 Jul 2020 06:01:11 -0400
    Ready:          True
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-qk5nc (ro)
Conditions:
  Type              Status
  Initialized       True 
  Ready             True 
  ContainersReady   True 
  PodScheduled      True 
Volumes:
  default-token-qk5nc:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-qk5nc
    Optional:    false
QoS Class:       BestEffort
Node-Selectors:  <none>
Tolerations:     node.kubernetes.io/not-ready:NoExecute for 300s
                 node.kubernetes.io/unreachable:NoExecute for 300s
Events:
  Type    Reason     Age        From               Message
  ----    ------     ----       ----               -------
  Normal  Scheduled  <unknown>  default-scheduler  Successfully assigned default/springboot-mybatis-deployment-5b78f66997-hcmm4 to worker1
  Normal  Pulled     107s       kubelet, worker1   Container image "zjj2006forever/springboot-mybatis:1.2" already present on machine
  Normal  Created    106s       kubelet, worker1   Created container spingboot-mybatis
  Normal  Started    106s       kubelet, worker1   Started container spingboot-mybatis

查看replicas

[root@master k8s]# kubectl get rs
NAME                                       DESIRED   CURRENT   READY   AGE
springboot-mybatis-deployment-5b78f66997   4         4         4       3m59s

检测一下应用运行正常

[root@worker1 ~]# curl http://10.244.1.24:18082/actuator/info
{"app":{"name":"springboot-mybatis","description":"two-datasource-test","version":"1.0","spring-boot-version":"2.1.6"}}

如果流量降下来了,我们可以收缩pod数量,执行命令

kubectl scale deployment nginx-deployment --replicas=2

查看pod数量,后来扩展的2个pod被删除了

[root@master k8s]# kubectl get pods
NAME                                             READY   STATUS    RESTARTS   AGE
springboot-mybatis-deployment-5b78f66997-d5fk9   1/1     Running   0          11m
springboot-mybatis-deployment-5b78f66997-k5xw8   1/1     Running   0          11m

可以看出,这种控制器模式,是由deployment控制ReplicaSet,ReplicaSet控制pod。

滚动更新

在实际开发工作中,升级服务上线是经常的事情。以本文中的应用为例,之前的deployment使用的镜像是zjj2006forever/springboot-mybatis:1.2,如果我们升级镜像版本到1.3,需要怎么操作呢?

注:镜像的升级版本我已经打好并且发布到dockerhub,感兴趣的同学自行拉取测试。

这个升级操作我们可以直接修改yaml文件,也可以执行如下命令进行修改,这个命令的原理是直接编辑etcd里面的springboot-mybatis-deployment控制器对象,可以跟编辑文件一样进行编辑

kubectl edit deployment/springboot-mybatis-deployment

编辑完成保存后,就会触发滚动更新。执行下面命令查看滚动更新的日志。

[root@master ~]# kubectl rollout status deployment/springboot-mybatis-deployment
Waiting for deployment "springboot-mybatis-deployment" rollout to finish: 1 out of 2 new replicas have been updated...
Waiting for deployment "springboot-mybatis-deployment" rollout to finish: 1 out of 2 new replicas have been updated...
Waiting for deployment "springboot-mybatis-deployment" rollout to finish: 1 out of 2 new replicas have been updated...
Waiting for deployment "springboot-mybatis-deployment" rollout to finish: 1 old replicas are pending termination...
Waiting for deployment "springboot-mybatis-deployment" rollout to finish: 1 old replicas are pending termination...
deployment "springboot-mybatis-deployment" successfully rolled out

这时我们再次查看pod,发现新的pod已经创建出来了

[root@master k8s]# kubectl get pods
NAME                                             READY   STATUS    RESTARTS   AGE
springboot-mybatis-deployment-69787d89c4-8kplf   1/1     Running   0          30s
springboot-mybatis-deployment-69787d89c4-hv4zl   1/1     Running   0          3m11s

从下面springboot-mybatis-deployment的描述Events中可以看出滚动更新的过程

[root@master ~]# kubectl describe deployment springboot-mybatis-deployment
Name:                   springboot-mybatis-deployment
Namespace:              default
CreationTimestamp:      Wed, 08 Jul 2020 06:00:17 -0400
Labels:                 <none>
Annotations:            deployment.kubernetes.io/revision: 2
                        kubectl.kubernetes.io/last-applied-configuration:
                          {"apiVersion":"apps/v1","kind":"Deployment","metadata":{"annotations":{},"name":"springboot-mybatis-deployment","namespace":"default"},"sp...
Selector:               app=springboot-mybatis
Replicas:               2 desired | 2 updated | 2 total | 2 available | 0 unavailable
StrategyType:           RollingUpdate
MinReadySeconds:        0
RollingUpdateStrategy:  25% max unavailable, 25% max surge
Pod Template:
  Labels:  app=springboot-mybatis
  Containers:
   spingboot-mybatis:
    Image:        zjj2006forever/springboot-mybatis:1.3
    Port:         8300/TCP
    Host Port:    0/TCP
    Environment:  <none>
    Mounts:       <none>
  Volumes:        <none>
Conditions:
  Type           Status  Reason
  ----           ------  ------
  Available      True    MinimumReplicasAvailable
  Progressing    True    NewReplicaSetAvailable
OldReplicaSets:  <none>
NewReplicaSet:   springboot-mybatis-deployment-69787d89c4 (2/2 replicas created)
Events:
  Type    Reason             Age    From                   Message
  ----    ------             ----   ----                   -------
  Normal  ScalingReplicaSet  30m    deployment-controller  Scaled up replica set springboot-mybatis-deployment-5b78f66997 to 2
  Normal  ScalingReplicaSet  29m    deployment-controller  Scaled up replica set springboot-mybatis-deployment-5b78f66997 to 4
  Normal  ScalingReplicaSet  19m    deployment-controller  Scaled down replica set springboot-mybatis-deployment-5b78f66997 to 2
  Normal  ScalingReplicaSet  6m18s  deployment-controller  Scaled up replica set springboot-mybatis-deployment-69787d89c4 to 1
  Normal  ScalingReplicaSet  3m37s  deployment-controller  Scaled down replica set springboot-mybatis-deployment-5b78f66997 to 1
  Normal  ScalingReplicaSet  3m37s  deployment-controller  Scaled up replica set springboot-mybatis-deployment-69787d89c4 to 2
  Normal  ScalingReplicaSet  3m32s  deployment-controller  Scaled down replica set springboot-mybatis-deployment-5b78f66997 to 0

上面event中最后4行就是滚动更新的过程。很明显,滚动更新过程是创建一个新的pod,删除一个旧的pod,直到新的pod全部创建,旧的pod的全部删除。可以"滚动更新"这个词非常形象。滚动更新有如下优势:

1.新pod启动失败整个过程就会停止,剩下的旧pod依然可以提供服务。

2.为了保证服务不中断,deployment控制器会保证一次删除pod的比例和一次创建的pod的比例,默认都是yaml中replicas的25%。

3.这2个比例也可以通过参数来配置,看下面的yaml。maxSurge指每次滚动过程中可以创建多少个pod,maxUnavailable指一次更新中可以删除几个pod,这2个参数值也可以用百分数表示,指的是滚动过程中一次创建或删除的pod数量占replicas配置的pod的比例。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: springboot-mybatis-deployment
spec:
  selector:
    matchLabels:
      app: springboot-mybatis
  replicas: 2
  template:
    metadata:
      labels:
        app: springboot-mybatis
    spec:
      containers:
      - name: spingboot-mybatis
        imagePullPolicy: IfNotPresent
        image: zjj2006forever/springboot-mybatis:1.3
        ports:
        - containerPort: 8300
    strategy:
      type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 1

失败回滚

如果我们升级应用的过程中,pod启动失败,这时候我们为了不中断服务,必须回滚。比如之前的yaml文件中,我们定义的springboot-mybatis镜像版本是1.3,如果我们改成1.4版本,dockerhub上并没有这个版本,拉取失败导致pod启动失败。修改yaml文件中镜像版本到1.4后,执行更新命令

kubectl apply -f springboot-mybatis.yaml

这时deployment就会触发滚动更新,但是这时因为镜像拉取失败,pod创建失败,如下结果中第4行

[root@master ~]# kubectl get rs
NAME                                       DESIRED   CURRENT   READY   AGE
springboot-mybatis-deployment-5b78f66997   0         0         0       15h
springboot-mybatis-deployment-69787d89c4   2         2         2       14h
springboot-mybatis-deployment-7d6fc78b87   1         1         0       80s

我们再查看deployment的状态,如下,镜像版本是1.4,这时我们可以触发回滚操作。

[root@master ~]# kubectl describe deployment springboot-mybatis-deployment
Name:                   springboot-mybatis-deployment
Namespace:              default
CreationTimestamp:      Wed, 08 Jul 2020 06:00:17 -0400
Labels:                 <none>
Annotations:            deployment.kubernetes.io/revision: 3
                        kubectl.kubernetes.io/last-applied-configuration:
                          {"apiVersion":"apps/v1","kind":"Deployment","metadata":{"annotations":{},"name":"springboot-mybatis-deployment","namespace":"default"},"sp...
Selector:               app=springboot-mybatis
Replicas:               2 desired | 1 updated | 3 total | 2 available | 1 unavailable
StrategyType:           RollingUpdate
MinReadySeconds:        0
RollingUpdateStrategy:  25% max unavailable, 25% max surge
Pod Template:
  Labels:  app=springboot-mybatis
  Containers:
   spingboot-mybatis:
    Image:        zjj2006forever/springboot-mybatis:1.4
    Port:         8300/TCP
    Host Port:    0/TCP
    Environment:  <none>
    Mounts:       <none>
  Volumes:        <none>
Conditions:
  Type           Status  Reason
  ----           ------  ------
  Available      True    MinimumReplicasAvailable
  Progressing    True    ReplicaSetUpdated
OldReplicaSets:  springboot-mybatis-deployment-69787d89c4 (2/2 replicas created)
NewReplicaSet:   springboot-mybatis-deployment-7d6fc78b87 (1/1 replicas created)
Events:
  Type    Reason             Age   From                   Message
  ----    ------             ----  ----                   -------
  Normal  ScalingReplicaSet  14h   deployment-controller  Scaled up replica set springboot-mybatis-deployment-69787d89c4 to 1
  Normal  ScalingReplicaSet  14h   deployment-controller  Scaled down replica set springboot-mybatis-deployment-5b78f66997 to 1
  Normal  ScalingReplicaSet  14h   deployment-controller  Scaled up replica set springboot-mybatis-deployment-69787d89c4 to 2
  Normal  ScalingReplicaSet  14h   deployment-controller  Scaled down replica set springboot-mybatis-deployment-5b78f66997 to 0
  Normal  ScalingReplicaSet  3m3s  deployment-controller  Scaled up replica set springboot-mybatis-deployment-7d6fc78b87 to 1

下面命令可以查看deployment的升级历史

[root@master k8s]# kubectl rollout history deployment/springboot-mybatis-deployment
deployment.apps/springboot-mybatis-deployment 
REVISION  CHANGE-CAUSE
1         <none>
2         <none>
3         <none>

从上面的deployment的describe中我们可以看出目前revision是3(deployment.kubernetes.io/revision: 3),我们应该恢复到2,如下命令

kubectl rollout undo deployment/springboot-mybatis-deployment --to-revision=2

执行之后,再看deployment状态,镜像版本已经恢复到zjj2006forever/springboot-mybatis:1.3

[root@master k8s]# kubectl describe deployment
Name:                   springboot-mybatis-deployment
Namespace:              default
CreationTimestamp:      Wed, 08 Jul 2020 06:00:17 -0400
Labels:                 <none>
Annotations:            deployment.kubernetes.io/revision: 4
                        kubectl.kubernetes.io/last-applied-configuration:
                          {"apiVersion":"apps/v1","kind":"Deployment","metadata":{"annotations":{},"name":"springboot-mybatis-deployment","namespace":"default"},"sp...
Selector:               app=springboot-mybatis
Replicas:               2 desired | 2 updated | 2 total | 2 available | 0 unavailable
StrategyType:           RollingUpdate
MinReadySeconds:        0
RollingUpdateStrategy:  25% max unavailable, 25% max surge
Pod Template:
  Labels:  app=springboot-mybatis
  Containers:
   spingboot-mybatis:
    Image:        zjj2006forever/springboot-mybatis:1.3
    Port:         8300/TCP
    Host Port:    0/TCP
    Environment:  <none>
    Mounts:       <none>
  Volumes:        <none>
Conditions:
  Type           Status  Reason
  ----           ------  ------
  Available      True    MinimumReplicasAvailable
  Progressing    True    NewReplicaSetAvailable
OldReplicaSets:  <none>
NewReplicaSet:   springboot-mybatis-deployment-69787d89c4 (2/2 replicas created)
Events:
  Type    Reason             Age   From                   Message
  ----    ------             ----  ----                   -------
  Normal  ScalingReplicaSet  14h   deployment-controller  Scaled up replica set springboot-mybatis-deployment-69787d89c4 to 1
  Normal  ScalingReplicaSet  14h   deployment-controller  Scaled down replica set springboot-mybatis-deployment-5b78f66997 to 1
  Normal  ScalingReplicaSet  14h   deployment-controller  Scaled up replica set springboot-mybatis-deployment-69787d89c4 to 2
  Normal  ScalingReplicaSet  14h   deployment-controller  Scaled down replica set springboot-mybatis-deployment-5b78f66997 to 0
  Normal  ScalingReplicaSet  15m   deployment-controller  Scaled up replica set springboot-mybatis-deployment-7d6fc78b87 to 1
  Normal  ScalingReplicaSet  35s   deployment-controller  Scaled down replica set springboot-mybatis-deployment-7d6fc78b87 to 0

最后,从replicas的结果中我们可以看出,每次无论升级成功失败都会有一个replicas创建出来,为了限制保留的历史版本个数,可以通过参数spec.revisionHistoryLimit来进行设置。

[root@master k8s]# kubectl get rs
NAME                                       DESIRED   CURRENT   READY   AGE
springboot-mybatis-deployment-5b78f66997   0         0         0       15h
springboot-mybatis-deployment-69787d89c4   2         2         2       14h
springboot-mybatis-deployment-7d6fc78b87   0         0         0       14m

总结

deployment是kubernete中非常重要的一个编排技术,不过它有一个局限,只能编排无状态的pod,比如一个应用的集群,集群中的节点都是平等的,不存在主备关系。但是我们日常的开发中,好多pod是有状态的,比如一个部署在kubernete中的redis集群,会存在主从节点,这样启动的时候pod就存在顺序,deployment就不能满足了。

分类
收藏
回复
举报
回复
    相关推荐