zoukankan      html  css  js  c++  java
  • kubernetes控制器之Deployment

    一、简介

    Deployment实现了Kubernetes项目中非常重要的功能:
    (1)、水平扩展
    (2)、水平收缩

    比如更新了Deployment的Pod模板,比如修改了镜像版本,那么Deployment就会遵循滚动更新(rolling update)的方式来升级现有的容器 。这个操作依赖Kubernetes中一个非常重要的API对象:ReplicaSet(详情见3.2)。不过Deployment又在ReplicaSet之上又做了新的封装,其新特性有如下几点:
    (1)、Deployment具有ReplicaSet的全部功能;
    (2)、可以查看Deployment升级详细状态和事件;
    (3)、当升级出现问题时,可以使用回滚操作回滚到之前的任一版本;
    (4)、新增版本记录,每一次操作Deployment都会记录下来,这也是版本回滚的基础;
    (5)、对每一次升级,都能进行暂停和启动;

    从上面可以知道,Deployment已经具体ReplicaSet的全部功能,并且还有许多新的功能,所以推荐使用Deployment来管理Pod。

    image.png
    从上图可以看到Deployment、ReplicaSet、Pod它们以层层控制关系,Deployment可以拥有多个ReplicaSet,一个ReplicaSet可以拥有多个Pod。一个Deployment拥有多个ReplicaSet主要是为了支持回滚操作,每当操作Deployment的时候,就会生成一个新的ReplicaSet,然后逐步更新新的Pod,而老的ReplicaSet会逐步减少Pod直到新的ReplicaSet全部接管。这时候并不会删除老的ReplicaSet,系统会将其保存下来,以备回滚使用。

    ReplicaSet还负责通过"控制器模式",保证系统的Pod数永远等于期望数,这也是Deployment只允许restartPolicy=Always的原因:只有在容器能保证自己始终处于running状态,通过ReplicaSet调整Pod的数量才有意义。

    而在此基础上,Deployment同样通过"控制器模式",来操作ReplicaSet的个数和属性,进而实现水平扩展/收缩和滚动更新这两个动作。其中水平扩展和收缩非常容易实现,Deployment Controller只需要修改它的ReplicaSet的Pod副本数就可以了。

    二、水平扩展/收缩

    我们看下面一个Deployment例子:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx-deployment
      labels:
        app: nginx
    spec:
      replicas: 3
      selector:
        matchLabels:
          app: nginx
      template:
        metadata:
          labels:
            app: nginx
        spec:
          containers:
          - name: nginx
            image: nginx:1.7.9
            ports:
            - containerPort: 80
    
    

    然后我们创建这个Deployment。
    image.png
    补充字段说明:
    (1)、READY:用户期望的Pod个数;
    (2)、UP-TO-DATE:当前处于最新版本的Pod个数;
    (3)、AVAILABLE:当前已经可用的Pod数,也就是处于running状态并且是最新的版本;

    从上我们看到Deployment和Pod都正常启动并且数量和期望的一致,现在我们使用kubectl scale来做水平扩展收缩。
    (1)、扩展
    image.png

    (2)、收缩
    image.png

    当然,除了使用命令的方式来做水平扩展/收缩以外,还可以直接编辑其配置文件,使用kubectl edit命令,如下:
    image.png
    然后保存退出,就可以看到如下扩展已经OK了,收缩是一样的操作:
    image.png

    除了上面两种方法,还可以直接编辑我们原始的YAML文件,然后使用kubectl apply -f nginx-deployment.yaml来做扩展和收缩,甚至可以用kubectl patch来打补丁,其内容用JSON语法。

    三、滚动更新/回滚

    3.1、滚动更新

    上面介绍了水平扩展和收缩,下面来介绍一下滚动更新和回滚操作。
    我们还是以上面的YAML文件为例,首先,我们创建这个YAML文件,这一次我们在创建的命令上加一个--record,它的作用是记录每次我们操作所执行的命令,方便后面操作。

    [root@master deployment]# kubectl apply -f nginx-deployment.yaml --record
    deployment.apps/nginx-deployment configured
    

    然后我们来查看集群状态:

    [root@master deployment]# kubectl get deployment
    NAME               READY   UP-TO-DATE   AVAILABLE   AGE
    nginx-deployment   3/3     3            3           6h6m
    

    我们可以通过kubectl rollout status 来查看Deployment对象的状态变化,如下:

    [root@master deployment]# kubectl rollout status deployment/nginx-deployment
    deployment "nginx-deployment" successfully rolled out
    [root@master deployment]# 
    

    我们可以查看Deployment的ReplicaSet:

    [root@master deployment]# kubectl get rs
    NAME                          DESIRED   CURRENT   READY   AGE
    nginx-deployment-5754944d6c   3         3         3       54m
    

    然后我们修改Pod的模板做滚动更新,修改Pod模板的方式也有很多,可以直接kubectl edit 修改配置文件,也可以修改源文件,然后使用kubectl apply -f 来使配置生效,我们这里采用kubectl edit来直接用来配置文件,这种修改保存退出就会立即生效,如下:
    image.png
    我们把镜像版本更新为1.8然后保存退出。然后使用kubectl rollout status来查看Deployment的变化情况:

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

    然后我们可以看到会启动一个新的ReplicaSet,来使用这个新的Pod模板来创建新的副本,然后会从老的ReplicaSet删除老的副本,如此进行直到版本更新完成。像这样将一个集群中正在运行的多个Pod版本,交替进行升级的过程叫做滚动更新。

    我们可以通过kubectl get rs查看新旧两个ReplicaSet的状态:

    [root@master ~]# kubectl get rs
    NAME                          DESIRED   CURRENT   READY   AGE
    nginx-deployment-5754944d6c   0         0         0       67m
    nginx-deployment-6f655f5d99   3         3         3       7h2m
    

    这种滚动更新的好处是:如果在更新过程中,新版本Pod有问题,那么滚动更新就会停止,这时候运维和开发就可以介入查看其原因,由于应用本身还有两个旧版本的Pod在线,所以并不会对服务造成太大的影响;当然,这时候应在Pod中加上health check检查应用的健康状态,而不是简单的依赖容器的running状态。为了进一步保证服务的延续性,Deployment Controller还会确保在任何时间窗口内,只有指定比例的Pod处于离线状态,同时它也会确保在任何时间窗口内,只有指定比例的Pod被创建,这个比例默认是DESIRED的25%。

    当然可以通过修改Deployment对象的一个字段RollingUpdateStrategy来自定义,比如:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx-deployment
      labels:
        app: nginx
    spec:
    ...
      strategy:
        type: RollingUpdate
        rollingUpdate:
          maxSurge: 1
          maxUnavailable: 1
    

    说明:
    (1)、maxSurge:定义除了DESIRED数量之外,在一次滚动更新过程中,Deployment还可以创建多少Pod;
    (2)、maxUnavailable:定义在一次滚动更新过程中,Deployment最多可以删除多少Pod;
    另外,这两个配置还可以通过设置百分值来表示。
    如此,我们可以得到如下关系图:

    Deployment实际控制的是ReplicaSet的数目以及每个ReplicaSet的属性。而一个应用版本,对应的就是一个ReplicaSet,而这个版本应有的Pod数量,是通过ReplicaSet自己的控制器来管理。

    3.2、回滚

    从上面我们明白了应用版本和ReplicaSet的对应关系,下面就来介绍一下它是如何回滚的。
    现在我们来更改Pod模板中的镜像版本信息,上面介绍了直接修改配置文件的方法来修改,这次用kubectl set image命令来修改。
    如下,我们修改一个不存在的nginx版本,故意制造故障。

    [root@master ~]# kubectl set image deployment/nginx-deployment nginx=nginx:1.999
    deployment.extensions/nginx-deployment image updated
    

    然后我们来查看ReplicaSet的状态:

    [root@master ~]# kubectl get rs
    NAME                          DESIRED   CURRENT   READY   AGE
    nginx-deployment-5754944d6c   0         0         0       103m
    nginx-deployment-6f655f5d99   3         3         3       7h37m
    nginx-deployment-79c5b65fdb   1         1         0       41s
    

    我们可以看到新创建了一个ReplicaSet,其中READY状态为0,这是因为我们这个镜像并不存在,所以就无法更新。

    我们可以通过一下方法进行回滚:
    (1)、直接回滚到上一个版本,我们执行kubectl rollout undo命令,如下:

    [root@master ~]# kubectl rollout undo deployment/nginx-deployment
    deployment.extensions/nginx-deployment rolled back
    [root@master ~]# kubectl get rs
    NAME                          DESIRED   CURRENT   READY   AGE
    nginx-deployment-5754944d6c   0         0         0       106m
    nginx-deployment-6f655f5d99   3         3         3       7h41m
    nginx-deployment-79c5b65fdb   0         0         0       3m59s
    

    这时候通过查看ReplicaSet的状态,可以看到刚新创建的ReplicaSet的Pod数收缩为0了。

    (2)、我们通过查看历史版本,恢复到任意版本,我们通过kubectl rollout history命令,如下:

    [root@master ~]# kubectl rollout history deployment/nginx-deployment
    deployment.extensions/nginx-deployment 
    REVISION  CHANGE-CAUSE
    2         kubectl apply --filename=nginx-deployment.yaml --record=true
    4         kubectl apply --filename=nginx-deployment.yaml --record=true
    5         kubectl apply --filename=nginx-deployment.yaml --record=true
    

    然后选择我们可以查看对应版本的详细信息:

    kubectl rollout history deployment/nginx-deployment --revision=2
    

    确定是我们需要的版本后就可以执行如下命令进行回滚操作:

    [root@master ~]# kubectl rollout undo deployment/nginx-deployment --to-revision=2
    deployment.extensions/nginx-deployment rolled back
    

    这时我们可以看到ReplicaSet已经回滚到上一个版本了:

    [root@master ~]# kubectl get rs
    NAME                          DESIRED   CURRENT   READY   AGE
    nginx-deployment-5754944d6c   3         3         3       115m
    nginx-deployment-6f655f5d99   0         0         0       7h50m
    nginx-deployment-79c5b65fdb   0         0         0       13m
    

    显然,从上面整个过程,我们知道只要我们对这个Deployment做一次更新操作,就会生成一个ReplicaSet,如果更新很频繁,这显然是有点浪费资源了,Kubernetes为了处理这类需求提供了一个指令kubectl rollout pause,它会让我们对Deployment的多次操作只生成一个ReplicaSe。具体用法如下:

    [root@master ~]# kubectl rollout pause deployment/nginx-deployment
    deployment.extensions/nginx-deployment paused
    

    然后可以用kubectl set image 或者kubectl edit随意修改这个Deployment的内容,等到我们修改完成后,再执行kubectl rollout resume命令来做恢复操作,比如我们修改image镜像和添加一个新的容器,然后保存退出:
    image.png
    然后执行恢复命令:

    [root@master ~]# kubectl rollout resume deployment/nginx-deployment
    deployment.extensions/nginx-deployment resumed
    

    我们上面最了两次修改,然后我们查看ReplicaSet:

    [root@master ~]# kubectl get rs
    NAME                          DESIRED   CURRENT   READY   AGE
    nginx-deployment-5754944d6c   0         0         0       132m
    nginx-deployment-5b9b565595   1         1         0       11s
    nginx-deployment-6f655f5d99   2         2         2       8h
    

    然后我们发现只生成了一个ReplicaSet,由于我本地没有这个镜像,所以拉取镜像过程中READY状态为0。

    这种办法会随着应用版本的不断增加,也会创建很多的ReplicaSet版本,所以Deployment对象还定义了一个字段revisionHistoryLimit,就是定义Kubernetes为Deployment保留的历史版本个数。
    我们可以通过kubectl edit 进去查看默认保留的个数:
    image.png

    四、总结

    从全文可知,Deployment实际是一个两层控制器:
    (1)、它通过ReplicaSet的个数来描述应用版本个数;
    (2)、它通过ReplicaSet的属性来保证Pod的副本数;
    而且Deployment的灵活控制,很方便水平扩展/收缩还有滚动更新以及回滚操作。

  • 相关阅读:
    HDU
    POJ
    POJ
    POJ
    POJ
    POJ
    POJ
    SPFA算法——最短路径
    POJ1251 Jungle Roads Kruskal+scanf输入小技巧
    MongoDB--关于数据库及选择MongoDB的原因
  • 原文地址:https://www.cnblogs.com/coolops/p/12986184.html
Copyright © 2011-2022 走看看