原文链接:Kubernetes编写自定义controller

来自kubernetes官方github的一张图:

如图所示,图中的组件分为client-go和custom controller两部分:

  1. client-go部分

    • Reflector: 监视特定资源的k8s api, 把新监测的对象放入Delta Fifo队列,完成此操作的函数是ListAndWatch。
    • Informer: 从Delta Fifo队列拿出对象,完成此操作的函数是processLoop。
    • Indexer: 提供线程级别安全来存储对象和key。
  2. custom-controller部分

    • Informer reference: Informer对象引用
    • Indexer reference: Indexer对象引用
    • Resource Event Handlers: 被Informer调用的回调函数,这些函数的作用通常是获取对象的key,并把key放入Work queue,以进一步做处理。
    • Work queue: 工作队列,用于将对象的交付与其处理分离,编写Resource event handler functions以提取传递的对象的key并将其添加到工作队列。
    • Process Item: 用于处理Work queue中的对象,可以有一个或多个其他函数一起处理;这些函数通常使用Indexer reference或Listing wrapper来检索与该键对应的对象。

client-go官方代码例子

package main

import (
"flag"
"fmt"
"time" "k8s.io/klog" "k8s.io/api/core/v1"
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/util/workqueue"
) // 定义一个结构体Controller
type Controller struct {
indexer cache.Indexer
queue workqueue.RateLimitingInterface
informer cache.Controller
} // 获取controller的函数
func NewController(queue workqueue.RateLimitingInterface, indexer cache.Indexer, informer cache.Controller) *Controller {
return &Controller{
informer: informer,
indexer: indexer,
queue: queue,
}
} // 处理workqueue中的对象
func (c *Controller) processNextItem() bool {
// Wait until there is a new item in the working queue
key, quit := c.queue.Get()
if quit {
return false
}
// Tell the queue that we are done with processing this key. This unblocks the key for other workers
// This allows safe parallel processing because two pods with the same key are never processed in
// parallel.
defer c.queue.Done(key) // Invoke the method containing the business logic
err := c.syncToStdout(key.(string))
// Handle the error if something went wrong during the execution of the business logic
c.handleErr(err, key)
return true
} // syncToStdout is the business logic of the controller. In this controller it simply prints
// information about the pod to stdout. In case an error happened, it has to simply return the error.
// The retry logic should not be part of the business logic.
func (c *Controller) syncToStdout(key string) error {
obj, exists, err := c.indexer.GetByKey(key)
if err != nil { klog.Errorf("Fetching object with key %s from store failed with %v", key, err)
return err
} if !exists { // Below we will warm up our cache with a Pod, so that we will see a delete for one pod
fmt.Printf("Pod %s does not exist anymore\n", key)
} else {
// Note that you also have to check the uid if you have a local controlled resource, which
// is dependent on the actual instance, to detect that a Pod was recreated with the same name
fmt.Printf("Sync/Add/Update for Pod %s\n", obj.(*v1.Pod).GetName())
}
return nil
} // handleErr checks if an error happened and makes sure we will retry later.
func (c *Controller) handleErr(err error, key interface{}) {
if err == nil {
// Forget about the #AddRateLimited history of the key on every successful synchronization.
// This ensures that future processing of updates for this key is not delayed because of
// an outdated error history.
c.queue.Forget(key)
return
} // This controller retries 5 times if something goes wrong. After that, it stops trying.
if c.queue.NumRequeues(key) < {
klog.Infof("Error syncing pod %v: %v", key, err) // Re-enqueue the key rate limited. Based on the rate limiter on the
// queue and the re-enqueue history, the key will be processed later again.
c.queue.AddRateLimited(key)
return
} c.queue.Forget(key)
// Report to an external entity that, even after several retries, we could not successfully process this key
runtime.HandleError(err)
klog.Infof("Dropping pod %q out of the queue: %v", key, err)
} func (c *Controller) Run(threadiness int, stopCh chan struct{}) {
defer runtime.HandleCrash() // Let the workers stop when we are done
defer c.queue.ShutDown()
klog.Info("Starting Pod controller") go c.informer.Run(stopCh) // Wait for all involved caches to be synced, before processing items from the queue is started
if !cache.WaitForCacheSync(stopCh, c.informer.HasSynced) { runtime.HandleError(fmt.Errorf("Timed out waiting for caches to sync"))
return
} for i := ; i < threadiness; i++ {
go wait.Until(c.runWorker, time.Second, stopCh)
} <-stopCh
klog.Info("Stopping Pod controller")
} func (c *Controller) runWorker() {
for c.processNextItem() {
}
} func main() {
var kubeconfig string
var master string // 指定kubeconfig文件
flag.StringVar(&kubeconfig, "kubeconfig", "", "absolute path to the kubeconfig file")
flag.StringVar(&master, "master", "", "master url")
flag.Parse() // creates the connection
config, err := clientcmd.BuildConfigFromFlags(master, kubeconfig)
if err != nil { klog.Fatal(err)
} // creates the clientset
clientset, err := kubernetes.NewForConfig(config)
if err != nil { klog.Fatal(err)
} // create the pod watcher
podListWatcher := cache.NewListWatchFromClient(clientset.CoreV1().RESTClient(), "pods", v1.NamespaceDefault, fields.Everything()) // create the workqueue
queue := workqueue.NewRateLimitingQueue(workqueue.DefaultControllerRateLimiter()) // Bind the workqueue to a cache with the help of an informer. This way we make sure that
// whenever the cache is updated, the pod key is added to the workqueue.
// Note that when we finally process the item from the workqueue, we might see a newer version
// of the Pod than the version which was responsible for triggering the update.
indexer, informer := cache.NewIndexerInformer(podListWatcher, &v1.Pod{}, , cache.ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) {
key, err := cache.MetaNamespaceKeyFunc(obj)
if err == nil {
queue.Add(key)
}
},
UpdateFunc: func(old interface{}, new interface{}) {
key, err := cache.MetaNamespaceKeyFunc(new)
if err == nil {
queue.Add(key)
}
},
DeleteFunc: func(obj interface{}) {
// IndexerInformer uses a delta queue, therefore for deletes we have to use this
// key function.
key, err := cache.DeletionHandlingMetaNamespaceKeyFunc(obj)
if err == nil {
queue.Add(key)
}
},
}, cache.Indexers{}) controller := NewController(queue, indexer, informer) // We can now warm up the cache for initial synchronization.
// Let's suppose that we knew about a pod "mypod" on our last run, therefore add it to the cache. // If this pod is not there anymore, the controller will be notified about the removal after the // cache has synchronized. indexer.Add(&v1.Pod{ ObjectMeta: meta_v1.ObjectMeta{ Name: "mypod", Namespace: v1.NamespaceDefault, }, }) // Now let's start the controller
stop := make(chan struct{})
defer close(stop)
go controller.Run(, stop) // Wait forever
select {}
}

