资讯详情

1.2kubernetes模型设计_kubernetes生产化实践之路

1.2.1.对象的一般设计原则

kubernetes遵循以下原则:

1.2.2、模型设计

1.2.2.1、TypeMeta

TypeMeta 是kubernetes 引入对象最基本的定义GKV(group、Kinx、Version)模型定义了一个对象的类型。

1、Group 根据其功能将对象分成不同的分组,例如将智齿最基本功能的对象分成 core 组将与应用部署相关的对象纳入组 apps 组。 使这些对象更具可维护性和可理解性。

2、Kind 定义对象的基本类型,例如Node、Pod、Deployment

3、Version

随着对象的成熟,版本将从 v1alpha1 到 v1alpha2,或者到v1beta1.最终成为生产就绪版v1 。

kubernetes 通过Version 当不同版本的对象定义发生变化时,可能会涉及数据迁移,kubernetes API Server 允许通过Conversion 方法转换不同版本的对象属性。

这是一种自动数据迁移机制。当集群版本升级时,已创建的旧版本对象将自动转换为新版本。

这里的版本是外版(External Version),即用户通过API 版本可见。 事实上,资源的定义是内版的(Internal Version),在 Kubernetes API Server 先将外版转换为内版,再持久化。

1.2.2.2、Metadata

TypeMeta 定义我是什么,Metadata定义了“我是谁”

Metadata 有两个重要属性 Namespace和Name,对象的定义定义Namespace归属和名称,这两个属性唯一定义了对象的实例。

Typemeta、Namespace、Name 唯一确定对象所在地的对象API 自动生成并保存访问路径的对象 Metadata 属性的 selfLink 中

在这里插入图片描述

Metadata 中还有 Label、Annotation、Finalizer、ResourceVersion 可作为资源对象配置管理的四个字段。

在传统的面向对象设计中,对象组合通常是嵌入或引用的。对象可能是一对多的关系。如果一个对象发生变化,系统需要通过所有相关对象进行修改。

kubernetes 采用松耦合关系管理对象。Label和Selector。 Label 就是给对象贴标签,一个对象可以有任意的标签,存在的形式是键值对。不需要独特,可以重复,一个对象也可以有多个标签。

Label 定义了这些对象的可识别属性,Kubernetes API 支持以Label 作为过滤条件查询对象。Label 通常以最简单的形式定义:

只需要定义其他对象 Label Selector 需要关联的对象可以根据条件查询。 Label 查询可以基于等式,如app=web或者app!=db,或基于集合 app in (web,db)。 可以只查询Label 键,如app。 只支持和操作多种条件,如app=web,tier=front。

Annotation 在开发新功能时,保存一些信息作为属性扩展。 也是键值定义,功能相同Label 不一样,API 不支持只用 Annotation 过滤条件。

比如为POD 标记 Annotation 以告知Prometheus 抓取系统指标

只看社区实现没有存在感,是实际落地过程中非常重要的属性。 因为kubernetes 不是独立存在的系统最终会与企业资源和系统集成,这意味着kubernetes将操作外部系统。

例如,一个场景: 创建了一个kubernetes 对象,假设相应的控制器需要从外部系统获取资源,当用户删除对象时,控制器将尝试在接收到删除事件后释放资源。但外部系统无法连接,控制器重启,后果是什么? 答案是对象总是泄露的。

Finalizer 本质是资源锁。 kubernetes 在接收对象的删除请求时,将进行检查Finalizer 是否空,如果空,只删除逻辑,即只更新对象中的metadata.deletionTimestamp 字段。 具有 Finalizer 对象不会立即删除,需要等到Finalizer 删除列表中的所有字段后,只有与对象相关的所有外部资源都被删除,对象才会最终被删除。

当对象的时候,控制器需要监控对象的更新时间 deletionTimestamp 当不是空的时候,处理对象删除逻辑,回收外部资源,以及他们以前添加的情况Finalizer。

当多线程操作相同的资源时,为了确保数据的一致性,需要在访问对象时锁定,以确保只有一个线程同时修改对象,其他线程只能等待锁定,从而降低系统的效率。

ResourceVersion 可视为乐观锁。 每个对象在任何时候都有它ResourceVersion,当kubernetes客户端读取对象后,ResourceVersion 同时阅读信息。 客户端更改对象并重写API Server时,ResourceVersion 同时增加API Server 需要确保回写版本高于服务端当前版本,服务端版本将在回写成功后更新为新版本ResourceVersion。

