当前位置 博文首页 > RtxTitanV的博客:Kubernetes控制器之ReplicaSet

    RtxTitanV的博客:Kubernetes控制器之ReplicaSet

    作者:[db:作者] 时间:2021-07-07 10:09

    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

    cs
    下一篇:没有了