打赏 jQuery火箭图标返回顶部代码

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;

另外,这两个配置还可以通过设置百分值来表示。

如此,我们可以得到如下关系图:

image

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的灵活控制,很方便水平扩展/收缩还有滚动更新以及回滚操作。

 
posted @ 2020-12-07 11:52  浪漫De刺猬  阅读(275)  评论(0编辑  收藏  举报