Overview

根据Kuberneter文档对Controller的描述,Controller在kubernetes中是负责协调的组件,根据设计模式可知,controller会不断的你的对象(如Pod)从当前状态与期望状态同步的一个过程。当然Controller会监听你的实际状态与期望状态。

Writing Controllers

package main

import (
"flag"
"fmt"
"os"
"time" v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/fields"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/util/homedir"
"k8s.io/client-go/util/workqueue"
"k8s.io/klog"
) type Controller struct {
lister cache.Indexer
controller cache.Controller
queue workqueue.RateLimitingInterface
} func NewController(lister cache.Indexer, controller cache.Controller, queue workqueue.RateLimitingInterface) *Controller {
return &Controller{
lister: lister,
controller: controller,
queue: queue,
}
} func (c *Controller) processItem() bool {
item, quit := c.queue.Get()
if quit {
return false
}
defer c.queue.Done(item)
fmt.Println(item)
err := c.processWrapper(item.(string))
if err != nil {
c.handleError(item.(string))
}
return true
} func (c *Controller) handleError(key string) { if c.queue.NumRequeues(key) < 3 {
c.queue.AddRateLimited(key)
return
}
c.queue.Forget(key)
klog.Infof("Drop Object %s in queue", key)
} func (c *Controller) processWrapper(key string) error {
item, exists, err := c.lister.GetByKey(key)
if err != nil {
klog.Error(err)
return err
}
if !exists {
klog.Info(fmt.Sprintf("item %v not exists in cache.\n", item))
} else {
fmt.Println(item.(*v1.Pod).GetName())
}
return err
} func (c *Controller) Run(threadiness int, stopCh chan struct{}) {
defer utilruntime.HandleCrash()
defer c.queue.ShutDown()
klog.Infof("Starting custom controller") go c.controller.Run(stopCh) if !cache.WaitForCacheSync(stopCh, c.controller.HasSynced) {
utilruntime.HandleError(fmt.Errorf("sync failed."))
return
} for i := 0; i < threadiness; i++ {
go wait.Until(func() {
for c.processItem() {
}
}, time.Second, stopCh)
}
<-stopCh
klog.Info("Stopping custom controller")
} func main() {
var (
k8sconfig *string //使用kubeconfig配置文件进行集群权限认证
restConfig *rest.Config
err error
)
if home := homedir.HomeDir(); home != "" {
k8sconfig = flag.String("kubeconfig", fmt.Sprintf("%s/.kube/config", home), "kubernetes auth config")
}
k8sconfig = k8sconfig
flag.Parse()
if _, err := os.Stat(*k8sconfig); err != nil {
panic(err)
} if restConfig, err = rest.InClusterConfig(); err != nil {
// 这里是从masterUrl 或者 kubeconfig传入集群的信息,两者选一
restConfig, err = clientcmd.BuildConfigFromFlags("", *k8sconfig)
if err != nil {
panic(err)
}
}
restset, err := kubernetes.NewForConfig(restConfig)
lister := cache.NewListWatchFromClient(restset.CoreV1().RESTClient(), "pods", "default", fields.Everything())
queue := workqueue.NewRateLimitingQueue(workqueue.DefaultControllerRateLimiter())
indexer, controller := cache.NewIndexerInformer(lister, &v1.Pod{}, 0, cache.ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) {
fmt.Println("add ", obj.(*v1.Pod).GetName())
key, err := cache.MetaNamespaceKeyFunc(obj)
if err == nil {
queue.Add(key)
} },
UpdateFunc: func(oldObj, newObj interface{}) {
fmt.Println("update", newObj.(*v1.Pod).GetName())
if newObj.(*v1.Pod).Status.Conditions[0].Status == "True" {
fmt.Println("update: the Initialized Status", newObj.(*v1.Pod).Status.Conditions[0].Status)
} else {
fmt.Println("update: the Initialized Status ", newObj.(*v1.Pod).Status.Conditions[0].Status)
fmt.Println("update: the Initialized Reason ", newObj.(*v1.Pod).Status.Conditions[0].Reason)
} if len(newObj.(*v1.Pod).Status.Conditions) > 1 {
if newObj.(*v1.Pod).Status.Conditions[1].Status == "True" {
fmt.Println("update: the Ready Status", newObj.(*v1.Pod).Status.Conditions[1].Status)
} else {
fmt.Println("update: the Ready Status ", newObj.(*v1.Pod).Status.Conditions[1].Status)
fmt.Println("update: the Ready Reason ", newObj.(*v1.Pod).Status.Conditions[1].Reason)
} if newObj.(*v1.Pod).Status.Conditions[2].Status == "True" {
fmt.Println("update: the PodCondition Status", newObj.(*v1.Pod).Status.Conditions[2].Status)
} else {
fmt.Println("update: the PodCondition Status ", newObj.(*v1.Pod).Status.Conditions[2].Status)
fmt.Println("update: the PodCondition Reason ", newObj.(*v1.Pod).Status.Conditions[2].Reason)
} if newObj.(*v1.Pod).Status.Conditions[3].Status == "True" {
fmt.Println("update: the PodScheduled Status", newObj.(*v1.Pod).Status.Conditions[3].Status)
} else {
fmt.Println("update: the PodScheduled Status ", newObj.(*v1.Pod).Status.Conditions[3].Status)
fmt.Println("update: the PodScheduled Reason ", newObj.(*v1.Pod).Status.Conditions[3].Reason)
}
} },
DeleteFunc: func(obj interface{}) {
fmt.Println("delete ", obj.(*v1.Pod).GetName(), "Status ", obj.(*v1.Pod).Status.Phase)
// 上面是事件函数的处理,下面是对workqueue的操作
key, err := cache.MetaNamespaceKeyFunc(obj)
if err == nil {
queue.Add(key)
}
},
}, cache.Indexers{}) c := NewController(indexer, controller, queue)
stopCh := make(chan struct{})
stopCh1 := make(chan struct{})
c.Run(1, stopCh)
defer close(stopCh)
<-stopCh1
}

