• k8s CRD相关


    Operator与CRD

    Operator不应当被称作是一种工具或者系统,它应该算是一种封装、部署和管理 Kubernetes 应用的方法,尤其是针对最复杂的有状态应用去封装运维能力的解决方案,最早由 CoreOS 公司(于 2018 年被 RedHat 收购)的华人程序员邓洪超所提出。

    Operator 将简洁的高级指令转化为 Kubernetes 中具体操作的方法, Helm 或者 Kustomize 的思路并不相同。Helm 和 Kustomize 最终仍然是依靠 Kubernetes 的内置资源来跟 Kubernetes 打交道的,Operator 则是要求开发者自己实现一个专门针对该自定义资源的控制器,在控制器中维护自定义资源的期望状态。通过程序编码来扩展 Kubernetes,比只通过内置资源来与 Kubernetes 打交道要灵活得多,譬如当需要更新集群中某个 Pod 对象的时候,由 Operator 开发者自己编码实现的控制器完全可以在原地对 Pod 进行重启,而无需像 Deployment 那样必须先删除旧 Pod,然后再创建新 Pod。

    1、基本概念

    • CRD (Custom Resource Definition): 允许用户自定义 Kubernetes 资源,是一个类型(和 Pod、service 类似);包括可指定的名称和模式,无需任何编程。Kubernetes API提供和处理自定义资源的存储

    • CR (Custom Resourse): CRD 的一个具体实例;
      自定义资源:扩展Kubernetes API或允许将自定义API引入kubernetes集群的对象
      自定义控制器:以新的方式处理内置的Kubernetes对象,如Deployment、Service等,或管理自定义资源,如同管理本机Kubernetes组件

    • Operator模式(适用于CRD和自定义控制器controller):Operator基于Kubernetes资源和控制器增加了允许Operator执行常见应用程序任务的配置。

    Kubernetes 1.7之后,提供了CRD(CustomResourceDefinitions)自定义资源的二次开发能力来扩展kubernetes API,通过此扩展可以向kubernetes API中增加新的资源类型,会比修改kubernetes apiserver的源代码或创建自定义的apiserver来的更加的简洁和容易。**用于统一部署/编排多个内置K8S资源(pod,service等),**熟练掌握 CRD 是成为 Kubernetes 高级玩家的必备技能。

    1.2 创建crd

    当你创建一个新的CustomResourceDefinition (CRD)时,Kubernetes API服务器将为你指定的每个版本创建一个新的RESTful资源路径,我们可以根据该api路径来创建一些我们自己定义的类型资源。

    CRD可以是命名空间的,也可以是集群范围的,由CRD的作用域(scpoe)字段中所指定的,与现有的内置对象一样,删除名称空间将删除该名称空间中的所有自定义对象。customresourcedefinition本身没有名称空间,所有名称空间都可以使用。

    operator与crd实质

    k8s的文档中本身没有operator这个词,operator实质是指:用户注册自己自定义的Custom Resource Definition,然后创建对应的资源实例(称为Custom Resource,简称CR),而后通过自己编写Controller来不断地检测当前k8s中所定义的CR的状态,如果状态和预期不一致,则调整。Controller具体做的事就是通过调用k8s api server的客户端,根据比较预期的状态和实际的状态,来对相应的资源进行 增,删,改。

    举个例子,deployment中的replica数量是3,意味着pod的数量必须维持在3,多了,就去除,少了,就创建。由于deployment是k8s内置的资源,k8s本身就有内置的controller来维护deployment的状态。如果自己要创建一个新的逻辑,那么就创建新的CRD和controller,来创建和维护对应的deployment,service之类的服务。

    为什么需要CRD?

    helm也可以做到统一部署/编排deployment,service,ingress,但它缺乏对资源的全生命周期的监控

    CRD通过apiserver接口,在etcd中注册一种新的资源类型,此后就可以创建对应的资源对象&并监控它们的状态&执行相关动作,

    https://zhuanlan.zhihu.com/p/423735403

    因为k8s内置的对象对于高端玩家不够使
    一个典型的例子就是一键化部署prometheus套件的kube-prometheus
    如果我们自己在k8s中部署prometheus全家桶,需要写的yaml很多,而且分片等也要自己实现,那么这个项目刚好使用了k8s的 crd封装了serviceMonitor对象
    kube-prometheus请看kube-prometheus和prometheus-operator教程之实战和原理介绍

    在这里插入图片描述

    k8s deployment controller

    比如kube-controller-manager中的deployment控制器,在初始化的时候就会传入要监听 Deployments、ReplicaSets和pod三个informer对象
    首先list一下对象到本地缓存,同时watch对象的变更,等于增量更新

    func startDeploymentController(ctx ControllerContext) (controller.Interface, bool, error) {
        dc, err := deployment.NewDeploymentController(
            ctx.InformerFactory.Apps().V1().Deployments(),
            ctx.InformerFactory.Apps().V1().ReplicaSets(),
            ctx.InformerFactory.Core().V1().Pods(),
            ctx.ClientBuilder.ClientOrDie("deployment-controller"),
        )
        if err != nil {
            return nil, true, fmt.Errorf("error creating Deployment controller: %v", err)
        }
        go dc.Run(int(ctx.ComponentConfig.DeploymentController.ConcurrentDeploymentSyncs), ctx.Stop)
        return nil, true, nil
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    然后内部会做sync其实就是Reconcile loop,即调谐循环
    说白了就是对比对象的 actualState 和expectState的差异,执行对应的增删操作 比如deployment中的扩缩容操作

    阿里云k8s日志采集 crd AliyunLogConfig

    K8S内部会注册自定义资源(CRD,CustomResourceDefinition)AliyunLogConfig,并部署alibaba-log-controller

    ⚡ kubectl get AliyunLogConfig -n kube-system
    NAME                                                               AGE
    k8s-nginx-ingress                                                  112d
    security-inspector-polaris-log-c9f3e93dda54e4407ac5ad01b9a910e9a   112d
    
    • 1
    • 2
    • 3
    • 4
     kubectl get AliyunLogConfig k8s-nginx-ingress -o yaml -n kube-system
    apiVersion: log.alibabacloud.com/v1alpha1
    kind: AliyunLogConfig
    metadata:
      creationTimestamp: "2022-05-20T11:34:26Z"
      generation: 2
      name: k8s-nginx-ingress
      namespace: kube-system
      resourceVersion: "1809"
      uid: 946a3743-b1c2-4313-a91a-a0865c8085dc
    spec:
      extenions: ""
      lifeCycle: null
      logstore: nginx-ingress
      logtailConfig:
        configName: k8s-nginx-ingress
        inputDetail:
          plugin:
            inputs:
            - detail:
                IncludeLabel:
                  io.kubernetes.container.name: nginx-ingress-controller
                Stderr: false
                Stdout: true
              type: service_docker_stdout
            processors:
            - detail:
                KeepSource: false
                Keys:
                - client_ip
                - x_forward_for
                - remote_user
                - time
                - method
                - url
                - version
                - status
                - body_bytes_sent
                - http_referer
                - http_user_agent
                - request_length
                - request_time
                - proxy_upstream_name
                - upstream_addr
                - upstream_response_length
                - upstream_response_time
                - upstream_status
                - req_id
                - host
                NoKeyError: true
                NoMatchError: true
                Regex: ^(\S+)\s-\s\[([^]]+)]\s-\s(\S+)\s\[(\S+)\s\S+\s"(\w+)\s(\S+)\s([^"]+)"\s(\d+)\s(\d+)\s"([^"]*)"\s"([^"]*)"\s(\S+)\s(\S+)+\s\[([^]]*)]\s(\S+)\s(\S+)\s(\S+)\s(\S+)\s(\S+)\s*(\S*).*
                SourceKey: content
              type: processor_regex
        inputType: plugin
      machineGroups: null
      productCode: k8s-nginx-ingress
      productLanguage: ""
      project: ""
      shardCount: null
    status:
      status: OK
      statusCode: 200
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63

    在k8s上创建资源的过程

    用户创建一个资源,实际上是把k8s抽象的资源根据资源清单(yaml文件)做实例化。具体过程如下:

    (1)用户的资源请求发送给apiserver,通过apiserver的认证、授权、准入控制以后,通过apiserver把对应的资源定义信息存放在etcd中;

    (2)对应资源类型的控制器一般被称为 controller或operator,===controller通过watch机制监听apiserver上的资源变动,通过对应资源变动事件触发对应类型资源的控制器从etcd中读取对应资源的定义,并将对应资源创建出来,并通过控制器内部的和解循环(control loop)监控着对应资源状态是否和用户定义的期望状态一样;===如果发现不一样,内部和解循环就会被触发,对应的控制器会向apiserver发起创建资源的请求,将对应资源重建,让对应资源的状态始终满足用户期望的状态。

    对于etcd来说,它是就一个kv数据库,可以存储任意类型的kv数据,但在k8s上,apiserver将不同类型的资源定义抽象成不同的资源,使得用户创建对应资源必须是满足对应类型资源定义的规范,然后将资源定义存放在etcd中。简单讲就是存入etcd中的数据必须是满足对应apiserver接口定义的规范。

    k8s扩展资源类型的方式

    在k8s上扩展资源类型的方式有三种:

    • 第一种是CRD,crd是k8s内置的资源类型,通过crd资源可以将用户自定义资源类型转换为k8s上资源类型;
    • 第二种是自定义apiserver,这种方式是复用 Kubernetes 的一些特性的同时,自由度最高的方式。可以自定义存储等,同时保有一定程度的公共特性。Cloud TiDB 的实现就是通过自定义 API server 进行的;
    • 第三种方式就是修改现有k8s apiserver的源码,让其支持对应用户自定义资源类型;

    另外,进行自定义资源类型,只能把对应资源类型的定义信息写入到etcd中,不能让对应自定义类型资源实例化为一个自定义资源对象,它不能真正的跑起来,要想真正的跑起来,我们还需要一个自定义控制器,将对应资源实例化为k8s上的资源对象,并专门负责监听对应的资源类型的资源变化。

    因此需要(1)自定义资源类型CRD;+(2)对应自定义资源类型的控制器controller;

    controller的作用是通过API Server提供的接口实时的对指定的resource进行监听和执行的动作(watch,diff,action)。

    备注:
    k8s api = k8s资源 = pod、service、PV等

    5种控制器类型:Deployment;StatefulSet;DaemonSet;Job;CronJob

    crd和operator的区别:

    所有的Operator都是基于Controller模式,Operator是使用CRD实现的定制化的Controller. 它与内置K8S Controller遵循同样的运行模式(比如 watch, diff, action);

    operator的逻辑也是创建一个crd资源,再创建一个控制器。

    即Kubernetes CRD Operator = kubernetes CRD+ custom controller

    开发自己的k8s的controller的好处是什么?

    现在一般部署k8s上自家的代码,几乎都是stateless,也就是说,对应的pod崩了之后,在重启一个就行,吞吐上不来的时候,横向增加pod数量就行。但是如果代码的逻辑需要维护一个状态(比如当前消息读取的offset),怎么办?pod崩了之后,如何恢复状态?可以上wal,上zookeeper,甚至k8s自身的etcd,如何自动化这部分“恢复的逻辑”?就是controller可以做的事儿,其实你用ansible等脚本也可以做,只是operator给你提供了一个开发友好的方式。你可以测试,部署,发布,一切都用go写,而不是在脚本里挣扎。还有就是用go自己写如何扩展伸缩。

    这个Controller可以运行在k8s集群里,也可以是另外一个地方,本质就是一个使用了k8s客户端的小程序。

    这里的开发逻辑是基于pull,而不是push,也就是说k8s的api server不会主动的发送事件给controller,而是k8s的go的client不断地‘拉’消息来获取最新的集群状态。这个‘拉’的方式的效率低,需要不断地get状态,这个肯定被考虑了,go的client内置就有一个队列来缓存事件消息,controller的逻辑就只需从队列中取消息处理即可。

    k8s设计模式

    https://zhuanlan.zhihu.com/p/94233354

    k8s Prometheus Operator 架构:

    Prometheus Operator 的目标是尽可能简化在 Kubernetes 中部署和维护 Prometheus 的工作。其架构如下图所示:

    在这里插入图片描述

    1)、Operator:
    Operator 即 Prometheus Operator,在 Kubernetes 中以 Deployment 运行。其职责是部署和管理 Prometheus Server,根据 ServiceMonitor 动态更新 Prometheus Server 的监控对象,这里的ServiceMonitor资源对象就是指一个需要监控的目标对象在Prometheus中的配置信息。operator会根据Kubernetes标签查询自动生成监控目标配置;不需要学习普罗米修斯特有的配置语言。(operator就是一个将应用的操作性知识以软件的形式表现出来,通过基于K8s的Resources 和 Controllers来创建、配置、管理有状态的pod,使有状态的应用在k8s中得到简化的运用)

    2)、Prometheus Server:
    Prometheus Server 会作为 Kubernetes 应用部署到集群中。为了更好地在 Kubernetes 中管理 Prometheus,CoreOS 的开发人员专门定义了一个命名为 Prometheus 类型的 Kubernetes 定制化资源。我们可以把 Prometheus 看作是一种特殊的 Deployment,它的用途就是专门部署 Prometheus Server。Prometheus的配置是通过yaml文件中serviceMonitorSelector标签来选择ServiceMonitor资源对象来自动创建配置,其告警规则文件是通过一个独立的prometheus-rules.yaml文件来创建一个“PrometheusRule”自定义的资源对象。

    3)、Service:
    这里的 Service 就是 Cluster 中的 Service 资源,也是 Prometheus 要监控的对象,在 Prometheus中叫做 Target。每个监控对象都有一个对应的 Service。比如要监控 Kubernetes Scheduler,就得有一个与 Scheduler 对应的 Service。当然,Kubernetes 集群默认是没有这个 Service 的,Prometheus Operator 会负责创建。

    4)、ServiceMonitor:
    Operator 能够动态更新 Prometheus 的 Target 列表,ServiceMonitor 就是 Target 的抽象。比如想监控 Kubernetes Scheduler,用户可以创建一个与 Scheduler Service 相对应的 ServiceMonitor对象。Operator 则会发现这个新的 ServiceMonitor,并将 Scheduler 的 Target 添加到 Prometheus 的监控列表中。ServiceMonitor 也是 Prometheus Operator 专门开发的一种 Kubernetes 定制化资源类型。

    5)、Alertmanager:
    除了 Prometheus 和 ServiceMonitor,Alertmanager 是 Operator 开发的第三种 Kubernetes 定制化资源。我们可以把 Alertmanager 看作是一种特殊的 Deployment,它的用途就是专门部署 Alertmanager 组件。。

    https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/

  • 相关阅读:
    二叉搜素树(BSTree)详解—— C++ 数据结构
    MySql的InnoDB的三层B+树可以存储两千万左右条数据的计算逻辑
    golang gin ShouldBindHeader绑定请求头数据:`header:“Referer“ binding:“required“`
    antv g6实现系统拓扑图
    API实战教程:使用身份证OCR识别API构建一个应用
    ROC和AUC
    深度学习·理论篇(2023版)·第004篇深度学习和概率论基础01:使用大白话举例说明条件概率独立概率+期望值方差+协方差+熵和平均编码长度的关系
    3、LeetCode之无重复字符的最长子串
    logos_HSST简要说明
    Windows安装WinDbg调试工具
  • 原文地址:https://blog.csdn.net/weixin_43746433/article/details/126796272