前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >kubernetes常用控制器之Deployment

kubernetes常用控制器之Deployment

作者头像
极客运维圈
发布2020-03-23 14:35:56
7980
发布2020-03-23 14:35:56
举报
文章被收录于专栏:乔边故事

一、简介

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

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

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

从上图可以看到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例子:

代码语言:javascript
复制
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。

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

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

(2)、收缩

当然,除了使用命令的方式来做水平扩展/收缩以外,还可以直接编辑其配置文件,使用kubectl edit命令,如下:

然后保存退出,就可以看到如下扩展已经OK了,收缩是一样的操作:

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

三、滚动更新/回滚

3.1、滚动更新

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

代码语言:javascript
复制
[root@master deployment]# kubectl apply -f nginx-deployment.yaml --record
deployment.apps/nginx-deployment configured

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

代码语言:javascript
复制
[root@master deployment]# kubectl get deployment
NAME               READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   3/3     3            3           6h6m

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

代码语言:javascript
复制
[root@master deployment]# kubectl rollout status deployment/nginx-deployment
deployment "nginx-deployment" successfully rolled out
[root@master deployment]#

我们可以查看Deployment的ReplicaSet:

代码语言:javascript
复制
[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来直接用来配置文件,这种修改保存退出就会立即生效,如下:

我们把镜像版本更新为1.8然后保存退出。然后使用kubectl rollout status来查看Deployment的变化情况:

代码语言:javascript
复制
[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的状态:

代码语言:javascript
复制
[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来自定义,比如:

代码语言:javascript
复制
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版本,故意制造故障。

代码语言:javascript
复制
[root@master ~]# kubectl set image deployment/nginx-deployment nginx=nginx:1.999
deployment.extensions/nginx-deployment image updated

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

代码语言:javascript
复制
[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命令,如下:

代码语言:javascript
复制
[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命令,如下:

代码语言:javascript
复制
[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

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

代码语言:javascript
复制
kubectl rollout history deployment/nginx-deployment --revision=2

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

代码语言:javascript
复制
[root@master ~]# kubectl rollout undo deployment/nginx-deployment --to-revision=2
deployment.extensions/nginx-deployment rolled back

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

代码语言:javascript
复制
[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。具体用法如下:

代码语言:javascript
复制
[root@master ~]# kubectl rollout pause deployment/nginx-deployment
deployment.extensions/nginx-deployment paused

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

然后执行恢复命令:

代码语言:javascript
复制
[root@master ~]# kubectl rollout resume deployment/nginx-deployment
deployment.extensions/nginx-deployment resumed

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

代码语言:javascript
复制
[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 进去查看默认保留的个数:

四、总结

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

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-02-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 乔边故事 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、简介
  • 二、水平扩展/收缩
  • 三、滚动更新/回滚
    • 3.1、滚动更新
      • 3.2、回滚
      • 四、总结
      相关产品与服务
      容器服务
      腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档