kubernetes api公约

api规范 前言 本问主要讲解整个kubernetes api的规范公约,本文译自kubernetes社区的本篇文档。译这篇文章是因为在与kubernetes打交道曾多次参考,非常有价值,可以帮助我们更好的理解kubernetes api。中文有的地方表达不是很完善,最好可以对照原文看。下面是部分译文。 本文档面向想深度理解kubernetes api结构,以及扩展kubernetes的开发人员。 目录 Types (Kinds) Resources Objects Metadata Spec and Status Typical status properties References to related objects Lists of named subobjects preferred over maps Primitive types Constants Unions Lists and Simple kinds Differing Representations Verbs on Resources PATCH operations Idempotency Optional vs. Required Defaulting Late Initialization Concurrency Control and Consistency Serialization Format Units Selecting Fields Object references HTTP Status codes Success codes Error codes…

探索client-go中的exec和cp的原理

开发kubernetes控制器中可能涉及到进入特定的container中执行命令的操作,或者拷贝文件等操作,此时我们可能会借助client-go提供的这个工具去实现: "k8s.io/client-go/tools/remotecommand" // 构建请求 req := client.RESTClient().Post(). Resource("pods"). Name(podName). Namespace(namespace). SubResource("exec") req.VersionedParams(&v1.PodExecOptions{ Container: containerName, Command: cmd, Stdin: false, Stdout: true, Stderr: true, TTY: true, }, scheme.ParameterCodec) // 创建执行器 exec, err := remotecommand.NewSPDYExecutor(config, "POST", req.URL()) // 执行命令 exec.Stream(remotecommand.StreamOptions{ Stdin: nil, Stdout: &buf, Stderr: &buf, Tty: true, }) 上面代码执行时会向apiserver发起一个请求,apiserver会通过代理机制将请求转发给相应节点上的kubelet服务,kubelet会通过cri接口调用runtime的接口发起流式接口中的Exec()接口进入到container执行。针对一般化的命令调用,输入参数和输出结果多数以文本为主,并不会占用带宽和apiserver的资源,但是当设计到文件拷贝的时候则会占用较多带宽,因此在实际使用时这种方式拷贝大文件来说可能并不是最优方案。 此处顺便描述一下如kubectl工具对cp命令的原理,其实也是调用的exec接口,然后执行tar命令进行文件的拷贝动作: # 从容器向外拷贝,通过tar命令压缩将输出重定向到标准输出 tar cf - <srcFile# 从外面向容器内拷贝,将标准输入数据通过tar解压写入到container内的文件目录 tar --no-same-permissions --no-same-owner -xmf - # 或 tar -xmf - 考虑到上面所说的带宽问题,在实际使用时也可向kubelet直接发起exec请求,只要通过client-go将pod所在节点实现查询一下即可,当然还会设计一些端口,证书问题,下面是一个直接向kubelet发起请求的示例代码。 package main import…

client-go代码分析之informer和sharedInformer分析

在茫茫代码中,很容易迷失。经过一段时间的艰苦探索,终于对client-go有了一定的了解,能够从整体上把相关功能串起来。本文主要是informer相关的内容,因为这是client-go比较核心的功能。后面还会发一篇关于client-go编程使用的文章,会从kubernetes.Interface,dynamic,discovery,workequeue和informer工厂函数等方面介绍,再结合一个operator作为实例进行分析(虽然大部分operator都使用kube-builder等类似的工具构建,但是本着求根问底的精神还是要分析一下)。 相关存储结构 在开始介绍之前,先介绍一下client-go中提供存储相关的接口,这些接口用来缓存api对象。Store是最基础的接口,提供增删改查等,还有一些继承于Store的接口,比Store可能会多实现一些方法,可以针对不同的场景进行使用。 Store ExpirationStore UndeltaStore Queue FIFO DeltaFIFO Indexer cache 不同Store的引用 Store接口的具体定义可以看vendor/k8s.io/client-go/tools/cache/store.go这个文件。在IDE的帮助下,找到了所有实现了这个Store的相关实现。本文主要关心client-go,所以主要跟进client-go下面的相关实现。 delta_fifo.go NewDeltaFIFO() NewDeltaFIFOWithOptions() informer和sharedinformer使用到了 vendor/k8s.io/client-go/tools/cache/controller.go:NewInformer() vendor/k8s.io/client-go/tools/cache/shared_informer.go:sharedIndexInformer.Run() expiration_cache.go NewTTLStore() pkg/kubelet/util/cache/object_cache.go:NewObjectCache() NewExpirationStore() pkg/credentialprovider/aws/aws_credentials.go:newECRProvider() pkg/credentialprovider/azure/azure_credentials.go:NewACRProvider() fifo.go 该文件中定义了Queue接口,继承了Store,并且在该文件中通过FIFO实现了这个queue,另外一个实现是在delta_fifo.go中的DeltaFIFO NewFIFO() 代码中未找到该引用 index.go 这个文件定义了Indexer接口,继承了Store,在store.go中通过cache实现了该接口 store.go NewStore() staging/src/k8s.io/client-go/tools/cache/controller.go:NewInformer() staging/src/k8s.io/client-go/tools/cache/undelta_store.go:NewUndeltaStore() NewIndexer() staging/src/k8s.io/apiserver/pkg/storage/cacher/watch_cache.go:newWatchCache() staging/src/k8s.io/client-go/tools/cache/controller.go:NewIndexerInformer() staging/src/k8s.io/client-go/tools/cache/reflector.go:NewNamespaceKeyedIndexerAndReflector() 该函数在IDE中显示未被使用 staging/src/k8s.io/client-go/tools/cache/shared_informer.go:NewSharedIndexInformer() undelata_store.go NewUndeltaStore() pkg/kubelet/config/apiserver.go:newSourceApiserverFromLW() informer简要介绍 client-go中提供了普通informer和sharedInformer两种informer给我们使用。使用informer可以快速的构建各种资源的控制器,来对k8s进行扩展。informer提供了资源变化时执行回调的功能,可以在新增资源,修改资源和是删除资源时执行相应的控制器逻辑。 使用sharedInformer可以对同一个资源注册多个控制器,每个控制器独立执行自己的业务逻辑,互不干扰。多个控制器之间底层公用一个存储和一个到apiserver的连接,可以减少apiserver的压力的和本地内存的占用。informer则不具备这些能力,对于简单控制器可以使用informer,对于较复杂的控制器,会有针对同一个资源多个控制逻辑的推荐使用sharedInformer。 这两个informer在实现的复杂度上有很大差异,sharedInformer相对于普通informer来说要复杂的多。因此本文先从普通informer开始来进行分析,普通informer还分两种,一种是普通的informer,另外一种indexerinfomer。两种informer的区别在于前者使用Store作为对象存储,而后者采用Indexer作为对象存储,通过索引可以加快搜索。 普通informer分析 接下来我们以普通的informer进行分析,关于informer的使用可以参考这里。代码位于k8s.io/client-go/tools/cache/controller.go文件中,该文件中定义了Controller接口,并通过controller进行了实现。 controller分析 先看下接口定义以及controller包含的关键数据结构: // 这两个函数用来创建informer实例 func NewInformer(lw ListerWatcher, objType runtime.Object, resyncPeriod time.Duration, h ResourceEventHandler,) (Store, Controller) {} func NewIndexerInformer(lw ListerWatcher, objType…