【K8S类型系统】一文梳理 K8S 各类型概念之间的关系(GVK/GVR/Object/Schema/RestMapper)

参考

k8s 官方文档
  • https://kubernetes.io/zh-cn/docs/reference/
  • https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/
重点
  • Kubernetes源码学习-kubernetes基础数据结构 - 知乎 重点

  • Kubernetes类型系统 | 李乾坤的博客 重点

  • k8s源码学习-三大核心数据结构_51CTO博客_c++数据结构 重点

  • Kubernetes源码分析(二)----资源Resource_kubernetes resources-CSDN博客 重点

  • 浅说Kubernetes中API的概念_kubernetes api-CSDN博客

  • Kubernetes API Server源码学习(二):OpenAPI、API Resource的装载、HTTP Server具体是怎么跑起来的?_apiserver openapi-CSDN博客 重点

  • Kubernetes API 概念 | Kubernetes

  • 3.1.3 访问kubernetes REST API · Kubernetes Documentation

  • Kubernetes源码分析(二)----资源Resource_kubernetes resources-CSDN博客

  • K8s 的核心是 API 而非容器(二):从开源项目看 k8s 的几种 API 扩展机制(2023) 重点

  • 【k8s基础篇】k8s基础2之GVK与GVR-CSDN博客

  • Kubernetes API Server源码学习(二):OpenAPI、API Resource的装载、HTTP Server具体是怎么跑起来的?_apiserver openapi-CSDN博客 重点

  • Kubernetes源码开发之旅三:API Server源码剖析_哔哩哔哩_bilibili blibli 视频教学,不错

  • Kubernetes API Server handler 注册过程分析 | 云原生社区(中国) 重点

  • 源码解析:K8s 创建 pod 时,背后发生了什么(三)(2021)

  • 一文读懂 Kubernetes APIServer 原理 - k8s-kb - 博客园

  • 【k8s基础篇】k8s基础3之接口文档_k8s接口文档-CSDN博客

  • 【k8s基础篇】k8s基础2之GVK与GVR_gvk gvr-CSDN博客

次要
  • REST: Part 1 - HTTP API 设计思路 - ZengXu’s BLOG
  • kubernetes官方案例sample-controller详解
  • Kubernetes API Server handler 注册过程分析 | 云原生社区(中国)
  • 面向API server CRUD的探索
  • K8S中为什么需要Unstructured对象
  • Kubernetes编程——client-go基础—— 深入 API Machinery —— Golang 类型转换为 GVK、GVR 和 HTTP 路径,API Machinery概览 - 左扬 - 博客园
  • Kubernetes CRD 系列:Api Server 和 GVK®
  • Kubernetes CRD 系列:Client-Go 的使用
  • kubernetes二次开发系列(1):client-go
  • Kubernetes源码 - 随笔分类 - 人艰不拆_zmc - 博客园
  • k8s中的所有api-resources类型简介 - 知乎
  • Kubernetes的Group、Version、Resource学习小记 - 掘金
  • sample-apiserver分析 - 简书
  • kube-apiserver代码分析 - API多版本初探 - 刘达的博客
  • 理解 Kubernetes 对象 | Kubernetes学习笔记
  • Kubernetes 中的资源对象 · Kubernetes 中文指南——云原生应用架构实战手册
  • 从 Kubernetes 中的对象谈起 - 面向信仰编程
  • 理解Kubernetes的RBAC鉴权模式-腾讯云开发者社区-腾讯云
  • Kubectl exec 的工作原理解读 - 米开朗基杨 - 博客园
  • Kubernetes RESTMapper源码分析 - 人艰不拆_zmc - 博客园

理解 Restful API(简单了解一下)

  • 理解RESTful架构 - 阮一峰的网络日志

  • 怎样用通俗的语言解释REST,以及RESTful? - 知乎

  • 什么是REST风格? 什么是RESTFUL?(一篇全读懂)_rest风格和restful风格区别-CSDN博客

REST之所以晦涩难懂,是因为前面主语(Resource )被去掉了。
全称是: Resource Representational State Transfer。
指的是客户端通过操作资源的表现形式(Representation)来实现状态(State)的转移。这个概念强调了在 RESTful 架构中,客户端通过与资源的交互来实现应用程序状态的转移,而不需要服务器端保持客户端的状态信息

分解开来讲解:
Resource:资源,在 REST 中指的是网络中的任何实体,可以是一个文档、一张图片、一个视频、一个人员、一个部门等等。每个资源都有一个唯一的标识符(URI或URL, 通常是 URL,这两个可以认为是一个东西,URL 是 URI 的子集)用于标识和定位。;
Representational:资源的呈现形式,通常是通过某种媒体类型(如 JSON、XML、HTML 等)来表示资源的数据。客户端通过获取资源的表现形式,并在需要时对其进行操作,来实现状态的转移;
State Transfer:状态变化。指的是客户端通过与资源的交互,改变了资源的状态。这种状态转移通常通过标准的 HTTP 方法(如 GET、POST、PUT、DELETE 等)来实现,每个 HTTP 方法都对应了一种不同的状态转移操作。

Rest 是一种架构风格,就是一种设计思想,其落地的方案需要依托底层传输协议,一般采用 HTTP 协议,其形成的 API 也就叫做 Restful API(称之为 Rest 风格 API)