Kubernetes 编写自定义 controller的更多相关文章

  1. k8s自定义controller设计与实现

    k8s自定义controller设计与实现 创建CRD 登录可以执行kubectl命令的机器,创建student.yaml apiVersion: apiextensions.k8s.io/v1bet ...

  2. 用mel编写自定义节点的属性编辑器界面

    用mel编写自定义节点的属性编辑器界面比较麻烦,而且网上例子又少,下面给出一个范例,说明基本的格式 // 初始化节点时调用 global proc initControl(string $attrNa ...

  3. MVC自定义过滤器,自定义Area过滤器,自定义Controller,Action甚至是ViewData过滤器

    实现MVC自定义过滤器,自定义Area过滤器,自定义Controller,Action甚至是ViewData过滤器 MVC开发中几种以AOP方式实现的Filters是非常好用的,默认情况下,我们通过A ...

  4. django “如何”系列4:如何编写自定义模板标签和过滤器

    django的模板系统自带了一系列的内建标签和过滤器,一般情况下可以满足你的要求,如果觉得需更精准的模板标签或者过滤器,你可以自己编写模板标签和过滤器,然后使用{% load %}标签使用他们. 代码 ...

  5. RobotFramework自动化测试框架-使用Python编写自定义的RobotFramework Lib

    使用Python构建Lib工程 可以用来开发Python Lib的IDE工具有很多,常见的有Pycharm,Eclipse with PyDev插件等,而且在RobotFramework官网中也已经提 ...

  6. SpringBoot编写自定义的starter 专题

    What’s in a name All official starters follow a similar naming pattern; spring-boot-starter-*, where ...

  7. kubernetes nginx ingress controller部署

    Kubernetes nginx ingress controller部署 1.下载kubernetes nginx的yaml文件 Wget https://raw.githubusercontent ...

  8. SpringBoot编写自定义配置信息

    ⒈编写自定义配置类 1.浏览器配置 package cn.coreqi.security.properties; public class BrowserProperties { private St ...

  9. R语言-编写自定义函数 ZZ

    一.函数构造器 每一个R函数都包括三个部分:函数名,程序主体以及参数集合,在编写自定义R函数时,需要将三个部分各自储存在一个R对象中.这里需要使用function函数,形如: my_function& ...

随机推荐

  1. pycharm 退出虚拟环境

    pycharm 内置虚拟环境 venv 如果要退出就直接 deactivate 命令就行 运行的话直接在命令行输python3  文件名

  2. spring 循环依赖的一次 理解

    前言: 在看spring 循环依赖的问题中,知道原理,网上一堆的资料有讲原理. 但今天在看代码过程中,又产生了疑问. 疑问点如下: // 疑问点: 先进行 dependon 判断String[] de ...

  3. 获取全部 txt 文本中出现次数最多的前N个词汇

    1.使用 chain 对 allwords 二维列表进行解包 from itertools import chain allwords = [] allwords.append(列表) 解包: cha ...

  4. Python time gmtime()方法

    描述 Python time gmtime() 函数将一个时间戳转换为UTC时区(0时区)的struct_time,高佣联盟 www.cgewang.com 可选的参数sec表示从1970-1-1以来 ...

  5. 2020牛客暑期多校训练营 第二场 B Boundary 计算几何 圆 已知三点求圆心

    LINK:Boundary 计算几何确实是弱项 因为好多东西都不太会求 没有到很精通的地步. 做法很多,先说官方题解 其实就是枚举一个点 P 然后可以发现 再枚举一个点 然后再判断有多少个点在圆上显然 ...

  6. 3.29省选模拟赛 除法与取模 dp+组合计数

    LINK:除法与取模 鬼题.不过50分很好写.考虑不带除法的时候 其实是一个dp的组合计数. 考虑带除法的时候需要状压一下除法操作. 因为除法操作是不受x的大小影响的 所以要状压这个除法操作. 直接采 ...

  7. Python selenium 三种消息框处理和浏览器(页面跳转)句柄处理

    1. alert: 警告框,只是一个提示信息,只有一个确定按钮,起提示用户的作用: 2.confirm: 确认框,确定和取消按钮会带来不同的结果.点击确定会执行操作,点击取消按钮会取消操作: 3.pr ...

  8. 安装Hive 使用beeline 链接 出现 User: AAA is not allowed to impersonate BBB

    AAA 指的是 hdfs 文件系统的用户 BBB 是hive 设置的 hiveserver2 配置文件中的登陆用户名 在hadoop 配置如下 <property> <name> ...

  9. 实验09——java基于TCP实现客户端与服务端通信

    TCP通信         需要先创建连接 - 并且在创建连接的过程中 需要经过三次握手        底层通过 流 发送数据 数据没有大小限制        可靠的传输机制 - 丢包重发 包的顺序的 ...

  10. java交换两个参数值的四种方法

    第一种:添加中间变量,算是最经典最简易的一种了. //添加一个中间变量 int x = 1, y = 2; int z; z = x;x = y;y = z; System.out.println(x ...