jamlee / blog Goto Github PK
View Code? Open in Web Editor NEWREPO for experimentation; ISSUE for blog
REPO for experimentation; ISSUE for blog
Please install our new product, Sonatype Lift with advanced features
Kubebuilder 和 Operator 是基于Controller Runtime
开发的 k8s 扩展脚手架。Controller Runtime
是用于监控 K8s
中 Resource
(例如Pod等)的资源事件的go库,本质上是对 client-go 中的 list 和 watch 方法的再次封装。实现了限流消息队列的能力, 保证了我们监控K8s
中的资源事件是高性能、高可用的。例如 Pod创建、Pod删除、Pod更新这样的都是资源事件。高性能体现自watch的资源会存在本地的cache,获取已经 watch 的资源描述是会从缓存中取的。在阅读本文时我们应该至少使用过Kubebuilder 和 Operator 写过一些小东西。下文简称 Controller Runtime
为 cr
.
cr
小例子源码下载: https://github.com/kubernetes-sigs/controller-runtime
让我们先看一个CR
的小例子:https://github.com/kubernetes-sigs/controller-runtime/blob/master/example_test.go
func Example() {
// 创建一个全局的日志对象
var log = controllers.Log.WithName("builder-examples")
// 创建一个controller manager, 该对象用于管理 controller
manager, err := controllers.NewManager(controllers.GetConfigOrDie(), controllers.Options{})
if err != nil {
log.Error(err, "could not create manager")
os.Exit(1)
}
// 创建一个监控 ReplicaSet 名下的 Pod 资源类型的 controller,对应的处理资源的对象为ReplicaSetReconciler
err = controllers.
NewControllerManagedBy(manager). // Create the Controller
For(&appsv1.ReplicaSet{}). // ReplicaSet is the Application API
Owns(&corev1.Pod{}). // ReplicaSet owns Pods created by it
Complete(&ReplicaSetReconciler{Client: manager.GetClient()})
if err != nil {
log.Error(err, "could not create controller")
os.Exit(1)
}
// 启动 manager 名下所有的 controller
if err := manager.Start(controllers.SetupSignalHandler()); err != nil {
log.Error(err, "could not start manager")
os.Exit(1)
}
}
# 主要的文件在pkg中
...
.
└── pkg
├── builder
├── cache # 管理多个 informers
├── client # 重新封装了client-go 的 client。实现读写分离,typed 和 unstructed 同用一个 client
├── controller # 内置controller 的实现
├── conversion
├── doc.go
├── envtest
├── event
├── handler
├── healthz
├── internal # 内置controller 的实现
├── leaderelection
├── log
├── manager 含有 manager 的实现
├── metrics
├── patterns
├── predicate
├── ratelimiter
├── reconcile
├── recorder
├── runtime # 含有 manager 的实现
├── scheme
├── source # 用于监控资源, 并把资源放到 queue 中
└── webhook
这里核心的文件夹有: source, cache, client, runtime, controller, reconcile。理清这几个文件夹里的内容是可以理清 controller runtime 工作机制的脉络的,这里让我们避轻就重大概看下 cr
的工作过程。 cr
的启动我们经常看到, 先实例化一个 manager 然后manger 中填入多个 controller 最后启动 manager。实际上 manager.Start函数中启动了循环启动了多个 controller。
这里我们用几句话概括下上图的内容:
cr
在启动时初始化了共享的全局变量给 manager,manager 把全局变量分配给名下的多个 controller。
cache 和 client 分别是什么呢?
cache 是 informerCache。informer Watch 时是wacth 的每一类资源例如 Pod,所以如果 Pod已经被 Watch了的话,因为Watch 时得到的返回对象就是 Informer,所以这里把所有的 Informers管理起来了。另外读取Pod时,因为Pod是被Watch的,最新的状态就在本地缓存中,所以会从本地缓存查询 Pod 状态,不访问 kube-apiserver。
client 是 clientCache。意为缓存 client-go 的 restClient 的实例。我们都见过 clientset 吧,clientset 里含有 core, apps 等api组的 client,似乎是在启动时就全部初始化了。cr
没有这么做, cr 只在用到 client 时采取初始化 client。并且 client 对client-go 的 restClient 做了封装。client 有个内部对象是 cache, 读就从 cache中读, 写就是直连。
# pkg/manager/manager.go:401
return &client.DelegatingClient{
Reader: &client.DelegatingReader{
// NOTE(JamLee): informerCache,处理结构化和非结构化。这里缓存了 informer
CacheReader: cache,
ClientReader: c,
},
// NOTE(JamLee): c 是缓存了 client, 每类资源一个 client
Writer: c,
StatusClient: c,
}, nil
这里我们一句话感性地总结下:
启动初始化全局变量 cache 和 client 给 manager,manager 把全局变量分配给名下的多个 controller。controller 下发全局变量并协调 source, reconciler, queue 等一起工作。
看到这里我们是否已经清楚了 cr
的脉络呢?接下来把每一个对象搞清楚就是完整的 cr
的分析了。让我们来各个击破吧!!!
工具库,用于缓存 informer, 并实现读写分离是它的真实写照。
工具库,用于缓存 client-go 的 restClient, 并实现typed 和 unstructured 都使用同一个 client。这个dynamic 在 client-go 是需要单独处理的。
用于监听事件支持 informer 和 webhook 两种方式。informer 这一侧是通过 controller 设置给 source 的 cache(informerCache)了来的,webhook 目前看来是用不到的。
cr
调用了 apiserver 的 watch 接口,它是使用了 client-go 的 informer, informer 本质上还是调用了 http 接口。
这里 Informer 归属于 client-go 的内容。底层调用了 watch 接口, watch接口是长连接,不会主动退出。这里我们再看一个 client-go
中使用 informer的小例子:
package main
import (
"fmt"
"flag"
"time"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/pkg/api/v1"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/pkg/fields"
)
var (
kubeconfig = flag.String("kubeconfig", "./config", "absolute path to the kubeconfig file")
)
func main() {
flag.Parse()
config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
if err != nil {
panic(err.Error())
}
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
panic(err.Error())
}
watchlist := cache.NewListWatchFromClient(clientset.Core().RESTClient(), "services", v1.NamespaceDefault,
fields.Everything())
_, controller := cache.NewInformer(
watchlist,
&v1.Service{},
time.Second * 0,
cache.ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) {
fmt.Printf("service added: %s \n", obj)
},
DeleteFunc: func(obj interface{}) {
fmt.Printf("service deleted: %s \n", obj)
},
UpdateFunc:func(oldObj, newObj interface{}) {
fmt.Printf("service changed \n")
},
},
)
stop := make(chan struct{})
go controller.Run(stop)
for{
time.Sleep(time.Second)
}
}
最原始的方式是调用 http://apiserver:8080/api/v1/watch/pods?watch=yes
方法,调用 watch 接口后会先将所有的对象 list 一次,然后 apiserver 会将变化的数据推送到 client 端,可以看到每次对于 watch 到的事件都需要判断后进行处理,然后将处理后的结果写入到本地的缓存中,原生的 watch 操作还是非常麻烦的。后来了官方推出的客户端 client-go ,client-go 中的 Informer 对 watch 操作做了封装。我们可以这样尝试这个接口:
kubectl proxy --port=8081 &
curl -v -i http://127.0.0.1:8081/api/v1/watch/pods?watch=yes
你会发现 curl 执行后会一致有新内容推送,这个 http 接口本质上是个长连接,原理是用了Chunked transfer encoding(分块传输编码),它首次出现在HTTP/1.1。
cr
中用到一些感觉还不错的库在这里记录一下
ID: JamLee
Email: [email protected]
我平时喜欢阅读一些源代码,这里有我一些开源项目的代码注解: 代码阅读中心。
我的博客采用CC-BY协议进行授权。
也用过一些自建或者博客平台, 管理起来还是繁琐了, 平时用到的过程文件也不好存和阅读。历史的文章不搬运了, 是些没眼看的傻缺内容 😺 哈哈:
jamlee|csdn
《数据发展的世纪之桥:希尔伯特的故事》👍👍👍👍👍
19-20世纪,讲述希尔伯特的一生,从哥尼斯堡(俄罗斯加里宁格勒)到哥根庭,那些希尔伯特或主导或见证的数学盛会。
Libuv是nodejs底层的异步io库。它提供的功能包括是io、进程、线程、信号、定时器、进程间通信等,相比 libev, libuv抹平了各个操作系统之间的差异。Libuv提供的功能如下:
Kubernetes的client-go库介绍client-go是一个调用kubernetes集群资源对象http API的客户端(是一个典型的web服务客户端库),即通过client-go实现对kubernetes集群中资源对象(包括deployment、service、ingress、replicaSet、pod、namespace、node等)的增删改查等操作。kubelet, kubeproxy, shcheduler 等组件均基于 client-go 来监听 api-server 的事件。
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.