简单总结(说人话):

  • 通过操作资源的表现形式来实现状态的转移

    • 向 URL (资源)发送请求,请求的内容(一般为 json 形式,表现形式),来获取服务端存储的对象内容或更新服务端存储的内容(状态的转移,若是 GET 请求就是获取,POST 或 PUT 就是更新或新建,DELETE 就是删除)
  • 你会想,上面描述不就是正常发起一个 http 请求嘛( 请求某个 URL,请求内容就是 Body 为 json 形式)

    • 其实这么理解没错,但是相对于以往 http 有些不同
    • REST 强调两个重要概念【资源和状态转移】,资源可以理解为 URL,状态转移可以理解依靠HTTP 方法(如 GET、POST、PUT、DELETE 等)来实现
  • 下面举例

    • # 1. 以往 API 设计
      # 获取 id=3 的文件
      POST 127.0.0.1:8080/unrestful/getFile?id=3
      # 获取所有文件
      POST 127.0.0.1:8080/unrestful/getAllFiles
      # 删除 id=3 的文件
      POST 127.0.0.1:8080/unrestful/deleteFile?id=3
      # 更新 id=3 的文件
      POST 127.0.0.1:8080/unrestful/updateFile?id=3
      
      # 2. Restful API 设计
      # 获取 id=3 的文件
      GET 127.0.0.1:8080/restful/files?id=3
      # 获取所有文件
      GET 127.0.0.1:8080/restful/files
      # 删除 id=3 的文件
      DELETE 127.0.0.1:8080/restful/files?id=3
      # 更新 id=3 的文件
      POST 127.0.0.1:8080/restful/files?id=3
      
      
      # 总结
      # 1. UnRestful API,将资源和对资源的操作耦合在一起,只采用 POST HTTP 操作,因此 URL 很复杂
      # 2. Restful API,将资源和对资源的操作解耦,用不同 HTTP 方法(GET/POST/UPDATE)来代表对资源的不同操作,URL仅代表资源,因此更加清晰易懂
      # 3. 当程序员调用 UnRestful API 时,需要记住资源的不同操作方法(getFile、getAllFiles、deleteFile、updateFile),若是新增了一个对象,如 Student,同时 API 设计不规范的话(如 getAllStudents 写为 getStudents,getFile 写成 fetchStudent),那会更增加理解、记忆、及编程难度
      # 4. 当程序员调用 Restful API 时,只需要记住 HTTP 方法(GET/POST/UPDATE)和对应的资源名称(files),若新增了 Students,那么只需要记住新增的名称 students(注意,一般在 URL 中都是小写字母)
      
  • 总结,记住这几句话

    • 看 URL 就知道要什么(资源)
    • 看 HTTP Method 就知道干什么(对资源的操作)
    • 看 HTTP Status Code 就知道结果如何(操作后的结果)
  • 看了上面内容,能理解 URL 就是资源(Resource)就可以,这个有助于理解下面 K8S 中的 Resource

理解 K8S 各资源术语及概念

总览

简称全称(或翻译)作用
Kind资源类型用于确定创建哪种资源,
并结合 Group、Version,形成 GVK 在 Schema 中寻找对应的数据结构,
从而进行资源对象的创建
Object资源对象GVK 创建的存储在 etcd 中的资源实体,称之为资源对象
ResourceAPIResource
(接口资源)
Kind 的小写字母复数形式,该结构具有多种属性字段
(如是否具有 Namespace 概念,如 Pod 具有,ClusterRole 不具有)
主要用于结合 Group、Version,形成 GVR ,从而生成资源 URI (HTTP Path、URL)
VersionAPIVersion
(接口版本)
用于管理 Resource 和 Kind 资源,相当于版本管理
Resource 和 Kind 资源可以多个 Version,如 v1aplha1、v1beta1、v1 等,
相当于版本管理,每个版本可能在上一版本新增了某些属性(字段)
GroupAPIGroup
(接口组)
用于管理 Resource 和 Kind 资源,相当于功能职责管理
应该出于这种考虑,Resource 和 Kind 有多种功能,同种或类似功能的放在一个 Group(比如认证相关放在rbac.authorization.k8s.io Group 中,网络相关放在 networking.k8s.io Group 中,部署相关放在 apps 组中等)
因此形成了如此组织结构:Group --> Version --> Kind 或 Resource
apiserver串联上面概念apiserver 可以理解为【 http Server】,那么就需要 http path --> handler 的映射关系
外部只有知道 http path (GVR)才能发起请求(如创建、更改、删除等),可以说认为此 http path 就是 Resource(可以查看上面 Restful API 介绍),之后 handler 收到请求后,进行后来处理(此处是内部逻辑 GVK),创建对应的资源对象实体(Object)进行存储
以 Pod 创建说明此过程
0. 首先 apiserver 预先注册了 http path 与 handler 的对应关系,然后对外提供服务
1. 用户提交 Pod yaml,创建 Pod,其中制定了 GVK
2. Pod yaml 相当于请求的 body 内容,提交到哪个 http path 呢?
首先通过 yaml 获取 GVK,然后通过 RestMapper 机制(k8s内部逻辑)转换为 GVR,之后将 GVR 转换为 http path
3. 之后该 http path 对应的 handler 该处理了,首先通过 GVK 查询 Schema (k8s 内部的注册表,记录了 GVK 与资源数据结构的对应关系)知道到此次创建的是 Pod Struct,而不是 Deployment,之后将 Pod yaml 中的信息填写到此 Pod Struct 字段中
4. 之后需要持久化,将该 Pod Struct 进行持久化处理,存入到 etcd 数据库中,该存储实体称之为 Object
  • kube-apiserver作为整个Kubernetes集群操作etcd的唯一入口,负责Kubernetes各资源的认证&鉴权、校验以及CRUD等操作,提供RESTful APIs,供其它组件调用:
  • 一文读懂 Kubernetes APIServer 原理 - k8s-kb - 博客园

在这里插入图片描述

  • Create 请求的流程可以总结为下图
  • Kubernetes API Server handler 注册过程分析 | 云原生社区(中国)
  • 在这里插入图片描述

对象(OBJECT) 和 资源(RESOURCE) 的区别

  • K8S - API 对象 - 潜水滴海军的blog

  • RESTful API 中的基本概念是资源,每个资源都分配有唯一标识它的 URI 或统一资源标识符(或称之为 http path 、http 端点、URL,本文中以下这几个名称表达意思相同)。

例如,在 Kubernetes API 中,应用程序部署由部署资源表示。

集群中所有部署的集合是在/api/v1/deployments. 当您使用该 GET 方法向此 URI 发送 HTTP 请求时,您会收到一个列出集群中所有部署实例的响应。

每个单独的部署实例也有自己唯一的 URI,通过它可以对其进行操作。因此,单个部署作为另一个 REST 资源公开。您可以通过向资源 URI 发送 GET 请求来检索有关部署的信息,并且可以使用PUT请求对其进行修改。

在这里插入图片描述

因此,一个对象可以通过多个资源公开。如图所示:

  • 当您查询 deployments 资源时(/apis/apps/v1/namespces/myns/deployments),命名的 Deployment 对象实例 mydeploy 作为集合元素返回
  • 当您直接查询单个资源 URI 时(/apis/apps/v1/namespces/myns/deployments/mydeploy),则作为单个对象返回。