在kubernetes当对象同时修改时,会在回写时进行判断ResourceVersion 是否高于当前版本,如果不高于,则回写失败,需要阅读新版本信息。

该机制保证了分布式系统中的任何多线程都能无锁并发送访问对象,大大提高了系统的分类效率。

1.2.2.3 Spec 和 Status

spec和status 是对象的核心。

spec 是用户端定义的期望的对象状态 status 控制器收集并更新对象的实际状态。

所以kubectl get 出来的deployment,比手写的yaml多了status 那段信息。 对照文末的yaml信息阅读。

与TypeMeta 和 Metadata 等一般属性不同,spec和status 是每个对象独有的。

鼓励API 对象应尽可能满足对象设计的要求,即高内聚、松耦合,以提高分解业务对象的可重用性。

高层API 对象设计必须从业务触发,低层API 对象可以是高层API 使用对象,减少冗余,提高重用性。

1.2.3.核心对象概述

kubernetes不同的资源对象是独立的API对象定义它们。 维护方便。

不同对象被划分到不同的Namespace后,可以通过权限来限制用户以何种权限访问哪些Namespace的哪些对象,进而构建一个多租户、彼此隔离的通用集群。

Pod 是kubernetes 应用程序的基本执行单元,即它是kubernetes 对象模型中创建和部署的最小和最简单的单元。

POD 是一个或者多个容器镜像的组合,同一个pod中的所有容器中的进程默认公用同一个网络Namespace,并且共用同一网络标识。

应用运行在Pod中,还需要的配置文件,需要明文读写或者权限控制加密等。

configmap和secret 没有本质区别,与persistVolumeClaim 类似,都可以作为卷加载给运行的Pod,Pod中的进程可以像访问本地文件一样访问它们。

secret 只是将内容进行base64 编码(对称加密算法),可以轻松解密。

pod 中运行的进程有时需要与 kubernetes api 通信,在启用了安全配置的集群里,pod 一定要以某种身份与 kubernetes 通信,这个身份就是 系统账户(serviceAccount)。

kubernetes 会默认为每个Namespace 创建一个 default ServiceAccount ,并且为每个ServiceAccount 生成一个 JWT Token ,这个Token 保存在Secret 中,用户可以在其Pod 定义中 指定 ServiceAccount (默认为default),其 对应的Token 会被挂载在pod中,pod中的进程可以通过该token 与 kubernetes 进行通信。

pod 只是单个应用实例的抽象,要构建高可用应用,同一个服务需要多个副本。 kubernetes 为此抽象出副本集 ReplicaSet ,其允许用户定义POD的副本数,每个pod都会当作一个无状态的成员进行管理,kubernetes 保证总是有用户期望的数量pod正常运行。 当某个副本宕机以后,控制器将会创建一个新的副本,也可以方便扩容和缩容副本数量。

Deployment 是一个用来描述发布过程的对象。 当发布新版本时,Deployment 会同时操作两个版本的ReplicaSet,其内置多种滚动升级策略,按照既定策略降低老版本的pod数量,同时创建新版本的pod,总是保证正在运行的pod总数与用户期望的副本数一致。(销毁的数量不会大于新生成的数量) 并依次将该Deployment 中的所有副本都更新至新版本

由于Deployment 会维护 ReplicaSet,ReplicaSet 会创建pod,所以使用Deployment 维护无状态的应用是第一选择。 Deployment 比pod的好处:

  • 维护一定数量的pod运行,有pod 失败时会再拉起。
  • 按照既定策略滚动升级,是自己暂停,恢复和回滚。
  • 扩容和缩容很方便

service 和 Ingress 是描述负载均衡配置的对象。 允许用户定义服务的协议和端口,定义Selector 选择后端服务的pod。 Selector 本身是一个Label 过滤器,它会选择所有Label 与该Selector 匹配的pod 作为目标。

kubernetes 为service 和选择出来的pod 创建一个关联对象,endpoint 里面记录了所有pod的ip地址和就绪状态,这些信息会被相应组件作为期望状态进行负载均衡配置。

Ingress 在服务的基础上定义API 网关的对象,通过Ingress 用户可以定义七层转发规则、网关证书等高级路由功能。

PersistentVolume(PV) 是集群中的一块存储卷,可以手动创建 或者 用户创建 PersistentVolumeClaim (PVC)时根据StorageClass 动态设置。

