Kubernetes控制器之ReplicaSet

ReplicaSet用来维护一组在任何时候都处于运行状态的Pod保持稳定的副本数。因此,它通常用来保证给定数量的完全相同的Pod的可用性。现在ReplicaSet基本取代了ReplicationController,ReplicaSet支持集合式的selector,而ReplicationController仅支持等式。不过现在建议使用Deployment来自动管理ReplicaSet,这样无需担心跟其他机制的不兼容问题,并且还支持版本记录、回滚、暂停升级等高级特性。

本文主要对Kubernetes的ReplicaSet控制器进行简单总结。

一、环境信息

本文所使用的环境如下:

  • 操作系统:CentOS Linux release 8.2.2004
  • Docker:19.03.12
  • kubernetes:v1.18.5

二、ReplicaSet简介

ReplicaSet的目的是维护一组在任何时候都处于运行状态的Pod保持稳定的副本数。因此,它通常用来保证给定数量的完全相同的Pod的可用性。

至于RepicaSet的工作原理,首先RepicaSet是通过一组字段定义的,包括一个用来识别可获得的Pod的selector,一个用来表明应该维护的Pod副本数(replica),一个用来指定应该创建新Pod以满足副本数条件时要使用的Pod模板(template)等。每个 ReplicaSet都将根据需要创建和删除Pod以达到期望的Pod副本数。当ReplicaSet需要创建新的Pod时,会使用所提供的Pod模板。ReplicaSet通过Pod上的metadata.ownerReferences字段连接到所属Pod,该字段指定当前对象属于哪个资源。ReplicaSet所获得的Pod都在其ownerReferences字段中包含了属主ReplicaSet的标识信息。正是通过这一连接,ReplicaSet获知了它所维护的Pod集合的状态并据此计划其操作行为。ReplicaSet使用其selector来识别要获取的Pod。如果某个Pod没有OwnerReference或者其OwnerReference不是一个控制器,并且其匹配到某ReplicaSet的selector,则该Pod立即被此ReplicaSet获得。

虽然ReplicaSet可以确保任何时间都有指定数量的Pod副本运行并可以独立使用,但现在它主要是用作协调Deploymen创建、删除和更新Pod的一种机制。使用Deployment时,我们不必担心它们创建的ReplicaSet如何管理,Deployment会拥有并管理它们,并向Pod提供声明式的更新以及许多其他有用的功能,例如滚动更新,Deployment支持而ReplicaSet不支持。所以推荐使用Deployment而不是直接使用ReplicaSet,除非需要自定义更新业务流程或根本不需要更新。

三、创建ReplicaSet

1.ReplicaSet清单

可以通过以下命令查看ReplicaSet资源清单规则:

kubectl explain rs
kubectl explain rs.spec
kubectl explain rs.spec.template

也可以通过官方Kubernetes API手册进行查找。这里主要总结一下资源清单中重要的字段:

字段类型说明
apiVersionstringapi版本定义
kindstring资源类型定义
metadataobject元数据定义
specobjectReplicaSet的Spec定义
spec.replicasintegerPod副本的期望数目,默认值为1
spec.selectorobject标签选择器,定义匹配Pod的标签。ReplicaSet管理所有标签与标签选择器匹配的Pod
spec.selector.matchLabelsobject{key,value}对的映射
spec.templateobjectPod模板定义,除了它是嵌套的并且没有apiVersionkind之外,与Pod资源清单的语法几乎完全一致。它是spec唯一需要的字段
spec.template.metadataobjectPod的元数据定义
spec.template.metadata.namestring定义Pod的名称
spec.template.metadata.labelsobject定义Pod的标签,必须与spec.selector匹配(可以多出其他标签),否则它将被API拒绝
spec.template.specobjectPod的Spec定义

注意:

  • 对于2个指定相同spec.selector但不同spec.template.metadata.labelsspec.template.spec字段的ReplicaSet,每个ReplicaSet将忽略另一个ReplicaSet创建的Pod。
  • 通常情况下不应该创建标签与此ReplicaSet标签选择器匹配的任何Pod,或者直接与另一个ReplicaSet或另一个控制器(如 Deployment)匹配的任何Pod,否则ReplicaSet会认为是它创建了这些Pod。

2.ReplicaSet示例

ReplicaSet通过其selector来识别要获取的Pod,管理所有标签与标签选择器匹配的Pod,一个简单的示意图如下:
1
首先准备一个镜像,创建一个名为mynginx1Dockerfile文件:

FROM nginx:alpine
RUN echo 'mynginx:v1' > /usr/share/nginx/html/index.html

构建mynginx:v1镜像:

docker build -t mynginx:v1 -f mynginx1 .

创建ReplicaSet资源清单文件mynginx-rs.yaml

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: mynginx-rs
  labels:
    app: mynginx
    env: test