在某些情况下,资源根本不代表任何对象。

这方面的一个例子是:

Kubernetes API 允许客户端验证主体(人或服务)是否被授权执行 API 操作的方式。这是通过向资源提交POST请求到 /apis/authorization.k8s.io/v1/subjectaccessreviews 来完成的。接口响应表明了主体是否被授权了,执行请求正文中指定的操作。这里的关键是 POST 请求没有创建任何对象。

上述例子表明,资源对象 并不是完全相同的。如果你熟悉关系型数据库,你可以把 资源对象 比作 视图资源 就是你与对象进行交互的 “视图”。

用故事理解 GVK/GVR/Object/Schema/RestMapper

现在有无数个硬盘,用户需要创建文件存储到这些硬盘中,目前由如下规则

  • 每个硬盘命名为 Group 名,
  • 用户通过 Kind 指定创建文件的种类(Kind 为了便于识别,都采用首字母大写,如 Sh、Doc、Docx、Ppt、Txt、Json 文件等,对应的文件后缀为 sh、doc、docx、ppt、txt、json等,)

现在假如有两个硬盘,

  • group1 硬盘(支持Kind 为 Sh、Doc、Txt )和 group2(支持 Kind 为 Sh、Ppt),
  • 这两个硬盘都具有 Kind 为 Sh 的种类,就是都能创建 sh 文件(不过这两个硬盘的 sh 用处不一样,因此文件权限不一样,【group1 中的 sh 文件可以执行,group2 中的 sh 文件不能执行】),
Group、Version、Kind 概念的引入

Group 表示功能职责管理,不同职责功能的 Kind 放入到不同 Group 中

Version 表示 版本管理

Kind 表示 资源的类型(创建何种类型资源)

  • 两个硬盘都具有 Kind 为 Sh 的种类,那若此时创建 Kind=Sh 的名为 test1 文件,该存储到哪个硬盘中?
  • 所以引入 Group 概念,创建时候应该说清出,创建【可以执行的】 sh 文件(即指定 Group=group1、Kind=Sh);但因为 group1 有多个 Kind (Sh、Doc、Txt),所以创建一个 shs 文件夹( Kind 小写字母复数形式,表示保存此类型文件,且数量较多),所以该 sh 文件目前的存储路径应该为 group1硬盘\shs\test1.sh
  • 但同时我们还有个规划,后续 Kind=Sh 的文件存储到 group1 中会自动加上水印,因此我们将目前这个无水印版本称之为 v1alpha1 版本,后续有水印版本称之为 v1 版本,那怎么区分呢?
    • 答:在 Kind 的上一级创建 Version (版本)文件夹,无水印版本创建 v1alpha1 文件夹,有水印版本创建 v1 文件夹,所以 test1.sh 对应的文件夹路径应改为 group1硬盘\v1alpha1\shs\test1.sh
  • 那就带来一个问题,若现在创建一个【可执行的、有水印的、Kind=Sh】名为 test2 的文件,只是指定 Group=group1 和 Kind=Sh ,也无法确定该 sh 该存储到哪个文件夹中,所以引入 Version 的概念,指定【Group=group1、Version=v1、 Kind=Sh】,这样便可以直到存储路径应为group1硬盘\v1\shs ,最后的文件路径为group1硬盘\v1\shs\test2.sh
Namespace 概念引入

Namespace 用于 资源隔离

上面需求刚解决完成,又来个需求,user1 用户创建的 sh 文件想要和 user2 创建的 sh 文件分隔开,而现在所有用户创建【可执行的 Group=group1、有水印的Version=v1、Kind=Sh】,都存储在group1硬盘\v1\shs 路径下,没有隔离性,user1 分不清这些文件中哪个是自己创建的,哪个是 user2 创建的,比如 user1 和 user2 都创建个【可执行的 Group=group1、有水印的Version=v1、Kind=Sh】名为 test3 的文件,就会冲突

  • 为了解决这个问题,我们提出个 Namespace 的概念,在 Kind 的上一级创建 Namespace 文件夹,比如 user1 的 Namespace 文件夹命名为 user1,user2 的 Namespace 文件夹命名为 user2,这样就分隔开了, user1 存储路径为 group1硬盘\v1\user1\shs\test3.sh
  • 这样解决了【user1和user2创建文件冲突的问题】,但还有不足,就是 group1硬盘\v1\user1\shs\test3.sh 路径可读性不强,从后往前读可知,test3.sh 前面是 shs,说明 test3.sh 文件时 Kind=Sh 类型,但 user1 我们就不太清楚是什么概念,同时有的用户名若是乱码如sdfsf,那就编程 group1硬盘\v1\sdfsf\shs\test3.sh ,就更不清楚该路径的语义,而 Group 硬盘名 和 Version 名数量是有限的,而且用户无法自定义,同时命名也是易懂的,所以不需要上层概念就能理解;
    • 所以为了解决此问题,我们在 Version 文件夹下一级增加 namespaces 文件夹(表名下一层级是 Namespace 概念,复数表示有众多 Namespace 文件夹),然后 namespaces 文件夹中创建【用户名对应的 Namespace 文件夹】,形式如下Group硬盘名\Version名\namespaces\用户自定义Namespace文件夹\Kind文件夹\Kind文件,因此 user1 创建的 test3.sh 对应的路径为 group1硬盘\v1\namespaces\user1\shs\test3.sh
全局概念引入

仍需要保留【非Namespace】的概念,有的资源需要全局独一份,用于全局管控,如 ClusterRole

上面解决了用户隔离问题,但同时还有个新的需求,group1 硬盘中 Version=v1、Kind=Doc 的文件是可全局访问到的、是重要的,同时需要保证唯一性;因此 user1 创建 doc 文件保存到 user1 Namespace 中,user2 创建 doc 文间保存到 user2 Namespace 中,都是存储在自己的 Namespace 文件夹中,因为文件夹的权限控制,user2 无法问到 user1 的 Namespace 文件夹、user1 也无法访问到 user2 的 Namespace 文件夹;

  • 因此创建 Doc 文件需要考虑放到一个公共的文件夹,这样所有 user 都可以访问,同时保证 doc 文件的唯一(同一个文件夹不会有重名文件)
  • 基于此需求,我们对 Doc 文件的创建取消 Namespace 的概念,如创建【Group=group1硬盘、Version=v1、Kind=Doc、名为 test4】,那么对应的路径为group1硬盘\v1\docs\test4.doc