通过日志可以看出,Pod create后的步骤大概为4步:

  • Initialized:初始化好后状态为Pending
  • PodScheduled:然后调度
  • PodCondition
  • Ready
add  netbox
default/netbox
netbox
update netbox status Pending to Pending
update: the Initialized Status True
update netbox status Pending to Pending
update: the Initialized Status True
update: the Ready Status False
update: the Ready Reason ContainersNotReady
update: the PodCondition Status False
update: the PodCondition Reason ContainersNotReady
update: the PodScheduled Status True update netbox status Pending to Running
update: the Initialized Status True
update: the Ready Status True
update: the PodCondition Status True
update: the PodScheduled Status True

大致上与 kubectl describe pod 看到的内容页相似

default-scheduler  Successfully assigned default/netbox to master-machine
Normal Pulling 85s kubelet Pulling image "cylonchau/netbox"
Normal Pulled 30s kubelet Successfully pulled image "cylonchau/netbox"
Normal Created 30s kubelet Created container netbox
Normal Started 30s kubelet Started container netbox

Reference

controllers.md

编写一个kubernetes controller的更多相关文章

  1. kubernetes controller 实现

    对于kubernetes中不存在的资源类型,我们可以通过自定义资源的方式进行扩展,首先创建customresourcedefinition对象定义资源及其schema,然后就可以创建自定义的资源了,但 ...

  2. .NET Core RC2发布在即,我们试着用记事本编写一个ASP.NET Core RC2 MVC程序

    在.NET Core 1.0.0 RC2即将正式发布之际,我也应应景,针对RC2 Preview版本编写一个史上最简单的MVC应用.由于VS 2015目前尚不支持,VS Code的智能感知尚欠火候,所 ...

  3. 从头开始编写一个Orchard网上商店模块(6) - 创建购物车服务和控制器

    原文地址: http://skywalkersoftwaredevelopment.net/blog/writing-an-orchard-webshop-module-from-scratch-pa ...

  4. SpringMVC入门--编写一个SpringMVC小程序

    一.SpringMVC的优势 Spring 为展现层提供的基于 MVC 设计理念的优秀的Web 框架,是目前最主流的 MVC 框架之一.Spring3.0 后全面超越 Struts2,成为最优秀的 M ...

  5. JAVA WEB快速入门之从编写一个基于SpringBoot+Mybatis快速创建的REST API项目了解SpringBoot、SpringMVC REST API、Mybatis等相关知识

    JAVA WEB快速入门系列之前的相关文章如下:(文章全部本人[梦在旅途原创],文中内容可能部份图片.代码参照网上资源) 第一篇:JAVA WEB快速入门之环境搭建 第二篇:JAVA WEB快速入门之 ...

  6. K8S学习笔记之二进制的方式创建一个Kubernetes集群

    0x00 单节点搭建和简述 minikube Minikube是一个工具,可以在本地快速运行一个单点的Kubernetes,尝试Kubernetes或日常开发的用户使用.不能用于生产环境. 官方地址: ...

  7. Kubernetes 学习笔记(二):本地部署一个 kubernetes 集群

    前言 前面用到过的 minikube 只是一个单节点的 k8s 集群,这对于学习而言是不够的.我们需要有一个多节点集群,才能用到各种调度/监控功能.而且单节点只能是一个加引号的"集群&quo ...

  8. 编写一个通用的Makefile文件

    1.1在这之前,我们需要了解程序的编译过程 a.预处理:检查语法错误,展开宏,包含头文件等 b.编译:*.c-->*.S c.汇编:*.S-->*.o d.链接:.o +库文件=*.exe ...

  9. CSharpGL(34)以从零编写一个KleinBottle渲染器为例学习如何使用CSharpGL

    CSharpGL(34)以从零编写一个KleinBottle渲染器为例学习如何使用CSharpGL +BIT祝威+悄悄在此留下版了个权的信息说: 开始 本文用step by step的方式,讲述如何使 ...

