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. Linux---远程连接、命令行基础、文件及目录管理

    远程连接管理Linux实践(centos) 连接小知识 IP地址:访问连接服务器,需要通过服务器的IP地址来实现,服务器的IP地址就相当于服务器的具体地址.一计算机都会有一个唯一的32位的IP地址,8 ...

  2. nginx配置后端映射(反向代理proxy_pass)

    说明:配置反向代理proxy_pass和location无关,location后面加不加 / 都可以 1.配置 proxy_pass 时,当在后面的 url 加上了 /,相当于是绝对路径,则 Ngin ...

  3. 【图文教学】如何轻松下载tiktok上的视频

    我是真诚的想和大家分享这个办法的!这个叫光影存图,图标就是这个绿色的箭头,我是苹果手机,安卓手机也可以用,就是它分免费版和会员版的,没有强制要你充会员,看一下广告就可以获取下载次数,我就是这么干的,只 ...

  4. 内网穿透NPS

    内网穿透实现 nps文档 https://ehang-io.github.io/nps/#/install nps docker镜像 https://hub.docker.com/r/ffdfgdfg ...

  5. ASP.NET Core WebApi返回结果统一包装实践

    前言 近期在重新搭建一套基于ASP.NET Core WebAPI的框架,这其中确实带来了不少的收获,毕竟当你想搭建一套框架的时候,你总会不自觉的去想,如何让这套框架变得更完善一点更好用一点.其中在关 ...

  6. 整理display:none;和visibility:hidden;和overflow:hidden;的区别

    1.display:none;  这个属性隐藏元素,不占网页任何空间,彻底隐藏,消失 2.visibility:hidden;  占据空间,但是无法点击.隐藏了这个层,看不到,却能摸得着 3.over ...

  7. XCTF练习题---MISC---Test-flag-please-ignore

    XCTF练习题---MISC---Test-flag-please-ignore flag:flag{hello_world} 解题步骤: 1.观察题目,下载附件 2.打开文件,发现又是一个没有名字的 ...

  8. 使用 Vert.X Future/Promise 编写异步代码

    Future 和 Promise 是 Vert.X 4.0中的重要角色,贯穿了整个 Vert.X 框架.掌握 Future/Promise 的用法,是用好 Vert.X.编写高质量异步代码的基础.本文 ...

  9. 一文搞懂CDN加速原理

    开源Linux 长按二维码加关注~ 一.什么是 CDN CDN的全称是(Content Delivery Network),即内容分发网络.其目的是通过在现有的Internet中增加一层新的CACHE ...

  10. 2022年5月11日,NBMiner发布了41.3版本,在内核中加入了100%LHR解锁器,从此NVIDIA的显卡再无锁卡一说

           2022年5月11日,NBMiner发布NBMiner_41.3版本,主要提升了稳定性.         2022年5月8日,NBMiner发布NBMiner_41.0版本,在最新的内核 ...