Resource 概念引入

由于由【Namespace】和【非Namespace】情况存在,GVK 无法判断出资源 URI 中是否要携带 Namespace 路径

而 GVR 可以解决此问题,Resource 中预先写入【控制信息】(如 Pod 的 Namespaced = True,ClusterRole 的 Namespaced = False)

所以也分清了职责

  • GVK 专注于定位到资源的数据结构
  • GVR 专注于生成资源描述符(URI),用于找到资源对象(Object)

上面共用问题也解决了,但也带来个问题,何时创建 Namespace 文件夹(或说哪种资源该创建 Namespace,同时应该如何控制)

  • 【Group=group1硬盘、Version=v1、Kind=Sh】,这种资源该创建 Namespace 文件夹

  • 但 【Group=group1硬盘、Version=v1、Kind=Doc】,这种资源不该创建 Namespace 文件夹

  • 而通过这种 GVK 的组合,创建资源时无法判断是否应该创建 Namespace 文件夹;不过也有种方法解决,【在后台将判断逻辑写死 Kind=Sh 就创建 Namespace 文件夹,Kind=Doc 就不创建 Namespace 文件夹,但这种方式不够灵活,程序是写死的,若后续这两情况反过来,还需要重新编译程序】 —— 因此为了解决这个问题,提出了 Resource 的概念

  • Resource ,也可以称之为 APIResource ,是 Kind 的同名小写复数形式(如 Kind=Sh,Resource=shs;Kind=Doc,Resource=docs),同时该 Resource 结构不同于 Kind,Kind 是 string 字符串,Resource 是结构体,Resource 内部具有个 Namespaced 属性(若 Namespaced=True 表示创建该资源时会创建 Namespace 文件夹,反之不会创建);如 Kind=Sh 对应的 shs Resource 结构就具有 Namespaced=True,这样提交 【Group=group1硬盘、Version=v1、Kind=Sh、user1、文件名为 test5】的创建请求时,GVK 会自动转换为 GVR,根据 GVR 中 Resource 的设置,形成相应的存储路径 group1硬盘\v1\namespaces\user1\shs\test5.sh;而Kind=Doc 对应的 docs Resource 结构就具有 Namespaced=False,后续不会创建 Namespace 文件夹,不在详解

Rest 映射、Schema、Object

Rest 映射( RestMapper):实现 GVK 和 GVR 的互相转换

Schema:GVK 和 资源数据结构的映射表

Object:资源对象,也可以称为 资源存储实体

  • 那 GVK 和 GVR 具体是如何转换的呢? —— 答:Rest 映射,有个 RestMapper 结构,此处不在详解

    • Group/Version/Kind(Rest 映射–>)Group/Version/Resource(GVR 形成–>)路径(path)
      group1硬盘/v1/Shgroup1硬盘/v1/shs(Namespaced=True)group1硬盘\v1\namespaces\{{user自定义那namespace}}\shs\{{用户创建的sh文件}}
      group1硬盘/v1/Docgroup1硬盘/v1/docs(Namespaced=False)group1硬盘\v1\docs\{{用户创建的doc文件}}
  • 最后还有个问题,GVK 相当于指定创建【何种类型的文件】,但这么多 GVK 和文件类型的对应关系,我该如何记住呢 —— 答:引入了 Schema 概念,可将 Schema 理解为一个记录表,记录 GVK 与创建文件类型的关系

    • Group/Version/Kind文件类型
      group1硬盘/v1alpha1/Sh无水印的 sh 文件
      group1硬盘/v1/Sh有水印的 sh 文件
      省略若干 GVK 介绍
      group1硬盘/v1/Doc有水印的 Doc 文件
  • 还差一个概念 Object,就是 GVK 对应创建出的真实文件,可理解为实际的存储

故事总结

在这里插入图片描述

  • Group 组、Version版本、Namespace 命名空间,这些都很容易理解,都是为了隔离,资源版本隔离(Group、Version)和用户资源隔离(Namespace)

  • Kind 对象类型,如 Kind=Sh 对应 sh 类型文件,Kind=Doc 对应 doc 类型文件

  • Resource 可以理解为 Kind 的含义补充,用于获取真正的资源对象;GVK 专注于类型定义,确定是哪种资源对象,GVR 专注于获取资源对象或对资源对象进行操作;GVR 可转换为资源对象的存储路径 Path,对应实际中就是 http path(对应 Restful API 中 URI、URL 的概念,可以说是文件资源标识),我们拿到了 URL 或 PATH,自然就可以访问到资源实体,所以称之为 Resource 很合理

  • Object 就是 GVK 创建的真正的资源存储实体,也是通过 GVR 形成 Path 所要访问的资源实体

  • Schema 是记录 GVK 与 资源结构的映射,知道 GVK 便知道要创建的资源对象的数据结构

  • GVK 和 GVR 是通过 Rest 进行映射,GVK 只专注于类型定义,GVR 包含构建资源路径的各种细节(比如是否要添加 namespace 路径等)

  • 为什么这么定义?

    • 可将 apiserver 理解为一个普通的 http server

    • 外部视角:用户通过 URL 才能访问到对应的资源吧,因此会认为 URL(HTTP PATH) 为 Resource(Restful API 中也是将 URL 定义为 Resource,所以 GVR 相当于一个用于生产外部 URL Resource 的概念)

    • 内部视角:用户提交指定 GVK 的 yaml,通过 GVK 检索(Schema)到对应的资源结构(Go Struct),才能创建资源,并完成持久化存储(Object)

    • apiserver 视角:本身是个 http Server,在启动前预先注册了 http path --> handler 的映射关系(就是用户向指定 http path 提交请求时,需要有对应的 handler 处理);通过 http path 可知道 GVR,但 GVR 不知道对应的资源结构(Go Struct),所以 GVR 和 GVK 存在个互相转换机制(RestMapper),这样通过 GVK 可知道该 http path 请求对应的资源结构(Go Struct),之后便交给 handler 处理;同时有时候只知道 GVK,但需要向指定路径 http path 发起请求,就需要通过互相转换机制(RestMapper)将 GVK 转换为 GVR,从而生成 http path

