K8S的client-go与informer机制
# 一、介绍
client-go是一个包含KubernetesAPI的SDK,它在整个k8s源码中发挥着不可或缺的作用。
# 二、KubernetesAPIs
# 2.1 规范
2.1.1 RESTful REST,即Representational State Transfer的缩写。这个词组可以翻译为"表现层状态转化"。
- 每一个URI代表一种资源;
- 客户端和服务器之间,传递这种资源的某种表现层;
- 客户端通过五个HTTP动词,对服务器端资源进行操作,实现"表现层状态转化"。 提问:注册登录场景的相关API如何用RESTful的方式设计? 2.1.2 GVK(R)
apiVersion: apps/v1
kind: Deployment
metadata:
name: httpbin
namespace: default
spec:
replicas: 1
....
- apiVersion ≈ apiGroupVersion = Group/Version
- GVK = Group Version Kind
- GVR = Group Version Resources 提问:Resource和Kind有什么区别?
答:Resource是一个对象,Kind是一个对象的类型名称
提问:一个标准的K8S资源的API长什么样?
# 2.2 实战调用
2.2.1 跳过鉴权
因为本次分享的API只是个引子,我们就不讲鉴权了。kubectl有个proxy的子命令可以实现在本地搭建一个具备kubectl同等权限的代理。这里我们通过这种方式跳过鉴权。
kubectl proxy --port=6443
2.2.2 几个例子
- 获取当前版本信息
- http://localhost:6443/version
- 获取APIServer支持的所有APIGroup
- http://localhost:6443/apis
- 获取全部命名空间的Deployment列表
- http://localhost:6443/apis/apps/v1/deployments
- 获取命名空间default下的Deployment列表
- http://localhost:6443/apis/apps/v1/namespaces/default/deployments
- 获取命名空间default下的一个Deployment对象
- http://localhost:6443/apis/apps/v1/namespaces/default/deployments/httpbin
- 获取Pod列表
- http://localhost:6443/api/v1/namespaces/default/pods 提问:获取rollout列表的接口是什么样 http://localhost:6443/apis/argoproj.io/v1alpha1/rollouts
# 三、client-go源码
# 3.1 实战调用
https://github.com/kubernetes/client-go/tree/master/examples
# clientset
clientset.AppsV1().Deployments(apiv1.NamespaceDefault).Create(context.TODO(), deployment, metav1.CreateOptions{})
# dynamic
deploymentRes := schema.GroupVersionResource{*Group*: "apps", *Version*: "v1", *Resource*: "deployments"}
dynamicClient.Resource(deploymentRes).Namespace(namespace).Create(context.TODO(), deployment, metav1.CreateOptions{})
# restclient
c.client.Post().
Namespace(c.ns).
Resource("deployments").
VersionedParams(&opts, scheme.*ParameterCodec*).
Body(deployment).
Do(ctx).
Into(result)
# 3.2 Package介绍
client-go源码目录结构
- discovery:用于发现APIs的相关资源
- kubernetes(clientset):基于rest封装的包含所有k8s内置资源的client集合
- informers:基于clientset实现了一个资源缓存池,封装了所有资源的list和get操作
- dynamic:基于rest实现了一个动态的client,支持所有类型的资源进行操作
- dynamic/dynamicinformer:为dynamic实现的informer
- tools/cache:informer的底层实现
- tools/watch:informer的watch实现,使用它可以watch到informer的资源变化
- transport:用作初始化一个http连接,AA也是在这里完成的
# 3.3 核心Package走读
3.3.1 kubernetes(clientset) 3.3.2 dynamic 3.3.3 transport
# 3.4 Informer
informer实际上是为controller服务的,所以这里我们先了解下k8s的controller的设计理念。 3.4.1 控制循环 控制论图解 Kubernetes中的控制循环
通常,控制环路如下所示:
- 阅读资源的状态
- 更改群集或群集外部世界中对象的状态
- 通过etcd中的API服务器更新步骤1中的资源状态
- 重复循环;返回步骤1。
提问:在控制循环中要求近乎实时的获取资源状态,如何实现? 边沿触发与电平触发
提问:事件驱动如何保证不丢数据? 这张图里展示了三种策略:
- edge-driven-only,错过了第二状态改变
- edge-triggered,不依赖事件的数据而是自行获取数据
- edge-triggered with resync,在上一个策略的基础上增加resync
3.4.2 ListWatch list-watch,顾名思义由list和watch组成。list调用资源的list API获取所有资源,watch调用资源的watch API监听资源变更事件。 提问:如何实现watch?
- 方案1:短轮训
- 方案2:长轮训
- 方案3:chunked 普通HTTP响应体
HTTP/1.1 200 OK
Content-Type: text/plain
Content-Length: 25
Mozilla Developer Network ——> body 数据内容,大小为25字节
chunked的HTTP响应体
HTTP/1.1 206 OK
Content-Type: text/plain
Transfer-Encoding: chunked
7 ——> 第一个chunk块,大小为7字节
Mozilla ——> 第一个chunk块内容
9 ——> 第二个chunk块,大小为9字节
Developer ——> 第二个chunk块内容
7 ——> 第三个chunk块,大小为7字节
Network ——> 第三个chunk块内容
0 ——> 标记性终止块,大小为0字节
普通HTTP请求响应处理 chunked的HTTP请求处理 informer中的chunk 抓包观察watch机制 3.4.3 核心代码走读 Informer组件:
- Controller
- Reflector:通过Kubernetes Watch API监听resource下的所有事件
- Lister:用来被调用List/Get方法
- Processor:记录并触发回调函数
- DeltaFIFO
- LocalStore
# 四、实现一个简单的Controller
# 参考文档
- https://github.com/kubernetes/client-go
- https://qiankunli.github.io/2020/07/20/client_go.html
- client-go的使用及源码分析 · Kubernetes 学习笔记 (opens new window)
- edge and level triggered interrupts - L (opens new window)
- https://zh.wikipedia.org/wiki/%E6%8E%A7%E5%88%B6%E8%AE%BA
- 深入理解k8s中的list-watch机制 (opens new window)
- HTTP 协议中的 Transfer-Encoding | JerryQu 的小站 (opens new window)
- 原文出处:
- 原文作者: https://github.com/saltbo
- 原文链接:
- 版权声明:本文欢迎任何形式转载,转载时完整保留本声明信息(包含原文链接、原文出处、原文作者、版权声明)即可。本文后续所有修改都会第一时间在原始地址更新。