PV PVC 与POD 生命周期无关,pod的变动不会影响pvc中的数据。

不同场景需要不同属性的pvc,比如性能、访问模式,类型由StorageClass 区分(具体的pvc是使用本地磁盘还是nfs、还是别的分布式存储)。集群有默认的StorageClass。

CustomResourceDefinition :自定义资源定义,即 CRD。允许用户将自己定义的对象添加到 kubernetes 集群中。

创建新的CRD定义时,API Server将为指定的每个版本创建一个新的 RESTFul 资源路径; 当成功创建了CRD时,就可以像原生资源一样使用它,利用k8s 的所有功能,api、rbac等。

CRD的定义是集群范围的。 资源对应的作用域,可以是Namespace 或者 集群。

删除 Namespace 也会删除所有的对象,但是不会删除CRD的定义。

k8s提供了codegen工具(deepcopy-gen、client-gen、lister-gen、informer-gen),能够自动生成该CRD 资源的golang版本的 Clientset、Lister、Informer。

CRD 就像是数据库的开放式表结构,这样可以满足更多种不同的业务需求。 Istio、Knative 就是基于CRD 构建的。

1.2.4、控制器模式

控制器模式,就是声明式系统的核心,通过这种机制确保实际状态与期望状态最终保持一致。

k8s 中定义了一系列的控制器,几乎所有的k8s中的对象都被一个或者多个控制器监听,当对象发生变化时,控制器会捕捉变化并完成配置操作。

api server 是 k8s的大脑,保存了所有对象及其状态。

开源的client-go 对控制器的编写提供了完备的自动化支持,任何k8s对象 都可以由 client-go 创建供控制器使用的 Informer() 和 Lister() 接口。 控制器的工作流程就是围绕着 这两个接口的。

  • Informer():接收资源对象变化的event,针对add、update、delete事件,注册相应的 eventhandler。 在 eventhandler 内根据传入的object 调用 controller.keyfunc 计算出字符串 key,并把它加入控制器的队列中。

  • lister():给控制器提供主动查询资源对象的接口,根据lables.selector 来指定筛选条件

控制模式:生产-消费者模式

  • 生产者:控制器启动后,informer()会监听其所关注的对象变化,一旦对象发生了创建、更新、删除等事件,这些事件会由核心组件api server 推送给控制器。 控制器会将对象(期望的)保存在本地缓存中,并将对象的主键推送至消息队列,此为生产者

  • 消费者:控制器会启动多个工作子线程(worker),从队列中依次获取对象主键,并从缓存中读取完整状态,按照期望状态完成配置更改,并将最终状态回写至api server,此为消费者

k8s就是基于此模式保证了整个系统的最终一致性。k8s 运行一组控制器,以使资源当前的状态与所需状态保持匹配。

对于基于事件的体系结构,控制器利用事件去触发相应的自定义代码,这部分都是由 sharedInformer 完成的。

例如 创建Deployment 控制器的核心代码如下:

具体的:如下图,sharedInformer 有 Reflector 、Informer、Indexer、Thread safe store 四个组件

  • Reflector: 用于监听特定的k8s api 资源对象,可以是内部的或者自定义的资源。 具体实现是通过 listandwatch 的方法进行的。 首先 reflector 将资源版本号设置为0,使用 list 操作获得指定资源对象,可能会导致本地的缓存相对于etcd里面的内容存在延迟。然后 reflector 通过watch操作监听大 api server 处资源对象的版本号变化,并将最新的数据放入 delta FIFO 队列中,使得本地的缓存数据与etcd的数据保持一致。如果resyncPeriod 不为零,那么reflector 会以resyncPeriod 为周期定期执行 delta FIFO 的Resync 函数,这样可以使Informer 定义处理所有的对象。

  • Informer:内部机制是从Delta FIFO 队列中弹出对象,将对象存入本地存储以供检索,另一方面触发时间以调用资源事件回调函数,控制器后续的典型模式是获取资源对象的key,并将该key 排入工作队列以进一步处理。Indexer 提供对象的索引功能。

  • Indexer 根据多个索引函数维护索引。Indexer使用线程安全的数据存储来存储对象及其键。在store 中定义了一个名为MetaNamespaceKeyFunc的默认函数,该函数生成对象的键的格式是 / 的组合。

1.2.5、控制器的协同工作原理