k8s 实操来理解概念

准备工作
# 开启 8080 端口,用于 http 访问
-> % kubectl proxy --port=8080
Starting to serve on 127.0.0.1:8080
案例一(支持 Namespace 的 Deployment, apps 组,apis 前缀)
# 案例一(支持 Namespace 的 Deployment, apps 组,apis 前缀)
# 创建 deployment  名为 encode-deploy
kubectl create deployment encode-deploy --image=busybox --replicas=1 -- /bin/sh -c "while true; do sleep 3600; done"

# deployment 的 GVK 为 apps/v1/Deployment
# 对应的 GVR 为 apps/v1/dployments,同时 deployment 支持 Namespace 隔离,而且该 deployment 在 default Namespace 下创建
# 所以 GVR 形成的路径为 apps/v1/namespaces/default/deployments/encode-deploy
# 同时有个知识点需要注意:因为 k8s 开始没有 Group 的概念,后来才有,所以 k8s 的基础资源如 Pod 的 Group 都为空,称之为 core,但在路径中没有表示,所以又创建个 api 和 apis 概念,api 只放置 core 组,其余后续的 Group 都在 apis 组
# 所以上面路径变为 apis/apps/v1/namespaces/default/deployments/encode-deploy
# 再补上 apiserver 的地址  http://localhost:8080
# 组成全路径,获取 encode-deploy 信息
$ curl http://localhost:8080/apis/apps/v1/namespaces/default/deployments/encode-deploy
# 返回的结果
{
  "kind": "Deployment",
  "apiVersion": "apps/v1",
  "metadata": {
    "name": "encode-deploy",
    "namespace": "default",
    "uid": "0bfd0275-cd3c-4602-81be-f996cc055cb2",
    "resourceVersion": "204043",
    "generation": 3,
    "creationTimestamp": "2024-02-28T08:08:52Z",
    "labels": {
      "app": "encode-deploy"
    },
    "annotations": {
      "deployment.kubernetes.io/revision": "1"
    },
    ......
}
案例二(支持 Namespace 的 Pod, core 组,api 前缀)
# 案例二(支持 Namespace 的 Pod, core 组,api 前缀)
# 创建 pod  名为 encode-po
$ kubectl run encode-po --image=busybox -- /bin/sh -c "while true; do sleep 3600; done"
# 按照上面讲解的,pod 的 GVK 为 Group=空 Version=v1 Kind=Pod, Group=空 称之为 core 组 对应的路径为 api 开头
# 同时 Pod 的 Resource 支持 Namespace 隔离,所以 GVR 对应的 Path 为 
# api/v1/namespaces/default/pods/encode-po
$ curl http://localhost:8080/api/v1/namespaces/default/pods/encode-po
# 返回的结果
{
  "kind": "Pod",
  "apiVersion": "v1",
  "metadata": {
    "name": "encode-po",
    "namespace": "default",
    "uid": "13dd4951-321c-45e5-bcb2-33b1e60f3954",
    "resourceVersion": "193006",
    "creationTimestamp": "2024-02-28T03:17:20Z",
    "labels": {
      "run": "encode-po"
    },
   ... ...  
}
案例三(不支持 Namespace 的 ClusterRole, core 组,api 前缀)
  • 扩展内容
    • 为什么 core Group,在路径中不显示 core,而路径前面多了 api?
    • 为什么非 core Group,在路径前面多了 apis 前缀?
# 扩展内容
# - 会奇怪 Pod 为什么只有 v1,没有 Group,因为最开始 k8s 没有 Group 概念,后续新增的,所以最早的基础资源 Group=空,称之为 core Group(核心组),但实际创建 Pod 时候不会写为 core/v1(仍是写为 v1),称之为 core Group 只是为了便于读和理解,总不能说是 Pod 属于【空Group】吧?这样太难理解了。。。 
# 而且还有个问题,记得 GVR 转换 http path 的 规则吧
# Resource 支持 Namespace 时
# GVK --> GVR --> HTTP PATH: /Group名/Version名/namespaces/namesapce名/Resouces名(Kind小写复数形式)/具体对象名称
# Resource 不支持 Namespace 时
# GVK --> GVR --> HTTP PATH: /Group名/Version名/Resouces名(Kind小写复数形式)/具体对象名称
# 按照转换规则 Pod GVK(Group=空,Version=v1,Kind=Pod)对应的 Path 为,default namespace 下名为 encode-po Pod 对应的 http path 为 v1/namespaces/default/pods/encode-po
# 按照转换规则 Deployment GVK(Group=apps,Version=v1,Kind=Pod)对应的 Path 为,default namespace 下名为 encode-deploy Deployment 对应的 http path 为 apps/v1/namespaces/default/deploy/encode-deploy 
# 可以看出,Pod 相比于 Deploy 少了个 Group 前缀,不易于理解,所以为了便于理解,在 Group 前面增加 api 和 apis 概念,规则就是只有 core Group 添加 api 前缀,其余 Group 都添加 apis 前缀,相当于一个再次分类,毕竟 Pod 等 core Group 中的资源属于【老员工】,有个独立的【api办公室】是可以理解的
# 所以演变为:
# core Group 资源路径:v1/namespaces/default/pods/encode-po --> api/v1/namespaces/default/pods/encode-po
# 非 core Group 资源路径: apps/v1/namespaces/default/deploy/encode-deploy  --> apis/apps/v1/namespaces/default/deploy/encode-deploy
  • 案例三
# 案例三(不支持 Namespace 的 ClusterRole, core 组,api 前缀)
# 不知道 ClusterRole 是哪个组,可以采用 kubectl-apiresources 命令进行搜索
# 返回的内容:记录了 GVR 和 GVK 的对应关系,还有 Resource 是否支持 Namespace 信息
# 第一列 Resource 名称(可以看出是小写字母复数形式)
# 第二列 该 Resource 的缩写,比如 pods 的缩写为 po,因此 kubectl get pods 等同于 kubectl get po,但同时需要注意有的没有缩写
# 第三列 该 Resource 和 Kind,所属于的 Group/Version,v1 代表 core Group 没有 Group 名
# 第四列 该 Resource 是否支持 Namespace 隔离,Namespaced=True 表示支持
# 第五轮 Kind 名称(包含大写字母)
 
$ kubectl  api-resources
NAME                              SHORTNAMES   APIVERSION                             NAMESPACED   KIND
bindings                                       v1                                     true         Binding
componentstatuses                 cs           v1                                     false        ComponentStatus
configmaps                        cm           v1                                     true         ConfigMap
endpoints                         ep           v1                                     true         Endpoints
events                            ev           v1                                     true         Event
pods                              po           v1                                     true         Pod
podtemplates                                   v1                                     true         PodTemplate
limitranges                       limits       v1                                     true         LimitRange
daemonsets                        ds           apps/v1                                true         DaemonSet
deployments                       deploy       apps/v1                                true         Deployment
replicasets                       rs           apps/v1                                true         ReplicaSet
statefulsets                      sts          apps/v1                                true         StatefulSet
... ...

# 上面信息太多,想要知道 ClusterRole 属于哪个 Group Version,可以看到如下命令
# 另外,可以看到 ClusterRole 对应的 Namespced=False, 不具备 Namespace 隔离,符合我们的测试要求
$ kubectl api-resources | grep clusterrole

clusterrolebindings                            rbac.authorization.k8s.io/v1           false        ClusterRoleBinding
clusterroles                                   rbac.authorization.k8s.io/v1           false        ClusterRole

# 随意查看个已有的 ClusterRole
$ bectl get clusterrole
NAME                                                                   CREATED AT
admin                                                                  2024-01-30T09:53:07Z
cluster-admin                                                          2024-01-30T09:53:07Z
... ...

# 以 admin  ClusterRole 为例, 按照上面构建路径,并发起请求,符合预期
curl http://localhost:8080/apis/rbac.authorization.k8s.io/v1/clusterroles/admin
{
  "kind": "ClusterRole",
  "apiVersion": "rbac.authorization.k8s.io/v1",
  "metadata": {
    "name": "admin",
    "uid": "37abf107-240e-474e-a65b-5827aff7cf00",
    "resourceVersion": "336",
    "creationTimestamp": "2024-01-30T09:53:07Z",
    "labels": {
      "kubernetes.io/bootstrapping": "rbac-defaults"
    },
    "annotations": {
      "rbac.authorization.kubernetes.io/autoupdate": "true"
    },
    ... ...   
}

SubResource 概念的引入

  • 相信你已理解上面 Resource 的概念,那 subResource 概念是什么意思呢?
  • 现在可以简单理解为,通过 curl GVR 形成的 http path 可以获取到一个 Deployment (此处示例为 default Namespace 下名为 encode-deploy 的 Deploy)的所有信息curl http://localhost:8080/apis/apps/v1/namespaces/default/deployments/encode-deploy
    • 此时会带来几个考虑
    • 用户1只想更改 encode-deploy 的副本数 replicas,觉得返回一堆信息没必要,增加更改复杂度
    • 用户2比较危险,需求只想更改 encode-deploy 的副本数 replicas,但现在其可以更改该 Deployment 的所有字段
    • 所以给 deployments Resource 增加了 scale Resource 用于更改 Deployment 的副本数
      • 路径变为了curl http://localhost:8080/apis/apps/v1/namespaces/default/deployments/encode-deploy/scale
      • 通过此路径,可以更改 Deployment 的副本数,也就是 replicas 字段
      • 以往在 RBAC 中只能赋予 deployments 权限,现在可以赋予 deployments/scale 权限,让用户只能更改副本数,无法更改其余字段
subresource 作用

Question1 : 可以通过 kubectl edit 更改 deployment 副本数,为什么还提出一个 scale subresource(子资源)

  1. API 一致性和规范性:Kubernetes 的设计哲学之一是提供统一的 API。通过为资源引入 scale 子资源,可以使得副本数的管理变得更加规范和统一,无论是通过 kubectl、API 或者其他工具,用户都可以使用相同的方法来管理副本数。这种一致性有助于降低用户学习成本,并简化资源管理。
  2. 权限控制和安全性:引入 scale 子资源可以使得 Kubernetes 更加灵活地进行权限控制。通过 RBAC(基于角色的访问控制)机制,管理员可以精确地控制哪些用户或服务账号具有修改副本数的权限,而不必担心他们能否编辑整个 Deployment 对象或其他资源。
  3. 自动缩放支持:许多 Kubernetes 集群中使用了自动缩放功能,例如 HorizontalPodAutoscaler (HPA)。HPA 可以根据资源使用率或自定义指标动态调整副本数。scale 子资源为这种自动缩放功能提供了支持,HPA 可以通过 scale 子资源查询和调整资源的副本数,从而实现自动化的水平扩展和收缩。

简而言之(说人话):

  1. 明显 kubectl edit 对应的 curl 比 kubectl scale 繁琐
  2. API 统一:scale subresource 出现后,statefulset、deployment、daemonset 扩缩容发起 http 请求时,只需要关注 scale 子资源,就是 curl …/scale,很统一
  3. 若采用 kubectl edit 进行扩容,用户需要具有【修改整个 deployment 对象的 update 权限,过大】,而采用 kubectl scale,用户只需要具有【deployment/scale 子资源的 update 权限,范围缩小,更安全】
  4. 增加了 scale 子资源后,便于进行自动缩放功能

Question2: 为什么 curl 更改 scale subresource 后,就可以进行 deployment 的扩缩

curl -X PUT
-H “Content-Type: application/json”
–data ‘{“apiVersion”:“autoscaling/v1”,“kind”:“Scale”,“metadata”:{“name”:“encode-deploy”,“namespace”:“default”},“spec”:{“replicas”:2}}’
http://localhost:8080/apis/apps/v1/namespaces/default/deployments/encode-deploy/scale

  • 增加 scale subresource,其实就相当于【增加一个 http path 端点】
  • 以往 deployment http 端点为 http://localhost:8080/apis/apps/v1/namespaces/default/deployments/encode-deploy
  • 而该新增的 scale http path 端点,对应的 http handler ,其实功能很简单,就是更改指定 deployment 的 spec.replicas(此例子是 encode-deploy 的 replicas),之后逻辑就很好理解了,deployment Controller 监控到 encode-deploy replicas 副本数的变化,便会进行相应的扩缩容
k8s 实操 subresource
# 开启 8080 端口,用于 http 访问
-> % kubectl proxy --port=8080
Starting to serve on 127.0.0.1:8080

# 创建 deployment  名为 encode-deploy
kubectl create deployment encode-deploy --image=busybox --replicas=1 -- /bin/sh -c "while true; do sleep 3600; done"

# 对 encode-deploy  进行扩容
# 方法1: 通过 scale subresource 进行扩容,对 scale http 端点发请求
-> % curl -X PUT \
  -H "Content-Type: application/json" \
  --data '{"apiVersion":"autoscaling/v1","kind":"Scale","metadata":{"name":"encode-deploy","namespace":"default"},"spec":{"replicas":2}}' \
  http://localhost:8080/apis/apps/v1/namespaces/default/deployments/encode-deploy/scale
# 成功执行
{
  "kind": "Scale",
  "apiVersion": "autoscaling/v1",
  "metadata": {
    "name": "encode-deploy",
    "namespace": "default",
    "uid": "0bfd0275-cd3c-4602-81be-f996cc055cb2",
    "resourceVersion": "203932",
    "creationTimestamp": "2024-02-28T08:08:52Z"
  },
  "spec": {
    "replicas": 2
  },
  "status": {
    "replicas": 1,
    "selector": "app=encode-deploy"
  }
}%

# kubectl scale(等同于上面,只是进行了封装,内部逻辑相同,实际代码执行逻辑等同于上面 curl)
-> % kubectl scale deploy encode-deploy --replicas=2
deployment.apps/encode-deploy scaled

# 方法2: 利用 kubectl edit 进行扩容,更改该 deploy 中的 spec.replicas 为 2
# 实际等同于,以下3步(未验证,可做参考),相比于 scale subresource 繁琐
# 1. 获取当前 yaml 配置:curl http://localhost:8080/apis/apps/v1/namespaces/default/deployments/encode-deploy -o deployment.yaml
# 2. 修改 yaml 配置:接下来,编辑 deployment.yaml 文件,将 spec.replicas 字段的值修改为 2
# 3. 上传新的 yaml 配置:curl -X PUT -H "Content-Type: application/yaml" --data-binary "@deployment.yaml" http://localhost:8080/apis/apps/v1/namespaces/default/deployments/encode-deploy
kubectl edit deploy encode-deploy
# 修改 spec.replicas 为 2 ,保存 esc  :wq
获取 subresource
  • Where can I get a list of Kubernetes API resources and subresources? - Stack Overflow
  • 由于无法直接查看到 Resource 有哪些 subResource,通过此脚本可以看到有哪些 subResource
# 1. 开启 proxy 8080 端口,http 不安全访问
$ kubectl proxy --port=8080

# 2. 执行如下脚本获取 subresource
# 若不执行第一步,未开启8080端口,那么将 curl -s $SERVER/ 替换为 kubectl get --raw / 即可正常执行
#!/bin/bash
SERVER="localhost:8080"

APIS=$(curl -s $SERVER/apis | jq -r '[.groups | .[].name] | join(" ")')

# do core resources first, which are at a separate api location
api="core"
curl -s $SERVER/api/v1 | jq -r --arg api "$api" '.resources | .[] | "\($api) \(.name): \(.verbs | join(" "))"'

# now do non-core resources
for api in $APIS; do
    version=$(curl -s $SERVER/apis/$api | jq -r '.preferredVersion.version')
    curl -s $SERVER/apis/$api/$version | jq -r --arg api "$api" '.resources | .[]? | "\($api) \(.name): \(.verbs | join(" "))"'
done

# 3. 执行结果举例
...
core pods: create delete deletecollection get list patch update watch
core pods/attach: create get
core pods/binding: create
core pods/ephemeralcontainers: get patch update
core pods/eviction: create
core pods/exec: create get
core pods/log: get
core pods/portforward: create get
core pods/proxy: create delete get patch update
core pods/status: get patch update
...

理解 k8s 主要 go 库作用

  • Kubernetes类型系统 | 李乾坤的博客

k8s中Apimachinery、Api、Client-go库之间的关系k8s.io/client-go, k8s.io/api, k8s.io/apimachinery 是基于Golang的 Kubernetes 编程的核心,是 schema 的实现。kubernetes 中 schema 就是 GVK 的属性约束 与 GVR 之间的映射。

  1. apimachinery 是最基础的库,包括核心的数据结构,比如 Scheme、Group、Version、Kind、Resource,以及排列组合出来的 常用的GVK、GV、GK、GVR等等,再就是编码、解码等操作。类似于Java 中的Class/Method/Field 这些
  2. api 库,这个库依赖 apimachinery,提供了k8s的内置资源,以及注册到 Scheme 的接口,这些资源比如:Pod、Service、Deployment、Namespace
  3. client-go 库,这个库依赖前两个库,提供了访问k8s 内置资源的sdk,最常用的就是 clientSet。底层通过 http 请求访问k8s 的 api-server,从etcd获取资源信息

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/420788.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Harbor 的安装及使用

Harbor 安装官网手册: https://goharbor.io/docs/2.10.0/install-config/download-installer/ Harbor 发布包地址: https://github.com/goharbor/harbor/releases Harbor 的架构查看: https://github.com/goharbor/harbor/wiki/Architectur…

​MPV,汽车产品里一个特殊品类的进化过程

「汽车」可能是整个工业革命以来,所诞生出的最有趣的工业产品。 它不仅能产生工业的机械美,还诞生了一个独立的文化体系,在汽车的发展过程中,我们也能看到一些本来应功能而诞生的产品,最终走向了千家万户。 MPV 就是…

如何设置从小程序跳转到其它小程序

​有的商家有多个小程序,希望能够通过一个小程序链接到所有其它小程序,用户可以通过点击跳转链接实现从一个小程序跳转到另一个小程序。要怎么才能实现这样的跳转呢。下面具体介绍。 1. 设置跳转。在小程序管理员后台->分类管理,添加一个…

js截取图片地址后面的参数和在路径中截取文件名或后缀名

文章目录 前言截取地址 ?后面的参数在路径中截取文件名或后缀名总结 前言 在处理网页上的图片资源或者其他类型的文件资源时,你可能会遇到需要使用这些技巧的情况。以下是一些具体的使用场景: 动态修改图片参数:如果你有一个图片U…

社交APP开发能给用户带来什么

现在的社交软件也非常的多,每款社交软件都有自己的特色,社交软件是日常中必备的软件,不管是生活交流还是感情工作交流都是比较方便的,因为社交软件满足了日常的远程交流问题,所以开发社交软件也会逐渐的流行起来的。 …

LeetCode240题:搜索二维矩阵II(python3)

代码思路: “根节点” 对应的是矩阵的 “左下角” 和 “右上角” 元素,以 matrix 中的左下角元素为标志数 flag ,则有: 若 flag > target ,则 target 一定在 flag 所在行的上方 ,即 flag 所在行可被消去&#xff0c…

NLP - 神经网络与反向传播

使用神经网络进行命名实体识别(二值词窗分类) 根据上下文窗口 建立词向量 通过一个神经网络层,通过一个逻辑分类器,得到这个概率是属于特定实体词的预测概率。 另一个分类器来比较说明 这个词是哪个实体类型(比较概率…

基于Python3的数据结构与算法 - 07 归并排序

一、归并 引入 假设现在的列表分两段有序,如何将其合并成为一个有序列表。 这种操作成为一次归并。 归并的思路 分别对两个列表进行遍历,比较两个列表中的最小值,将更小的取出来。取出后一次进行上操作,直到其中一个列表中的元…

Servlet 新手村引入-编写一个简单的servlet项目

Servlet 新手村引入-编写一个简单的servlet项目 文章目录 Servlet 新手村引入-编写一个简单的servlet项目一、编写一个 Hello world 项目1.创建项目2.引入依赖3.手动创建一些必要的目录/文件4.编写代码5.打包程序6.部署7.验证程序 二、更方便的处理方案(插件引入&am…

vue3编写H5适配横竖屏

具体思路如下&#xff1a; 1、监听浏览器屏幕变化&#xff0c;通过监听屏幕宽高&#xff0c;辨别出是横屏&#xff0c;还是竖屏状态 在项目的起始根页面进行监听&#xff0c;我就是在App.vue文件下进行监听 代码如下&#xff1a; <template><RouterView /> <…

Redis 存储原理和数据模型

redis 是不是单线程 redis 单线程指的是命令处理在一个单线程中。主线程 redis-server&#xff1a;命令处理、网络事件的监听。 辅助线程 bio_close_file&#xff1a;异步关闭大文件。bio_aof_fsync&#xff1a;异步 aof 刷盘。bio_lazy_free&#xff1a;异步清理大块内存。io_…

【前端素材】推荐优质在线高端家具电商网页Classi平台模板(附源码)

一、需求分析 1、系统定义 在线高端家具商城是一个专门销售高端家具产品的电子商务平台&#xff0c;旨在为消费者提供购买高品质家具的便捷渠道。 2、功能需求 在线高端家具商城是一个专门销售高端家具产品的电子商务平台&#xff0c;旨在为消费者提供购买高品质家具的便捷…

springboot-基础-thymeleaf配置+YAML语法

备份笔记。所有代码都是2019年测试通过的&#xff0c;如有问题请自行搜索解决&#xff01; 目录 配置thymeleafthymeleaf举例参数设置yaml基础知识YAML语法报错&#xff1a;Expecting a Mapping node but got 其他语法 spring boot不推荐使用jsp。thymeleaf是一个XML/XHTML/HTM…

react 使用 craco库 配置 @ 路径,以及 jsconfig.json或者tsconfig.json 配置智能提示

使用 craco库 来自定义CRA配置 1、概述 Craco&#xff08;Create React App Configuration Override&#xff09;是一个用于扩展 Create React App&#xff08;CRA&#xff09;配置的工具。通过 Craco&#xff0c;你可以在不弹出 Create React App 的内部配置的情况下&#x…

Entry First Day 入职恩孚第一天

入职第一天&#xff0c;电脑还没配置好就去了工厂。 熟悉了一下设备&#xff0c;切了几个小玩意&#xff0c; hello world 一下。 了解了串行端口的Nodejs的库 https://github.com/serialport/node-serialport&#xff0c;以后要用这个东西和硬件通讯&#xff0c;安装&#…

CleanMyMac X2024免费Mac电脑清理和优化工具

CleanMyMac X是一款专业的 Mac 清理和优化工具&#xff0c;它具备一系列强大的功能&#xff0c;可以帮助用户轻松管理和维护他们的 Mac 电脑。以下是一些关于 CleanMyMac X 的主要功能和特点&#xff1a; 智能清理&#xff1a;CleanMyMac X 能够智能识别并清理 Mac 上的无用文件…

mybatis原理图,我拿到了梦寐以求的字节跳动和腾讯双offer

Kafka 如何做到支持百万级 TPS &#xff1f; 先用一张思维导图直接告诉你答案&#xff1a; 顺序读写磁盘 生产者写入数据和消费者读取数据都是顺序读写的&#xff0c;先来一张图直观感受一下顺序读写和随机读写的速度&#xff1a; 从图中可以看出传统硬盘或者SSD的顺序读写甚…

map和set例题应用

个人主页&#xff1a;Lei宝啊 愿所有美好如期而遇 目录 第一题 第二题 第三题 第一题 随机链表的复制https://leetcode.cn/problems/copy-list-with-random-pointer/description/ 思路 首先遍历旧链表&#xff0c;并创建新节点&#xff0c;同时用map将旧节点与新节点…

3,设备无关位图显示

建立了一个类Dib Dib.h #pragma once #include “afx.h” class CDib :public CObject { public: CDib(); ~CDib(); char* GetFileName(); BOOL IsValid(); DWORD GetSize(); UINT GetWidth(); UINT GetHeight(); UINT GetNumberOfColors(); RGBQUAD* GetRGB(); BYTE* GetDat…

MySQL:使用聚合函数查询

提醒&#xff1a; 设定下面的语句是在数据库名为 db_book里执行的。 创建t_grade表 USE db_book; CREATE TABLE t_grade(id INT,stuName VARCHAR(20),course VARCHAR(40),score INT );为t_grade表里添加多条数据 INSERT INTO t_grade(id,stuName,course,score)VALUES(1,测试0…
最新文章