k8s声明式API介绍

声明式API

所谓“声明式”,指的就是我只需要提交一个定义好的 API 对象来“声明”,我所期望的状态是什么样子

“声明式 API”允许有多个 API 写端,以 PATCH 的方式对 API 对象进行修改,而无需关心本地原始 YAML 文件的内容

Kubernetes 项目才可以基于对 API 对象的增、删、改、查,在完全无需外界干预的情况下,完成对“实际状态”和“期望状态”的调谐(Reconcile)过程

声明式 API,才是 Kubernetes 项目编排能力“赖以生存”的核心所在

AdmissionControl机制

在K8S中 当一个Pod或者任何一个API对象提交给APIServer之后 总需要做一些
     初始化的工作 比如在自动为Pod添加上某些标签
     这些功能的实现依赖于一组Admission Controller来实现 可以选择性的编译到
     APIServer中 在API对象创建之后会被立即调用
     需要重新编译自己的APIServer添加自己的规则 比较麻烦

热插拔Admission机制(Dynamic Admission)

Istio实现机制
        编写一个用来为所有Pod自动注入自己定义的容器的Initializer
        这个Initializer的定义会以ConfigMap的方式进行保存在集群中
        在Initializer更新用户的Pod对象的时候,必须使用PATCH API来完成
        Istio将一个编写好Initializer做为一个Pod运行在k8s集群中
        在Pod YAML文件提交给K8S之后 在创建好的Pod的API对象上自动添加Envoy容器配置

Initializer初始化器介绍

Initializer可以是以一个Pod的形式运行在集群当中
      Initializer就是初始化器的意思       就是在任何一个API对象刚刚创建成功后马上调用初始化器给这个对象添加一些自定义的属性

Initializer 要做的工作,就是把这部分单独定义相关的字段,自动添加到用户提交的Pod的API对象里.可是,用户提交的 Pod 里本来就有containers字段和volumes字段

所以Kubernetes 在处理这样的更新请求时,就必须使用类似于git merge 这样的操作,才能将这两部分内容合并在一起 最后按照合并后的结果创建容器和挂载卷等
      Initializer在更新用户pod对象的时候 必须使用PATCH API来完成    而PATCH API正是声明式API的最主要的能力
      k8s能够对API对象进行在线更新的能力

Initializer逻辑流程
       1.首先从ConfigMap中拿到相关数据创建一个空的Pod对象
       2.使用新旧两个Pod对象做为参数调用k8s中TwoWayMergePatch返回patch数据
       3.通过client发起PATCH请求更新原来的pod对象

一个用户提交的 Pod 对象里,就会被自动加上 Envoy 容器相关的字段    使用 Kubernetes 的 Initializer 特性,完成 Envoy 容器“自动注入”的原理

声明式API设计

API对象在Etcd里的完整路径由Group/Version/Resource组成      同一种API对象可以有多个Version k8s进行API版本化的重要手段

1.首先匹配API对象的组

Pod  Node等核心API对象是不需要Group的 它们的Group是"" 直接从/api开始查找

2.根据完整路径找到k8s的类型定义后使用用户提交的YAML文件中的字段创建一个实例

在创建实例的过程中会进行一个Convert操作   把用户提交的YAML文件转成一个super version对象

它是API资源类型所有版本的字段全集    方便用户提交不同API版本的YAML

3.进行API对象的Initializer操作和Validation操作

validation操作验证对象中各个字段的合法性  验证后保存到Registry数据结构中  一个API对象的定义能在Registry里能查到 那么它就是一个有效的k8s API对象

4.把super version对象转换成用户提交版本的对象  序列化后保存到etcd中

自定义API资源类型(CRD)

成功创建CRD之后 只是完成声明式API的一半工作
     因为还没有为这个CRD创建控制器 所以在k8s中只能对这个CRD进行增删改查操作
     但无法对CRD对象发生增删改的操作时触发对应的业务逻辑    必须为每个CRD创建一个对应的CRD控制器来实现当CRD对象发生变化时候触发控制器里面的业务逻辑代码

“registry”的作用就是注册一个类型(Type)给 APIServer.其中Network(CRD)资源类型在服务器端的注册的工作APIServer 会自动帮我们完成

