RelicaSet控制器

ReplicaSet控制器官方文档https://v1-16.docs.kubernetes.io/docs/concepts/workloads/controllers/replicaset/ K8S较早期的版本中仅有ReplicationController一种类型的Pod控制器,后来的版本中陆续引入了更多的控制器实现,这其中就包括用来取代RelicationController的新一代实现ReplicaSet。事实上,除了额外支持基于集合(set-based)的标签选择器,以及它的滚动更新(Rolling-update)机制要基于更高级的控制器Deployment实现之外,目前的RelicaSet的其余功能基本与ReplicationController相同。如果想要使用滚动更新功能请使用更高级别的控制器Deployment来实现。K8S官方目前也强烈推荐大家使用ReplicaSet控制器。目前ReplicationController基本也已经被废弃 虽然ReplicaSet可以独立使用,但目前的实践环境当中,它主要被Deployment控制器用于协调Pod创建,删除和更新的机制,当你使用Deployment时,就不需要担心还要管理他们创建的ReplicaSet。Deployment会拥有并管理他们的ReplicaSet .spec.template是.spec唯一需要的字段。.spec.template是Pod模板。它和Pod的语法几乎完全一样,除了它是嵌套的字段,因此它并没有apiVersion和kind字段,除了所需的Pod字段之外,Replicaset中的Pod模板必须指定适当的标签和适当的重启策略,对于标签,请确保不要与其他控制器重叠,对于重启策略.spec.template.spec.restartPolicy唯一允许的值是Alwas,这也是默认值,对于本地容器重新启动,ReplicaSet委托给了节点上的代理去执行,例如kubelet或docker

ReplicaSet概述

RelicaSet(简称RS)是Pod控制器的一种实现,用于确保由其管控的Pod对象副本在任一时刻都能精确满足用户期望的数量。RelicaSet控制器启动后会查找集群中匹配其标签选择器的Pod资源对象,当前活动对象的数量与期望的数量不吻合时,实行多退少补,即多则删除,少则通过Pod模板创建以补足,等Pod资源副本数量符合用户期望值后即进入下一轮和解循环 RelicaSet的副本数量,标签选择器甚至是Pod模板都可以随时按需进行修改,不过仅改动期望的副本数量会对现有的Pod副本产生直接影响。修改标签选择器可能会使得现有的Pod副本的标签变得不再匹配,此时ReplicaSet控制器要做的不过是不再计入它们而已。另外,在创建完成后,ReplicaSet也不会再关注Pod对象中的实际内容,因此Pod模板的改动也只会对后来新建的Pod副本产生影响。相比较手动创建和管理Pod资源来说,ReplicaSet能够实现以下功能

  • 确保Pod资源对象的数量精确反映期望值;RelicaSet需要确保由其控制运行的Pod副本数量精确吻合配置中定义的期望值,否则就会自动补足或终止多余的Pod
  • 确保Pod健康运行;探测到由其管控的Pod对象因其所在的工作节点故障而不可用时,自动请求由调度器于其他工作节点创建缺失的Pod副本
  • 弹性伸缩;业务规模因各种原因时长存在明显波动,在访问量最大或最小期间,可以通过ReplicaSet控制器动态调整相关Pod资源对象的数量。此外,在必要时还可以通过HPA(HroizontalPodAutoscaler)控制器实现Pod资源规模的自动伸缩

创建ReplicaSet