单个k8s资源对象的变更,会触发多个控制器对该资源对象的变更进行响应,继而还能引发其相关的其他对象发生变更,从而触发其他对象控制器的配置逻辑。

除了 api server和etcd外,所有的组件,scheduler、controller manager、kubelet本质都是一致的,都可以被称为调度器。

这些组件中都有一个控制循环,它们监听 api server 中的对象变更,在自己关注的对象发生变更后完成既定的控制逻辑,再将控制逻辑执行完成后的结果更新回api server,并持久化到etcd中。

api server 作为集群的api 网关,接收所有来自用户的请求。

1、 用户创建deployment之后,该请求被发送至api server,经过认证,鉴权和准入三个环境,该deployment 对象被保存到etcd中。

2、controller manager 中的deployment controller 监听api server 中所有deployment的变更事件,此时其捕获了deployment 的创建事件,并开始执行控制逻辑。 deployment controller 读取deployment 对象的Selector 定义,通过该属性过滤当前Namespace 中的所有ReplicaSet 对象,并判断是否有 ReplicaSet 对象的OwnerReference 属性为此Deployment。 由于此deployment 刚刚创建,没有满足此查询条件的ReplicaSet。 于是Deployment Controller 会读取Deployment 中定义的podTemplate,将其做哈希计算,得到值为 [pod-template-hash] ,并依据如下约定创建新的ReplicaSet。

  • 新的ReplicaSet 的命名格式为 [deployment-name]-[pod-template-hash]
  • 为ReplicaSet 添加label,此label为pod-template-hash:[pod-template-hash]
  • 将deployment的值赋给 ReplicaSet 的 OwnerReference

Deployment Controller 将新的ReplicaSet 创建请求发送至api server,api server 经过认证授权和准入步骤,将该对象保存至etcd。

ReplicaSet Controller 监听api server中所有ReplicaSet 对象的变更,新对象的创建令其唤醒,并开始执行控制逻辑。 ReplicaSet Controller 读取ReplicaSet 对象的Selector 定义,并通过该属性过滤当前Namespace中的所有的pod,并判断是否pod的OwnerReference 为该ReplicaSet。 由于此ReplicaSet 刚刚创建,所以没有满足此查询条件的pod,于是ReplicaSet 会按照如下约定创建pod:

  • 读取ReplicaSet 定义,Replicas 的数量代表需要创建的pod的数量
  • 以ReplicaSet名作为 pod 的GenerateName ,该属性会被当作pod名单 前缀,k8s在此基础上加上一个随机字符串作为pod名。
  • 该ReplicaSet 可以作为pod的OwnerReference使用

ReplicaSet Controller将新建pod的请求发送给api server,api server将pod对象的信息保存到etcd中。 此时调度器被唤醒,其监听 api server 中所有nodeName 为空的pod,即未经过调度的pod。

经过一系列的调度算法,不满足pod需求的节点被过滤。 满足pod需求的节点按照空闲资源,端口占用情况,实际资源利用率等信息被排序,评分最高的节点名被更新到 nodename属性中有,该属性经api server 保存至etcd。

当被选中的node节点上的kubelet 监听到有归属自己节点的新pod时,就开始加载pod清单,下载pod所需的配置信息。 调用容器运行时接口启动容器,调用容器网络接口加载网络,调用容器存储接口挂载存储,并完成pod的启动。

k8s 就是依靠这种联动机制,通过分散的业务控制逻辑满足用户的需求。

用户只是发送了一个创建deployment的请求,k8s 里涉及了多个组件。 优势:各个组件各司其职,巧妙灵活,代码易于维护,解耦 缺点:运维复杂度高,业务流中任何组件故障都会使得k8s不可用。

不能简单的抄写文字。没有意义。