spec:
  replicas: 3
  selector:
    matchLabels:
      app: mynginx
      env: test
  template:
    metadata:
      labels:
        app: mynginx
        env: test
        creator: rtxtitanv
    spec:
      containers:
      - name: nginx
        image: mynginx:v1
        imagePullPolicy: IfNotPresent
        ports:
        - name: http
          containerPort: 80        

执行以下命令创建ReplicaSet

kubectl apply -f mynginx-rs.yaml

查看ReplicaSetPod信息:

kubectl get rs -o wide 
kubectl describe rs mynginx-rs
kubectl get pod -o wide --show-labels

2
验证这些Pod的所有者引用是否为mynginx-rs,查看其中一个Pod的Yaml:

kubectl get pod mynginx-rs-jrv2t -o yaml

查看结果如下,这里只列出了其中一部分:

apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: "2020-08-24T02:06:33Z"
  generateName: mynginx-rs-
  labels:
    app: mynginx
    creator: rtxtitanv
    env: test
...
  name: mynginx-rs-jrv2t
  namespace: default
  ownerReferences:
  - apiVersion: apps/v1
    blockOwnerDeletion: true
    controller: true
    kind: ReplicaSet
    name: mynginx-rs
    uid: 066e381d-e74e-48ab-bfaa-732e308f2d0a
  resourceVersion: "543754"
  selfLink: /api/v1/namespaces/default/pods/mynginx-rs-jrv2t
  uid: aaf22e96-38f5-4604-a4cb-119f26e67117
...

可见在元数据的ownerReferences字段中设置了mynginx-rs的信息。下面删除其中一个Pod再次查看Pod,发现又创建了一个新的Pod以维持Pod副本数:
3

3.获取非模板创建的Pod

在创建没有控制器管理的Pod时最好确保Pod的标签不要与ReplicaSet的标签选择器匹配,因为ReplicaSet不限于拥有其Pod模板所指定的Pod,它可以获取其他的Pod。获取非模板创建的Pod有两种情况,如果先创建了ReplicaSet再创建标签与ReplicaSet的标签选择器匹配的Pod,ReplicaSet也会获取这些标签与ReplicaSet的标签选择器匹配的Pod,但是由于ReplicaSet会维护Pod副本数稳定处于期望副本数,获取了这些非模板创建的Pod后ReplicaSet所管理的Pod超出了期望副本数,这时这些非模板创建的Pod会被ReplicaSet终止。如下图所示,灰色的两个Pod表示在ReplicaSet之后创建的标签与ReplicaSet标签选择器匹配的Pod,被ReplicaSet获取之后由于超出了期望副本数3而被终止:
4
下面就创建两个与ReplicaSet的标签选择器匹配的Pod,先创建资源清单文件mynginx-pods.yaml

apiVersion: v1
kind: Pod
metadata:
  name: mynginx-pod1
  labels:
    app: mynginx
    env: test
    creator: rtxtitanv
spec:
  containers:
  - name: nginx
    image: mynginx:v1
    imagePullPolicy: IfNotPresent
    ports:
    - name: http
      containerPort: 80         
---
apiVersion: v1
kind: Pod
metadata:
  name: mynginx-pod2
  labels:
    app: mynginx
    env: test
    creator: rtxtitanv
spec:
  containers:
  - name: mginx
    image: mynginx:v1
    imagePullPolicy: IfNotPresent
    ports:
    - name: http
      containerPort: 80             

创建与ReplicaSet的标签选择器匹配的Pod并查看,发现新创建的Pod已终止或正在终止:
5
如果先创建标签与ReplicaSet的标签选择器匹配的Pod再创建ReplicaSet,ReplicaSet会先获取这些Pod,如果没有达到期望的副本数,ReplicaSet会根据其Spec创建了新的Pod直到Pod副本数达到期望数目为止,不管怎样,ReplicaSet会维护Pod副本数保持在期望副本数。如下图所示,先创建了图中左边的两个Pod,然后创建ReplicaSet,先创建的两个Pod标签匹配ReplicaSet标签选择器,被ReplicaSet获取,此时Pod副本数小于期望副本数3(如果等于期望副本数,则不会再创建Pod,如果多于期望副本数,会删除多余的Pod以维持期望副本数),ReplicaSet会根据其Pod模板再创建一个Pod:
6
删除ReplicaSet,然后先创建上面这两个Pod,再创建ReplicaSet,查看所有Pod发现ReplicaSet已经获取到了这两个自主创建的Pod,并根据其Spec创建了新的Pod直到Pod副本数达到期望数目为止,这样ReplicaSet就拥有了一组非同构的Pod
7
8

四、更新ReplicaSet