但与之对应的,我们还需要让客户端也能“知道”Network 资源类型的定义.这就需要我们在项目里添加一个 register.go 文件(v1/register.go)

自定义控制器

1.编写main函数
    2.编写自定义控制器定义
    3.编写控制器的业务逻辑

Informer机制

Reflector使用ListAndWatch方法来获取并监听对象实例的变化 一旦任何一个实例有任何变化Reflector都会收到事件通知
      收到通知后把(事件和对象)的组合存入一个先进先出的队列中

Informer不断从队列中读取对象 判断事件的类型 然后创建或者更新本地对象的缓存 同步本地缓存的工作 是Informer的重要职责

Informer的第二个职责 就是根据事件的类型 触发事先注册好的ResourceEventHandler

通过监听到的事件变化,Informer 就可以实时地更新本地缓存,并且调用这些事件对应的EventHandler了
      每经过 resyncPeriod 指定的时间,Informer 维护的本地缓存,都会使用最近一次 LIST 返回的结果强制更新一次,从而保证缓存的有效性

所谓的 Informer,就是一个自带缓存和索引机制,可以触发 Handler 的客户端库。
      这个本地缓存在 Kubernetes 中一般被称为 Store,索引一般被称为 Index.Informer 使用了 Reflector 包,它是一个可以通过 ListAndWatch 机制获取并监视 API 对象变化的客 户端封装.Reflector 和 Informer 之间,用到了一个“增量先进先出队列”进行协同.

而 Informer与你要编写的控制循环之间,则使用了一个工作队列来进行协同.在实际应用中,除了控制循环之外的所有代码,实际上都是 Kubernetes 为你自动生成的

控制循环的逻辑
     1.等待Informer完成一次本地缓存的数据同步操作
     2.通过goroutine启动一个或多个无限循环任务
     3.在每一个循环周期中 执行的就是用户真正关心的业务逻辑代码
        1.如果控制循环在Informer缓存中获取不到相应的对象的信息 说明要执行删除逻辑
        2.如果从缓存中获取到对象信息 就执行控制器模式对比期望状态和实际状态       期望状态来自于etcd 实际状态来自于集群本身

这套流程不仅可以用在自定义API资源上也完全可以用在Kubernetes原生的默认API 对象上
这就使得在这个自定义控制器里面,我可以通过对自定义API对象和默认API 对象进行协同,从而实现更加复杂的编排功能

只需要关注如何拿到“实际状态”,然后如何拿它去跟“期望状态”做对比,从而决定接下来要做的业务逻辑即可 这个就是Kubernetes API编程范式的核心思想

原文地址:https://www.cnblogs.com/yxh168/p/12230853.html

时间: 2024-10-28 15:40:17

k8s声明式API介绍的相关文章

【Kubernetes】深入解析声明式API

在Kubernetes中,一个API对象在Etcd里的完整资源路径,是由:Group(API组).Version(API版本)和Resource(API资源类型)三个部分组成的. 通过这样的结构,整个Kubernetes里的所有API对象,可以用如下的树形结构表示出来 如果现在要声明一个CronJob对象,那么YAML的开始部分会这么写 apiVersion: batch/v2alpha1 kind: CronJob ... CronJob就是这个API对象的资源类型,Batch就是它们的组,v

通过 React Hooks 声明式地使用 setInterval

本文由云+社区发表 作者:Dan Abramov 接触 React Hooks 一定时间的你,也许会碰到一个神奇的问题: setInterval 用起来没你想的简单. Ryan Florence 在他的推文里面说到: 不少朋友跟我提起,setInterval 和 hooks 一起用的时候,有种蛋蛋的忧伤. 老实说,这些朋友也不是胡扯.刚开始接触 Hooks 的时候,确实还挺让人疑惑的. 但我认为谈不上 Hooks 的毛病,而是 React 编程模型和 setInterval 之间的一种模式差异.

Spring声明式事务管理与配置介绍