[root@jyzx-tower1 ~]# kubectl get deployments ummp-activity-deployment -n cmsc -o yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  annotations:
    deployment.kubernetes.io/revision: "945"
    field.cattle.io/publicEndpoints: '[{"addresses":["10.71.164.29"],"port":31597,"protocol":"TCP","serviceName":"cmsc:ummp-activity-service","allNodes":true},{"addresses":["10.71.164.29"],"port":31208,"protocol":"TCP","serviceName":"cmsc:ummp-activity-service","allNodes":true},{"addresses":["10.71.164.29"],"port":31628,"protocol":"TCP","serviceName":"cmsc:java-debug-ummp-activity-service","allNodes":true}]'
    kubectl.kubernetes.io/last-applied-configuration: |
      { 
        "apiVersion":"apps/v1","kind":"Deployment","metadata":{ 
        "annotations":{ 
        },"labels":{ 
        "cmsc":"ummp-activity-deployment"},"name":"ummp-activity-deployment","namespace":"cmsc"},"spec":{ 
        "replicas":1,"selector":{ 
        "matchLabels":{ 
        "cmsc":"ummp-activity-deployment"}},"strategy":{ 
        "type":"Recreate"},"template":{ 
        "metadata":{ 
        "labels":{ 
        "cmsc":"ummp-activity-deployment"}},"spec":{ 
        "containers":[{ 
        "env":[{ 
        "name":"JAVA_OPTS","value":"-server -agentlib:jdwp=transport=dt_socket,address=8000,server=y,suspend=n -Dproject.name=ummp-activity -Dcsp.sentinel.config.file=classpath:sentinel-dev.properties"},{ 
        "name":"APP_PROPS","value":"--spring.profiles.active=dev"},{ 
        "name":"UPDATE-UUID","value":"38102"}],"image":"10.71.164.28:5000/com-cmcc-coc-ummp-activity-parent:1.0.66-SNAPSHOT","imagePullPolicy":"Always","name":"ummp-activity-deployment","ports":[{ 
        "containerPort":8080,"protocol":"TCP"}],"volumeMounts":[{ 
        "mountPath":"/root/ummp-activity","name":"nfs-logs"}]}],"volumes":[{ 
        "name":"nfs-logs","nfs":{ 
        "path":"/var/nfs/k8s_storage/ummp-activity","server":"10.71.164.28"}}]}}}}
  creationTimestamp: "2019-10-18T02:39:44Z"
  generation: 958
  labels:
    cmsc: ummp-activity-deployment
  name: ummp-activity-deployment
  namespace: cmsc
  resourceVersion: "159989560"
  selfLink: /apis/extensions/v1beta1/namespaces/cmsc/deployments/ummp-activity-deployment
  uid: 8b49322d-f150-11e9-ae22-c8d9d2254422
spec:
  progressDeadlineSeconds: 600
  replicas: 1
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      cmsc: ummp-activity-deployment
  strategy:
    type: Recreate
  template:
    metadata:
      creationTimestamp: null
      labels:
        cmsc: ummp-activity-deployment
    spec:
      containers:
      - env:
        - name: JAVA_OPTS
          value: -server -agentlib:jdwp=transport=dt_socket,address=8000,server=y,suspend=n
            -Dproject.name=ummp-activity -Dcsp.sentinel.config.file=classpath:sentinel-dev.properties
        - name: APP_PROPS
          value: --spring.profiles.active=dev
        - name: UPDATE-UUID
          value: "38102"
        image: 10.71.164.28:5000/com-cmcc-coc-ummp-activity-parent:1.0.66-SNAPSHOT
        imagePullPolicy: Always
        name: ummp-activity-deployment
        ports:
        - containerPort: 8080
          protocol: TCP
        resources: { 
        }
        terminationMessagePath: /dev/termination-log
        terminationMessagePolicy: File
        volumeMounts:
        - mountPath: /root/ummp-activity
          name: nfs-logs
      dnsPolicy: ClusterFirst
      restartPolicy: Always
      schedulerName: default-scheduler
      securityContext: { 
        }
      terminationGracePeriodSeconds: 30
      volumes:
      - name: nfs-logs
        nfs:
          path: /var/nfs/k8s_storage/ummp-activity
          server: 10.71.164.28
status:
  availableReplicas: 1
  conditions:
  - lastTransitionTime: "2019-10-18T02:50:04Z"
    lastUpdateTime: "2021-10-22T06:36:26Z"
    message: ReplicaSet "ummp-activity-deployment-767547f9d5" has successfully progressed.
    reason: NewReplicaSetAvailable
    status: "True"
    type: Progressing
  - lastTransitionTime: "2021-10-25T10:52:56Z"
    lastUpdateTime: "2021-10-25T10:52:56Z"
    message: Deployment has minimum availability.
    reason: MinimumReplicasAvailable
    status: "True"
    type: Available
  observedGeneration: 958
  readyReplicas: 1
  replicas: 1
  updatedReplicas: 1
[root@jyzx-tower1 ~]# 

标签: 二极管cmsc

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台