可以通过修改ReplicaSet的Pod模板来更新ReplicaSet,如下图所示,将Pod使用的镜像由mynginx:v1改为mynginx:v2,重载ReplicaSet可以进行更新,但由于新旧ReplicaSet的spec.selector是相同的,新的ReplicaSet将接管老ReplicaSet的Pod,所以需要删除老ReplicaSet所创建的Pod,新的ReplicaSet就会根据其Pod模板创建新的Pod,达到期望副本数为止:
9
10
先准备一个mynginx:v2镜像,创建一个名为mynginx2Dockerfile文件:

FROM nginx:alpine
RUN echo 'mynginx:v2' > /usr/share/nginx/html/index.html

构建mynginx:v2镜像:

docker build -t mynginx:v2 -f mynginx2 .

先删除之前创建的ReplicaSet再重新创建,然后修改Pod模板以进行更新。如下所示,修改ReplicaSet资源清单文件,将镜像mynginx:v1改为mynginx:v2

  template:
    metadata:
      labels:
        app: mynginx
        env: test
        creator: rtxtitanv
    spec:
      containers:
      - name: nginx
        image: mynginx:v2
        imagePullPolicy: IfNotPresent
        ports:
        - name: http
          containerPort: 80 

执行apply命令重载ReplicaSet,然后执行下面的命令查看Pod所用镜像,发现没有更新,如下图所示:

kubectl get pod -o custom-columns=Name:metadata.name,Image:spec.containers[0].image

11
这是因为这些Pod是在ReplicaSet重载之前创建的,需要手动删除ReplicaSet管理的Pod。下面手动删除ReplicaSet管理的Pod后再次查看Pod所用镜像,发现已经更新:
12

五、缩放ReplicaSet

通过更新spec.replicas字段,ReplicaSet可以被轻松的进行缩放。可以通过编辑资源清单文件修改spec.replicas字段,也可以通过kubect edit命令修改,kubectl还提供了一个子命令scale用于实现应用规模的伸缩,支持从资源清单文件中获取新的目标副本数量,也可以直接在命令行通过--replicas选项进行读取。下面先查看ReplicaSetPod
13
然后执行以下命令将Pod副本扩容为5个:

kubectl scale rs mynginx-rs --replicas=5

查看ReplicaSetPod
14
执行以下命令将Pod副本收缩至3个:

kubectl scale rs mynginx-rs --replicas=3

查看ReplicaSetPod
15
ReplicaSet也可以被HPA(Horizontal Pod Autoscaler)自动缩放。例如以下HPA资源清单:

apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
  name: mynginx-scaler
spec:
  scaleTargetRef:
    kind: ReplicaSet
    name: mynginx-rs
  minReplicas: 3
  maxReplicas: 10
  targetCPUUtilizationPercentage: 50

创建该HPA资源对象就能根据Pod的CPU利用率对目标ReplicaSet自动缩放,当CPU利用率超过50%Pod最多不能扩容至超过10个,当CPU利用率低于50%Pod最少不能缩减至少于3个。也可以使用kubectl autoscale命令完成相同的操作,更加简单:

kubectl autoscale rs mynginx-rs --max=10 --min=3 --cpu-percent=50

由于HPA需要获取CPU内存等指标,需要部署监控系统来收集这些指标,这里就不进行演示了。

六、将Pod从ReplicaSet隔离

可以通过改变Pod标签来从ReplicaSet中移除Pod。这种技术可以用来从服务中去除Pod,以便进行排错、数据恢复等。如果期望的副本数没有改变的话,以这种方式移除的Pod将被自动替换。如下图所示:
16
先查看Pod及其标签:
17
执行下面的命令修改其中一个pod的标签,然后查看Pod及标签,发现ReplicaSet又新建了一个标签为env=testpod,如下图所示:

kubectl label pod mynginx-rs-g75mm --overwrite env=dev

18
因为ReplicaSet管理所有标签与标签选择器匹配的Pod,当有一个pod的标签改变,不再与标签选择器匹配,这个Pod将从ReplicaSet中移除,而ReplicaSet发现管理的pod少了一个,就会新建一个以维持期望副本数。而app=mynginx1的pod就变为了自主pod,删除了也不会创建出一个新的Pod。下面删除修改了标签的Pod,发现并没有再创建Pod
19

七、删除ReplicaSet

要删除ReplicaSet和它的所有Pod,使用kubectl delete命令。默认情况下,垃圾收集器会自动删除所有依赖的Pod。执行以下命令删除ReplicaSet和它的所有Pod,然后查看ReplicaSetPod,发现均已经被删除,如下图所示:

kubectl delete rs mynginx-rs

20
如果只想删除ReplicaSet而不删除它的Pod,可以使用kubectl delete命令并设置--cascade=false选项。先创建ReplicaSet,查看ReplicaSetPod
21
执行以下命令只删除ReplicaSet,然后查看ReplicaSetPod,发现ReplicaSet被删了,Pod没有被删除,如下图所示:

kubectl delete rs mynginx-rs --cascade=false

22

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

RtxTitanV

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值