转至:http://java.9sssd.com/javafw/art/1215 [摘要]本文介绍Spring声明式事务管理与配置,包括Spring声明式事务配置的五种方式.事务的传播属性(Propagation).Spring事务的隔离级别(Isolation level)等内容. 一.Spring声明式事务配置的五种方式 前段时间对Spring的事务配置做了比较深入的研究,在此之间对Spring的事务配置虽说也配置过,但是一直没有一个清楚的认识.通过这次的学习发觉Spring的事务配置只要把

Rabbitmq与spring整合之重要组件介绍——AMQP声明式配置&RabbitTemplate组件

上一节是使用rabbitAdmin的管理组件进行声明队列,交换器,绑定等操作,本节则是采用AMQP声明式配置来声明这些东西.AMQP声明主要是通过@Bean注解进行的. 配置: 1 package com.zxy.demo.config; 2 3 import org.springframework.amqp.core.Binding; 4 import org.springframework.amqp.core.BindingBuilder; 5 import org.springframew

spring笔记--事务管理之声明式事务

事务简介: 事务管理是企业级应用开发中必不可少的技术,主要用来确保数据的完整性和一致性, 事务:就是一系列动作,它们被当作一个独立的工作单元,这些动作要么全部完成,要么全部不起作用. Spring中使用事务: 作为一个受欢迎的企业应用框架,Spring在不同的事务管理API上定义了一个抽象层,而开发时不必了解底层的事务管理API,就可以使用Spring的事务管理机制. Spring既支持编程式的事务管理,也支持声明式的事务管理,大多数情况我们选择后者. 编程式事务管理:将事务管理代码嵌入到业务代

Spring笔记(四): spring的编程式事务与声明式事务

一.Spring 事务属性分析 事务管理对于企业应用而言至关重要.它保证了用户的每一次操作都是可靠的,即便出现了异常的访问情况,也不至于破坏后台数据的完整性.就像银行的自助取款机,通常都能正常为客户服务,但是也难免遇到操作过程中机器突然出故障的情况,此时,事务就必须确保出故障前对账户的操作不生效,就像用户刚才完全没有使用过取款机一样,以保证用户和银行的利益都不受损失. 在 Spring 中,事务是通过 TransactionDefinition 接口来定义的.该接口包含与事务属性有关的方法.在

全面分析 Spring 的编程式事务管理及声明式事务管理--转

开始之前 关于本教程 本教程将深入讲解 Spring 简单而强大的事务管理功能,包括编程式事务和声明式事务.通过对本教程的学习,您将能够理解 Spring 事务管理的本质,并灵活运用之. 先决条件 本教程假定您已经掌握了 Java 基础知识,并对 Spring 有一定了解.您还需要具备基本的事务管理的知识,比如:事务的定义,隔离级别的概念,等等.本文将直接使用这些概念而不做详细解释.另外,您最好掌握数据库的基础知识,虽然这不是必须. 系统需求 要试验这份教程中的工具和示例,硬件配置需求为:至少带

spring事务管理——编程式事务、声明式事务

本教程将深入讲解 Spring 简单而强大的事务管理功能,包括编程式事务和声明式事务.通过对本教程的学习,您将能够理解 Spring 事务管理的本质,并灵活运用之. 先决条件 本教程假定您已经掌握了 Java 基础知识,并对 Spring 有一定了解.您还需要具备基本的事务管理的知识,比如:事务的定义,隔离级别的概念,等等.本文将直接使用这些概念而不做详细解释.另外,您最好掌握数据库的基础知识,虽然这不是必须. 系统需求 要试验这份教程中的工具和示例,硬件配置需求为:至少带有 512MB 内存(

Spring Cloud 声明式服务调用 Feign

一.简介 在上一篇中,我们介绍注册中心Eureka,但是没有服务注册和服务调用,服务注册和服务调用本来应该在上一章就应该给出例子的,但是我觉得还是和Feign一起讲比较好,因为在实际项目中,都是使用声明式调用服务.而不会在客服端和服务端存储2份相同的model和api定义.Feign在RestTemplate的基础上对其封装,由它来帮助我们定义和实现依赖服务接口的定义.Spring Cloud Feign 基于Netflix Feign 实现的,整理Spring Cloud Ribbon 与 S