类似于Pod资源,创建ReplicaSet控制器对象同样可以使用YAML或json格式的清单文件定义其配置信息,而后使用相关的创建命令来完成资源的创建,上一篇的文章中给出了示例就是一个简单的ReplicaSet定义,它由apiVersion、kind、metadata、spec和status这5个一级字段组成,其中status是只读字段,因此需要在清单文件中配置的字段仅为前4个字段。它的spec字段一般嵌套如下几个属性字段

  • replicas: 定义期望的Pod副本数量
  • selector
  • template
  • minReadySeconds:新建的Pod对象,再启动后的多长时间内如果其容器未发生崩溃等异常情况即被视为“就绪”;默认为0秒,表示一旦就绪性探测成功,即被视为可用
    这里我们使用前一篇文章当中的清单文件,然后使用apply将它创建出来
  1. 1.查看清单文件
  2. [root@k8s-master01 con]# cat rs-demo.yaml
  3. apiVersion: apps/v1
  4. kind: ReplicaSet
  5. metadata:
  6. name: rs
  7. spec:
  8. replicas: 2
  9. selector:
  10. matchLabels:
  11. app: rs-damo
  12. template:
  13. metadata:
  14. labels:
  15. app: rs-damo
  16. spec:
  17. containers:
  18. - name: rs-busybox
  19. image: registry.cn-hangzhou.aliyuncs.com/jiangyida/busybox:0.1
  20. ports:
  21. - name: http
  22. containerPort: 80
  23. [root@k8s-master01 con]#
  24. 2.创建Pod
  25. [root@k8s-master01 con]# kubectl apply -f rs-demo.yaml
  26. replicaset.apps/rs created
  27. [root@k8s-master01 con]#
  28. #因为目前我们集群当中没有定义标签文件app: rs-damo的Pod资源存在,因此rs需要按照replicas字段的定义创建它们,名称以其所属的控制器名称为前缀。
  29. 3.查看Pod资源
  30. [root@k8s-master01 con]# kubectl get pods -l "app=rs-damo"
  31. NAME READY STATUS RESTARTS AGE APP=RS-DAMO APP
  32. rs-88n57 1/1 Running 0 4m20s rs-damo
  33. rs-rkg99 1/1 Running 0 4m20s rs-damo
  34. [root@k8s-master01 con]#

接下来我们可以使用kubectl get rs命令查看replicaSet控制器资源的相关状态。下面的命令结果显示出它已经根据清单配置的Pod模板创建了两个Pod资源,并且当前已经是READY状态

  1. [root@k8s-master01 con]# kubectl get rs
  2. NAME DESIRED CURRENT READY AGE
  3. rs 2 2 2 36s
  4. [root@k8s-master01 con]#

经由控制器创建与用户自主创建的Pod对象的功能并无不同,但其自动和解的功能在很大程度上能为用户省去不少的管理精力,这也是使得K8S系统至上的应用程序变得拥有自愈能力的主要保障

ReplicaSet管控下的Pod对象

前面的清单文件中,rs通过标签选择器将拥有”app=rs-damo”标签的Pod资源关联起来,并确保其数量精确符合所期望的数目,使用标签则其显示出的Pod资源列表也能验证这一点。然而,实际中存在着不少可能导致Pod对象数目与期望不符合的可能性,如Pod对象的意外删除,Pod对象标签的变动(已有的Pod资源变得不匹配控制器的标签选择器,或者外部的Pod资源标签变得匹配到了控制器的标签选择器)、控制器的标签选择器变动甚至是工作节点故障等。ReplicaSet控制器的和解循环过程能够实时监控到这类异常,并及时启动和解操作

示例1:缺少Pod副本

任何原因导致的相关Pod对象丢失,都会由ReplicaSet控制器自动补足。例如,手动删除上面列出的一个Pod对象

  1. [root@k8s-master01 con]# kubectl get pods -l "app=rs-damo"
  2. NAME READY STATUS RESTARTS AGE APP=RS-DAMO APP
  3. rs-2dc4v 1/1 Running 0 4m20s rs-damo
  4. rs-rkg99 1/1 Running 0 4m20s rs-damo
  5. [root@k8s-master01 con]
  6. [root@k8s-master01 con]# kubectl delete pods rs-2dc4v
  7. pod "rs-2dc4v" deleted
  8. [root@k8s-master01 con]#

再次列出相关Pod对象的信息,可以看到被删除的rs-2dc4v进入了终止过程,而新的Pod对象rs-tlcnw已经被创建出来

  1. [root@k8s-master01 log]# kubectl get pods
  2. NAME READY STATUS RESTARTS AGE
  3. rs-2dc4v 0/1 Terminating 0 9m25s
  4. rs-rkg99 1/1 Running 0 9m25s
  5. rs-tlcnw 1/1 Running 0 32s
  6. [root@k8s-master01 log]#

