美文网首页
深入剖析k8s中常见的控制器

深入剖析k8s中常见的控制器

作者: 文景大大 | 来源:发表于2022-04-22 14:06 被阅读0次

    本文是《深入剖析k8s》学习笔记的第三篇,主要对k8s中的控制器进行分析和讲解。

    pod是k8s操作的最小单元,操作pod的工作都是由控制器controller完成的,对应k8s中的组件就是kube-controller-manager,其下常见的控制器类型有:

    • Deployment,无状态容器控制器,通过控制ReplicaSet来控制pod;应用场景web应用;
    • StatefulSet,有状态容器控制器,保证pod的有序和唯一,pod的网络标识和存储在pod重建前后一致;应用场景主从架构;
    • DeamonSet,守护容器控制器,确保所有节点上有且仅有一个pod;应用场景监控;
    • Job,普通任务容器控制器,只会执行一次;应用场景离线数据处理;
    • CronJob,定时任务容器控制器,定时执行;应用场景通知、备份;

    控制器的yaml文件一般分为两个部分,上半部分是关于控制器的定义,下半部分是关于被控制对象,也就是pod的定义:

    ## 上半部分,定义控制器
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx-deployment
    spec:
      # 管理标签为app=nginx的pod
      selector:
        matchLabels:
          app: nginx
      # 确保被管理的对象数量始终为3
      replicas: 3
      ## 下半部分,定义被控制的对象,也就是pod
      template:
        metadata:
          labels:
            app: nginx
        spec:
          containers:
          - name: nginx
            image: nginx:1.7.9
            ports:
            - containerPort: 80
    

    Deployment、ReplicaSet、Pod三者之间是一种层层控制的关系,ReplicaSet通过控制器模式来保证pod的数量永远等于指定的个数,而Deployment同样也通过控制器的模式来操作ReplicaSet。如此,Deployment可以很方便地实现如下两个特性(并不只是Deployment控制器的功能):

    • 水平收缩,通过修改replicas副本数量,Deployment将指令传递给ReplicaSet,由ReplicaSet来实现pod的水平收缩;
    • 滚动更新,Deployment会创建一个新的ReplicaSet来逐一新建新版本的pod,旧的ReplicaSet也逐渐将旧版本的pod副本数量降低到0;好处就是如果新版本的pod创建过程中出现问题,滚动更新会中断,旧版本的pod也会停止销毁,此时还能对外提供旧版本的服务,不会导致业务中断;当然,我们还可以通过如下的更新策略字段来控制新版本滚动更新的范围,实现金丝雀发布或者灰度发布的目的:
      • partition,StatefulSet控制器拥有该属性,表示编号大于等于该值的pod才会更新为新的版本;
      • maxSurge,Deployment拥有该属性,更新时同一时间新建pod的数量占总数量的百分比,默认25%;
      • MaxUnavailable,Deployment拥有该属性,更新时同一时间可以删除pod的数量占总数量的百分比,默认25%;
      • pods,Deployment拥有该属性,表示可以一次性更新的pod数量;

    StatefulSet主要是为了满足需要维持应用之间拓扑状态、稳定应用各自的网络状态、保持应用各自存储状态的情形而设计的。

    • 拓扑状态,即多个pod之间存在启动依赖关系,比如主从架构中,从节点肯定要依赖并晚于主节点才能启动,且写请求一定只能转发给主节点,这种情况下,Deployment就无法解决。StatefulSet之所以能满足该场景,是因为其给所有pod进行了编号,编号以StatefulSet Name-index命名,比如mystatefulset-0、mystatefulset-1,每个pod按照编号递增,永不重复。这些pod的创建是顺序同步进行的,前面的pod没有进入到running状态,后面的pod就会一直pending。
    • 网络状态,所有pod都进入running之后,各自都会有固定不变的网络身份,即他们的hostname,和它们的pod编号名称一样,固定不变是指无论重新创建多少次,各个pod的网络身份始终一致。这样通过headless service方式访问每个pod的地址就始终固定不变,比如mystatefulset-0.servicename、mystatefulset-1.servicename,如此StatefulSet就保证了pod网络标识的稳定性。
    • 存储状态,每个pod挂载pvc时,也会给pvc命名,命名规则为pvc-StatefulSet Name-index,比如mypvc-mystatefulset-0、mypvc-mystatefulset-1,无论pod重新创建与否,每个pod与其对应的pvc始终都会处于绑定状态。如此StatefulSet就保证了存储状态的稳定性。

    DaemonSet控制器确保k8s集群中的每个节点有且仅有一个定义的pod运行。那么它是如何实现这个功能的呢?

    • 从etcd中获取所有node的信息,循环遍历每个node,没有守护容器的就新建,超过1个的就删除,正好就1个的就表示正常;
    • 通过nodeAffinity节点亲和性来保证每个守护pod只会在和其亲和的节点上被调度运行;
    • 通过tolerations声明,允许守护pod可以在被标记为污点的Node上调度运行;

    建议在设置DaemonSet控制器时,限制守护pod的资源占用上线,避免守护容器过度占用宿主机的资源,影响用户容器的正常运行。

    前面所说的Deployment、StatefulSet、DaemonSet都是一种Long Running Task,即长在线业务,这些应用一旦运行起来,除非出错或者停止,它的容器进程会一直保持在running的状态。然而现实中有种业务是执行完成就结束,不需要一直在线运行的,这种业务被称为离线业务,Batch Job,就是我们接下来要介绍的Job和CronJob。

    如下是一个Job的yaml定义代码,它也是直接管理pod,其中的部分字段含义如下:

    • restartPolicy,指pod中的任务执行失败时的重启策略;
      • Never,表示pod不要重启,但是会创建新的pod来替换旧的pod执行任务;
      • OnFailure,pod不会变化,但是会尝试重启pod中的容器;
    • spec.backoffLimit,任务失败的最大重试次数,每次重试的时间间隔是按照指数级增加的,比如10s、20s、40s......
    • spec.activeDeadlineSeconds,任务最大可运行时间,到了这个时间,Job中还未结束的pod都会被强制停止;
    
    apiVersion: batch/v1
    kind: Job
    metadata:
      name: test-job
    spec:
     # 定义pod模板
      template:
        spec:
          # 定义pod中容器
          containers:
          - name: test01
            image: resouer/ubuntu-bc 
            # 需要在容器中执行的任务,执行完毕就退出
            command: ["sh", "-c", "echo 'scale=10000; 4*a(1)' | bc -l "]
          # pod的重启策略,通常有Never和OnFailure
          restartPolicy: Never
      # 任务失败重试次数,默认为6
      backoffLimit: 4
    

    Job还支持任务的并行执行,主要通过如下两个参数来控制并行的策略:

    • spec.parallelism,任务并行度,定义一个Job同时最多可以启动pod的数量;
    • spec.completions,任务数,定义一个Job总共需要完成多少个pod的数量;

    CronJob是Job的控制器,通过控制Job来控制pod,只是比Job多了调度cron表达式的功能。它所用的cron表达式是unix cron风格的,支持5位,分别代表分、时、日、月、星期,比如*/1 * * * *就表示每隔1分钟就创建一个Job,但是并不限制已经创建Job的结束时间,所以可能就会出现多个Job同时在运行的情况,此时可以通过如下的字段来进行约束:

    • spec.concurrencyPolicy,定义Job的调度策略;
      • Allow,允许多个Job同时运行;
      • Forbid,不允许多个Job同时运行,该创建周期被跳过;
      • Replace,新周期创建的Job会替换旧的还没有执行完成的Job;
    • spec.startingDeadlineSeconds,指定若干秒内,某个Job如果执行100次都失败,就会停止再次创建这个Job;

    相关文章

      网友评论

          本文标题:深入剖析k8s中常见的控制器

          本文链接:https://www.haomeiwen.com/subject/amhnertx.html