编写一个kubernetes controller
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
编写一个kubernetes controller的更多相关文章
- kubernetes controller 实现
对于kubernetes中不存在的资源类型,我们可以通过自定义资源的方式进行扩展,首先创建customresourcedefinition对象定义资源及其schema,然后就可以创建自定义的资源了,但 ...
- .NET Core RC2发布在即,我们试着用记事本编写一个ASP.NET Core RC2 MVC程序
在.NET Core 1.0.0 RC2即将正式发布之际,我也应应景,针对RC2 Preview版本编写一个史上最简单的MVC应用.由于VS 2015目前尚不支持,VS Code的智能感知尚欠火候,所 ...
- 从头开始编写一个Orchard网上商店模块(6) - 创建购物车服务和控制器
原文地址: http://skywalkersoftwaredevelopment.net/blog/writing-an-orchard-webshop-module-from-scratch-pa ...
- SpringMVC入门--编写一个SpringMVC小程序
一.SpringMVC的优势 Spring 为展现层提供的基于 MVC 设计理念的优秀的Web 框架,是目前最主流的 MVC 框架之一.Spring3.0 后全面超越 Struts2,成为最优秀的 M ...
- JAVA WEB快速入门之从编写一个基于SpringBoot+Mybatis快速创建的REST API项目了解SpringBoot、SpringMVC REST API、Mybatis等相关知识
JAVA WEB快速入门系列之前的相关文章如下:(文章全部本人[梦在旅途原创],文中内容可能部份图片.代码参照网上资源) 第一篇:JAVA WEB快速入门之环境搭建 第二篇:JAVA WEB快速入门之 ...
- K8S学习笔记之二进制的方式创建一个Kubernetes集群
0x00 单节点搭建和简述 minikube Minikube是一个工具,可以在本地快速运行一个单点的Kubernetes,尝试Kubernetes或日常开发的用户使用.不能用于生产环境. 官方地址: ...
- Kubernetes 学习笔记(二):本地部署一个 kubernetes 集群
前言 前面用到过的 minikube 只是一个单节点的 k8s 集群,这对于学习而言是不够的.我们需要有一个多节点集群,才能用到各种调度/监控功能.而且单节点只能是一个加引号的"集群&quo ...
- 编写一个通用的Makefile文件
1.1在这之前,我们需要了解程序的编译过程 a.预处理:检查语法错误,展开宏,包含头文件等 b.编译:*.c-->*.S c.汇编:*.S-->*.o d.链接:.o +库文件=*.exe ...
- CSharpGL(34)以从零编写一个KleinBottle渲染器为例学习如何使用CSharpGL
CSharpGL(34)以从零编写一个KleinBottle渲染器为例学习如何使用CSharpGL +BIT祝威+悄悄在此留下版了个权的信息说: 开始 本文用step by step的方式,讲述如何使 ...
随机推荐
- 查看k8s的yaml里面反馈的错误,不仅仅是通过日志来查看错误
使用:kubectl describe pod......例如: kubectl describe pod api-55f5d8d49d-kzmcj ///////////////////////// ...
- iperf/LANSpeedTest网络传输速度测试工具
最近公司测试限速,搜集软件发现两款,iperf,LANSpeedTest. iperf,多平台. LANSpeedTest,读写显示,操作简单. 局域网测试传输,优先考虑UDP. iperf Iper ...
- MySQL事务提交流程详解
MySQL事务的提交采用两阶段提交协议, 前些日子和同事聊的时候发现对提交的细节还是有些模糊,这里对照MySQL源码详细记录一下,版本是MySQL5.7.36. 一. 事务的提交流程. 1. 获取 M ...
- Hoo Smart Chain 万物生长计划火热报名中,可视化公链迸发勃勃生机
在DeFi越来越趋向同质化和静态化时,Hoo Smart Chain决定充当破局者,宣布决定All In元宇宙,并于2022年3月份开启面向全球去中心化开发者的奖励计划--「万物生长计划」 目前Ter ...
- Java语言学习day35--8月10日
今日内容介绍1.集合2.Iterator迭代器3.增强for循环4.泛型 ###01集合使用的回顾 *A:集合使用的回顾 *a.ArrayList集合存储5个int类型元素 public static ...
- 小程序开发之获取客户来源 scene 场景值 手机设备信息
为什么要获取客户来源 用作数据分析,根据客户来源,做精准转化! 判断客户来源入口方式 1.通过官方的scene场景值 常见场景值 场景值ID 说明 1001 发现栏小程序主入口,「最近使用」列表 10 ...
- Azure DevOps (十一) 通过Azure Devops部署一个.NET Core WebAPI
前几篇文章中,我们讨论了如何通过流水线实现项目的编译.上传.打包.部署等操作,今天我们来实现一套完整的流程,把之前碎片化的知识点给串起来. 本次我们使用一个ASP.NET Core的WebApi项目来 ...
- Redis 内存满了怎么办?这样设置才正确!
上回在<Redis 数据过期了会被立马删除么?>说到如果过期的数据太多,定时删除无法删除完全(每次删除完过期的 key 还是超过 25%),同时这些 key 再也不会被客户端请求,就无法走 ...
- XCTF练习题---CRYPTO---wtc_rsa_bbq
XCTF练习题---CRYPTO---wtc_rsa_bbq flag:flag{how_d0_you_7urn_this_0n?} 解题步骤: 1.观察题目,下载附件 2.下载后是一个文件,不清楚格 ...
- 研讨会回放视频:如何提升Jenkins能力,使其成为真正的DevOps平台
"如何实现集中管理.灵活高效的CI/CD"在线研讨会精彩分享 演讲嘉宾:杨海涛 在2022年3月29日举办的"如何实现集中管理.灵活高效的CI/CD"在线研讨会 ...