另外,强行修改隶属于控制器rs的某Pod资源(匹配与标签控制器)的标签,会导致它不再被控制器作为副本计数,这也将触发控制器的Pod对象副本缺失补足机制,例如,将rs-tlcnw的标签值置空

  1. [root@k8s-master01 con]# kubectl label pods rs-tlcnw app= --overwrite
  2. pod/rs-tlcnw labeled
  3. [root@k8s-master01 con]#

然后再列出相关Pod对象的信息,发现rs-tlcnw已经消失不见,并且根据ReplicaSet控制器再次补足一个Pod资源,但是我们将标签选择器置空的Pod也并未被删除,而只是变得不再由该Pod控制来管理了。

  1. [root@k8s-master01 con]# kubectl get pods -l "app=rs-damo"
  2. NAME READY STATUS RESTARTS AGE
  3. rs-d7grg 1/1 Running 0 86s
  4. rs-rkg99 1/1 Running 0 15m
  5. [root@k8s-master01 con]#

由此可见,修改Pod资源的标签即可将其从控制器的管控之下移除,当然修改后的标签如果又能被其它控制器资源的标签选择器所命中,则此时它成了隶属于另一控制器的副本。如果修改其标签后的Pod对象不再隶属于任何控制器,那么它就将称为自主式Pod,与此前手动直接创建的Pod对象的特性相同,即误删除或所在的工作节点故障都会造成其永久性的消失

  1. [root@k8s-master01 con]# kubectl get pods
  2. NAME READY STATUS RESTARTS AGE
  3. rs-d7grg 1/1 Running 0 4m22s
  4. rs-rkg99 1/1 Running 0 18m
  5. rs-tlcnw 1/1 Running 0 9m54s
  6. [root@k8s-master01 con]#
  7. [root@k8s-master01 con]# kubectl delete pods rs-tlcnw
  8. pod "rs-tlcnw" deleted
  9. [root@k8s-master01 con]# kubectl get pods
  10. NAME READY STATUS RESTARTS AGE
  11. rs-d7grg 1/1 Running 0 8m35s
  12. rs-rkg99 1/1 Running 0 23m
  13. [root@k8s-master01 con]

示例2:多出Pod副本

一旦被标签选择匹配到的Pod资源数量因任何原因超出期望值,多余的部分将都被控制器自动删除,例如,我们在创一个一个Pod资源,然后手动为这个Pod资源添加一个”app=rs-damo”标签

  1. [root@k8s-master01 con]# kubectl get pods
  2. NAME READY STATUS RESTARTS AGE
  3. rs-d7grg 1/1 Running 0 17h
  4. rs-rkg99 1/1 Running 0 17h
  5. [root@k8s-master01 con]#
  6. 可以看到我们再次创建了一个Pod资源
  7. [root@k8s-master01 nginx]# kubectl apply -f box.yaml
  8. pod/mybox created
  9. [root@k8s-master01 nginx]# kubectl get pods
  10. NAME READY STATUS RESTARTS AGE
  11. mybox 1/1 Running 0 3s
  12. rs-d7grg 1/1 Running 0 17h
  13. rs-rkg99 1/1 Running 0 17h
  14. [root@k8s-master01 nginx]#
  15. 修改mybox的标签为"app=rs-damo"
  16. [root@k8s-master01 nginx]# kubectl label pods mybox app=rs-damo
  17. pod/mybox labeled
  18. [root@k8s-master01 nginx]#

再次查看Pod资源,可以看到rs控制器启动了删除多余Pod的操作,Pod数量再次变成两个

  1. [root@k8s-master01 nginx]# kubectl get pods
  2. NAME READY STATUS RESTARTS AGE
  3. rs-d7grg 1/1 Running 0 17h
  4. rs-rkg99 1/1 Running 0 17h
  5. [root@k8s-master01 nginx]#

这意味着,任何自主式Pod或者本隶属于其他控制器的Pod资源,只要其标签的结果一旦匹配到了其他的副本控制器,就会导致这类Pod资源被删除

查看Pod资源变动的相关事件