随机推荐

  1. The 18th Zhejiang Provincial Collegiate Programming Contest

    The 18th Zhejiang Provincial Collegiate Programming Contest GYM链接 https://codeforces.com/gym/103055 ...

  2. Linux curl遇到错误curl: (3) Illegal characters found in URL

    服务器上执行一个脚本,在linux新建的sh,把本地编辑器的内容粘贴到文件里. 结果执行的时候报错了. 问题就是 curl:(3)Illegal characters found in URL 看着一 ...

  3. android软件简约记账app开发day04-记账页面条目的代码书写

    android软件简约记账app开发day04-记账页面条目的代码书写 在前三天我们完成了基本的界面展示,从今天开始,我们进入到后台逻辑代码的编写中,今天开发记账条目的代码 我们在主页面点击记一笔图标 ...

  4. 马里奥制造,Ready~~GO!「GitHub 热点速览 v.22.16」

    作者:HelloGitHub-小鱼干 如果你有创造力,就可以以马里奥 Mario 为主角在 a-little-game-called-mario 中开启你的 Hell 模式 Mario:如果你想贡献代 ...

  5. Bugku练习题---Web---计算器

    Bugku练习题---Web---计算器 flag:flag{8b4b2f83db2992d17d770be1db965147} 解题步骤: 1.观察题目,打开场景 2.场景打开后发现是一个验证码界面 ...

  6. XCTF练习题---MISC---功夫再高也怕菜刀

    XCTF练习题---MISC---功夫再高也怕菜刀 flag:flag{3OpWdJ-JP6FzK-koCMAK-VkfWBq-75Un2z} 解题步骤: 1.观察题目,下载附件 2.下载到电脑后发现 ...

  7. Django-ORM-连表正反操作

    一.A表男生,B表女生,C表关系 1通过A表查与某个男生有关系的所有女生 思想1:在A表中确认男生后,通过反查到C表,获取相关内容(QuerySet),然后再跨到B表获取所有女生信息. obj=mod ...

  8. VMware安装Ubuntu20(图文教程,超详细)

    VMware安装Ubuntu20(图文教程,超详细) 此文讲述使用 VMware 工具安装 Ubuntu 系列虚拟机,不同位数和不同版本的 Ubuntu 安装过程相差无几,这里以 Ubuntu20 6 ...

  9. NLP教程(3) | 神经网络与反向传播

    作者:韩信子@ShowMeAI 教程地址:http://www.showmeai.tech/tutorials/36 本文地址:http://www.showmeai.tech/article-det ...

  10. Go 语言快速开发入门

    目录 需求 开发的步骤 linux下如何开发Go程序 MAC下如何开发Go程序 Golang执行流程分析 编译和运行说明 Go程序开发的注意事项 Go语言的转义字符(escapechar) Golan ...