kubectl describe replicasets命令可以打印出replicasSet控制器的详细状态,从下面的命令结果中events一段也可以看出,rs执行了Pod资源的创建和删除操作,为的就是确保其数量的精确性

  1. [root@k8s-master01 nginx]# kubectl describe rs rs
  2. Name: rs
  3. Namespace: default
  4. Selector: app=rs-damo
  5. Labels: <none>
  6. Annotations: kubectl.kubernetes.io/last-applied-configuration:
  7. {"apiVersion":"apps/v1","kind":"ReplicaSet","metadata":{"annotations":{},"name":"rs","namespace":"default"},"spec":{"replicas":2,"selector...
  8. Replicas: 2 current / 2 desired
  9. Pods Status: 2 Running / 0 Waiting / 0 Succeeded / 0 Failed
  10. Pod Template:
  11. Labels: app=rs-damo
  12. Containers:
  13. rs-busybox:
  14. Image: registry.cn-hangzhou.aliyuncs.com/jiangyida/busybox:0.1
  15. Port: 80/TCP
  16. Host Port: 0/TCP
  17. Environment: <none>
  18. Mounts: <none>
  19. Volumes: <none>
  20. Events:
  21. Type Reason Age From Message
  22. ---- ------ ---- ---- -------
  23. Normal SuccessfulDelete 4m18s replicaset-controller Deleted pod: mybox
  24. [root@k8s-master01 nginx]#

事实上,ReplicaSet控制器能对Pod对象数目的异常及时做出响应,是因为它向API Server注册监听(watch)了相关资源及其列表的变动信息,于是API Server会在变动发生时立即通知给相关的监听客户端 而因节点自身故障而导致的Pod对象丢失,ReplicaSet控制器一样会使用补足资源的方式进行处理,这里就不再演示了,感兴趣的朋友可以自己实验以下,方法很简单,就是关掉上面Pod对象所在的某一个节点,然后看看Pod是否会被控制器重新创建到别的节点

更新ReplicaSet控制器

ReplicaSet控制器的核心组成部分是标签选择器,副本数量及Pod模板,但更新操作一般是围绕replicas和template两个字段值进行的,毕竟改变标签选择器的需求几乎不存在。改动Pod模板的定义对已经创建完成的活动对象无效,但在用户逐个手动关闭其旧版本的Pod资源后就能以新代旧,实现控制器下应用版本的滚动升级。另外,修改副本的数量也就意味着应用规模的扩展或收缩。这两种操作也是系统运维人员日常维护工作的重要组成部分

更改Pod模板:升级应用

ReplicaSet控制器的Pod模板可随时按需修改,但它仅影响之后由其新建的Pod对象,对已有的副本不会产生作用。大多数情况下,用户需要改变的通常是模板中的容器镜像文件及其相关的配置以实现应用的版本升级。下面的示例文件中,与之前的rs比较唯一的不同之处就是镜像的改动,将v1改成v2

  1. apiVersion: apps/v1
  2. kind: ReplicaSet
  3. metadata:
  4. name: rs
  5. spec:
  6. replicas: 2
  7. selector:
  8. matchLabels:
  9. app: rs-damo
  10. template:
  11. metadata:
  12. labels:
  13. app: rs-damo
  14. spec:
  15. containers:
  16. - name: rs-busybox
  17. image: registry.cn-hangzhou.aliyuncs.com/jiangyida/busybox:0.2
  18. ports:
  19. - name: http
  20. containerPort: 80

对新版本的清单文件执行kubectl applykubectl replace命令即可完成rs控制器资源的修改操作

  1. [root@k8s-master01 con]# kubectl replace -f rs-demo.yaml
  2. replicaset.apps/rs replaced
  3. [root@k8s-master01 con]#

不过,控制器rs管控的现存Pod对象使用的依然是原来版本中定义的镜像

  1. [root@k8s-master01 con]# kubectl describe pods rs-d7grg
  2. ...
  3. ...
  4. ...
  5. Controlled By: ReplicaSet/rs
  6. Containers:
  7. rs-busybox:
  8. Container ID: docker://6951115c8734226dc2cf26f432d0f26bdc49c4c911e5b48b8b1adb468cfedd7a
  9. Image: registry.cn-hangzhou.aliyuncs.com/jiangyida/busybox:0.1
  10. Image ID: docker-pullable://registry.cn-hangzhou.aliyuncs.com/jiangyida/
  11. ...
  12. ...
  13. ...

此时,手动删除控制器现有的Pod对象(或修改与其匹配的控制器标签选择的标签),并由控制器基于新的Pod模板自动创建出足额的Pod副本,即可完成一次应用的升级。新旧更替的过程中支持如下两类方式

  • 一次性删除控制器相关的所有Pod副本或更改相关的标签;剧烈更替,可能会导致Pod中的应用短时间不可访问,生成中,此种做法不可取
  • 分批次删除旧的Pod副本或更改其标签(待控制器补足后再删除另一批);滚动更替,更替期间新旧版本共存
    例如,我们采用第一种方法进行操作,一次性删除rs相关的所有Pod副本,然后再查看其更新过后的Pod,可以看到Image字段已经变成v2版本了
  1. [root@k8s-master01 con]# kubectl delete pods -l "app=rs-damo"
  2. pod "rs-d7grg" deleted
  3. pod "rs-rkg99" deleted
  4. [root@k8s-master01 con]# kubectl get pods
  5. NAME READY STATUS RESTARTS AGE
  6. rs-n2pkw 1/1 Running 0 46s
  7. rs-v5rj7 1/1 Running 0 46s
  8. [root@k8s-master01 con]#
  9. [root@k8s-master01 con]# kubectl describe pods rs-n2pkw
  10. ...
  11. ...
  12. ...
  13. Containers:
  14. rs-busybox:
  15. Container ID: docker://394412aa13b1638863c67945c0ac21c0d7bf2bd2da26603227bdd95c1492f4c8
  16. Image: registry.cn-hangzhou.aliyuncs.com/jiangyida/busybox:0.2
  17. ...
  18. ...
  19. ...
  20. ...
  21. ...

必要时,用户还可以将Pod模板改回旧的版本进行应用的“降级”或“回滚”,它的操作过程与上述过程基本类似。事实上,修改Pod模板时,不仅仅能替换镜像文件的版本,甚至还可以将其替换成其他正在运行着的,完全不同应用的容器,只不过此类需求并不多见。若同时改动的还有Pod模板中的其他字段,那么在新旧更替的过程中,它们也将随之被应用。 以上操作只为说明应用的部署方式,实际使用时还需要更完善的机制。即便是仅执行了一到多次删除操作,手动执行更替操作也并非一项轻松的任务,幸运的是,更高级别的Pod控制器Deployment能够自动实现更完善的更新和回滚,并未用户提供自定义更新策略的接口。而且,经过精心组织的更新操作还可以实现诸如蓝绿部署、金丝雀部署和灰度部署等

扩容和缩容

改动ReplicaSet控制器对象配置中期望的Pod副本数量(replicas字段)会由控制器实时做出响应,从而实现应用规模的水平伸缩。replicas的修改及应用方式同Pod模板,不过,kubectl还提供了一个专用的子命令scale用于实现应用规模的伸缩,它支持从资源清单文件中获取新的目标副本数量,也可以直接命令行通过”—replicas”选型进行读取,例如,我们将rs控制器的Pod副本提升到5个

  1. [root@k8s-master01 con]# kubectl scale rs rs --replicas=5
  2. replicaset.apps/rs scaled
  3. [root@k8s-master01 con]# kubectl get pods
  4. NAME READY STATUS RESTARTS AGE
  5. rs-btc2h 1/1 Running 0 3s
  6. rs-n2pkw 1/1 Running 0 11m
  7. rs-sbpgn 1/1 Running 0 3s
  8. rs-v5rj7 1/1 Running 0 11m
  9. rs-zsmwl 1/1 Running 0 3s
  10. [root@k8s-master01 con]#
  11. [root@k8s-master01 con]# kubectl get rs rs
  12. NAME DESIRED CURRENT READY AGE
  13. rs 5 5 5 19h
  14. [root@k8s-master01 con]#

收缩规模的方式也扩展的方式是一样的,只需要明确指定目标副本数量即可

  1. [root@k8s-master01 con]# kubectl scale rs rs --replicas=3
  2. replicaset.apps/rs scaled
  3. [root@k8s-master01 con]# kubectl get pods
  4. NAME READY STATUS RESTARTS AGE
  5. rs-btc2h 1/1 Terminating 0 86s
  6. rs-n2pkw 1/1 Running 0 13m
  7. rs-sbpgn 1/1 Running 0 86s
  8. rs-v5rj7 1/1 Running 0 13m
  9. rs-zsmwl 1/1 Terminating 0 86s
  10. [root@k8s-master01 con]# kubectl get rs rs
  11. NAME DESIRED CURRENT READY AGE
  12. rs 3 3 3 19h
  13. [root@k8s-master01 con]#

另外,kubectl scale命令还支持在现有的Pod副本数量符合指定的值时执行扩展操作,这只需要为命令使用--current-replicas选项即可。例如,下面的命令表示如果rs目前的副本数量为3个,将将其扩展至4个

  1. [root@k8s-master01 con]# clear
  2. [root@k8s-master01 con]# kubectl get pods
  3. NAME READY STATUS RESTARTS AGE
  4. rs-n2pkw 1/1 Running 0 15m
  5. rs-sbpgn 1/1 Running 0 4m3s
  6. rs-v5rj7 1/1 Running 0 15m
  7. [root@k8s-master01 con]# kubectl scale rs rs --current-replicas=3 --replicas=4
  8. replicaset.apps/rs scaled
  9. [root@k8s-master01 con]#
  10. [root@k8s-master01 con]# kubectl get pods
  11. NAME READY STATUS RESTARTS AGE
  12. rs-hh2kh 1/1 Running 0 22s
  13. rs-n2pkw 1/1 Running 0 16m
  14. rs-sbpgn 1/1 Running 0 4m42s
  15. rs-v5rj7 1/1 Running 0 16m
  16. [root@k8s-master01 con]#
  17. 如果`--current-replicas`的值不是当前的活动Pod副本数量,那么该命令就会返回一个错误,例如下面的示例
  18. [root@k8s-master01 con]# kubectl scale rs rs --current-replicas=5 --replicas=4
  19. error: Expected replicas to be 5, was 4
  20. [root@k8s-master01 con]#

注意:如果ReplicaSet控制器管控的是有状态的应用,例如,主从架构的Redis集群,那么上述这些升级,降级、扩展和收缩的操作都需要精心编排和参与才能进行,不过,这也在一定程度上降低了K8S等容器编排的价值和意义。好在,它提供了StatefulSet资源来应对这种需求,因此,replicaSet通常仅用于管理无状态的应用,如http服务等

删除ReplicaSet控制器资源

使用kubectl delete命令删除ReplicaSet对象时默认会一并删除其管控的Pod对象。有时,考虑到这些Pod资源未必由其创建,或者即便由其创建却也并非其自身的组成部分,所以需要在命令后面使用--cascade=false选项,取消级联,删除相关的Pod对象,这在Pod资源后续可能会再次用到时尤为有用。例如,下面的示例,我们删除rs控制器,但是并不删除该控制器下面的Pod资源对象

  1. [root@k8s-master01 con]# kubectl delete rs rs --cascade=false
  2. replicaset.apps "rs" deleted
  3. [root@k8s-master01 con]# kubectl get pods
  4. NAME READY STATUS RESTARTS AGE
  5. rs-hh2kh 1/1 Running 0 8m22s
  6. rs-n2pkw 1/1 Running 0 24m
  7. rs-sbpgn 1/1 Running 0 12m
  8. rs-v5rj7 1/1 Running 0 24m
  9. [root@k8s-master01 con]#

删除操作完成之后,此前由rs控制器管控的Pod对象依旧处于运行状态,但它们已经变成了自主式的Pod,用户需要自行组织和维护它们,一旦删除了原来的ReplicaSet,我们也可以创建一个新的来替换它。由于新旧ReplicaSet的.spec.selector是相同的,新的ReplicaSet将接管老的Pod。但是,它并不会使用新的Pod模板。如果需要使用新的Pod模板,就需要使用上面的更新操作 尽管ReplicaSet控制器功能强大,但在实践中,它却并非是用户直接使用的控制器,而是由更高一级的Deployement控制器来管理ReplicaSet