Kubernetes Events虽不常被提起,却意义非凡。它存储在Etcd里,记录了集群运行所遇到的各种大事件。本系列文章将一步一步地揭开Kubernetes Events的神秘面纱。

师出有名

前些天群里有位同学(@二东)提问说怎么通过API得到kubectl describe pod的结果,我立刻找到了Kubernetes相关的API并回复他,但他说这不是他要的东西。经过一番描述,我才了解到他想要的是原来如下图中红框里的信息:

Message属于Kubernetes的一种特殊的资源:Events。老实讲,我以前是没有怎么注意过这个Events是怎么来的,甚至一直觉得它应该是Pod的一部分。那么这个Events到底是什么样的资源?它从何而来?下面随我一起踏上捉妖之路。

真身难觅

熟悉Kubernetes的小伙伴应该对于它的资源比较有体会,作为调度基本单元的Pod是一种资源,控制Pod更新、扩容、副本数量的ReplicaSet是一种资源,作为发布单位的Deployment也是一种资源,哦,还有Service,Endpoints等等。它们有这么一些共同点:

  • 都可以通过kubectl get $ResourceName的方式获取
  • 都有对应的RESTful API定义的操作

Events亦如此,kubectl get events的结果为下图:

就像kubectl get pods一样,通过kubectl get events获得当前命名空间下所有Events的列表。如果想查看某条Events的详细信息,是否也可以使用kubectl describe events $EventsName进行获取呢?我尝试了下,得到了下面的失败信息:

甚至连kubectl get events $EventsName也变得没那么好使了:

另外,Events的RESTful API为下图:

而通过最朴素的curl 之刃也没能找出Events的真身:

这着实让人“大吃一斤”。

踏破铁鞋

那么这个Events到底是何方神圣?常规手段居然拿它没一丁点办法了?不,还有一招json宝典待我祭出使用。我们知道kubectl get一些资源的时候可以通过它的-o json参数得到该资源的json格式的信息描述,那么对上面的Events进行kubectl get events -o json > /tmp/events.json,得到了一个json数组,里面的每一条都对应着一个Events对象:

Bingo!这就是我们要找的Events对应的实体json。仔细观察,图中红框里的名字正是kubectl get events里得到的Events名字,然而实际上它并不是真正的Events的名字。这是为何?在Kubernetes资源的数据结构定义中,一般都会包含一个metav1.TypeMeta和一个ObjectMeta成员,比如:

TypeMeta里定义了该资源的类别和版本,对应我们平时写json文件或者yaml文件时的kind: Pod和apiVersion: v1。OjbectMeta里定义了该资源的元信息,包括名称、命名空间、UID、创建时间、标签组等。

Events的数据结构定义里同样包含了metav1.TypeMeta和ObjectMeta,那么从前面的json图中可以确定红框里的名字并不是该Events对象的真实名字,它对应的是InvolvedObject的名字,而蓝框里对应的才是Events的真实名字。然后使用kubectl get和curl进行验证:

到此,我们已经探明了Events的真名。仔细观察它的名字,发现它由三部分构成:”发生该Events的Pod名称” + “.” + “神秘数字串”。发生该Events的Pod名称倒是好理解,而后面的神秘数字串却不知从何而来。既然这个Events是来自这个Pod的状态变化,那么想必这个数字串也可以在Pod的详情里找到吧。出乎意料的是在Pod的详情json未曾找到这个神秘数字串,甚至把这个Pod祖上的ReplicaSet和Deployment也翻了个底朝天也是没有一点线索。捉妖行动陷入僵局。

星宿Kubelet

道高一尺,魔高一丈。纵使齐天大圣也得经常搬救兵,而不少时候这个妖怪就是某个星宿的坐骑或童子。拿起这个Events的json仔细观察,发现里面有个不起眼的component: kubelet:

回想一下kubelet的作用是:负责管理和维护在这台主机上运行着的所有容器,维持pod的运行状态(status)和它的期望值(spec)一致。kubelet启动时,会加载它本身的配置信息、接入容器运行时(Docker或Rkt)、以及定义kubelet与整个集群进行交互所需的信息。在启动后,会进行一系列的初始化工作,创建ContainerManager、设置OOMScoreAdj值、创建DiskSpaceManager、PodManager等等。那么会不会是kubelet为这个Pod创建了该Events呢?

为了解答这个问题,不得不拿出尘封已久的究极“源码大法”。

果然在Kubernetes源码的kubernetes/pkg/kubelet/events/event.go里有了一些收获。event.go里定义了是Events资源常用的一些常量,挑选列出如下:

const (
FailedToStartContainer = “Failed”
BackOffStartContainer = “BackOff”
ErrImageNeverPullPolicy = “ErrImageNeverPull”
BackOffPullImage = “BackOff”
FailedSync = “FailedSync”

)

这里面的不少我们平时都会经常遇到。它们是各种事件的原因列表,包含容器事件(创建、启动、失败等)、镜像事件(镜像拉取失败等)、kubelet事件(节点失效、节点不可调度等)、Pod Worker事件(同步失败)等。随便拿出一条进行暴力搜寻,比如”FailedToStartContainer”,发现除了在此处的定义进行了引用外,还在kubernetes/pkg/kubelet/dockertools/docker_manager.go里711行进行了引用:

dm.recorder.Eventf(ref, api.EventTypeWarning, events.FailedToStartContainer, “Failed to start container with docker id %v with error: %v”, utilstrings.ShortenString(createResp.ID, 12), err)

由此更加确认的是Events跟Kubelet密不可分。循着这条线索一直往下,还会有什么惊奇的发现?

火眼金睛

上面引用了docker_manager.go里的一行,除开事件本身外,里面还有一些关键词值得琢磨:dm, recorder, Eventf。

dm是结构体DockerManager的实例,该结构体定义也在这个文件中。定义比较长,这里就不贴出来了,它包含了DockerInterface的成员、EventRecorder的成员、OSInterface的成员以及cadvisorapi.MachineInfo的成员等等。这个EventRecorder的定义在k8s.io/kubernetes/pkg/client/record/event.go里,是一个接口,可以按照EventSource的表现记录相应的事件。
type EventRecorder interface {
Event(object runtime.Object, eventtype, reason, message string)
Eventf(object runtime.Object, eventtype, reason, messageFmt string, args …interface{})
PastEventf(object runtime.Object, timestamp unversioned.Time, eventtype, reason, messageFmt string, args …interface{})
}

在这个文件的285~295行有对这个三个接口的实现:

func (recorder *recorderImpl) Event(object runtime.Object, eventtype, reason, message string) {
recorder.generateEvent(object, unversioned.Now(), eventtype, reason, message)
}
func (recorder *recorderImpl) Eventf(object runtime.Object, eventtype, reason, messageFmt string, args …interface{}) {
recorder.Event(object, eventtype, reason, fmt.Sprintf(messageFmt, args…))
}
func (recorder *recorderImpl) PastEventf(object runtime.Object, timestamp unversioned.Time, eventtype, reason, messageFmt string, args …interface{}) {
recorder.generateEvent(object, timestamp, eventtype, reason, fmt.Sprintf(messageFmt, args…))
}

不管是PastEventf()、Eventf()还是Event()最终都指向了辅助函数generateEvent(),它的实现在255行:

func (recorder *recorderImpl) generateEvent(object runtime.Object, timestamp unversioned.Time, eventtype, reason, message string) { // 获取发生事件的对象,比如前面说到的Pod
ref, err := api.GetReference(object) if err != nil {
glog.Errorf(“Could not construct reference to: ‘%#v’ due to: ‘%v’. Will not report event: ‘%v’ ‘%v’ ‘%v'”, object, err, eventtype, reason, message) return
}
// 验证事件类型
if !validateEventType(eventtype) {
glog.Errorf(“Unsupported event type: ‘%v'”, eventtype) return
}
// 生成Event
event := recorder.makeEvent(ref, eventtype, reason, message)
event.Source = recorder.source

go func() {
// NOTE: events should be a non-blocking operation
defer utilruntime.HandleCrash()
// 将Event进行广播
recorder.Action(watch.Added, event)
}()
}

recorder.makeEvent()就是这个Events的真正来源:

func (recorder *recorderImpl) makeEvent(ref *api.ObjectReference, eventtype, reason, message string) *api.Event { t := unversioned.Time{Time: recorder.clock.Now()} namespace := ref.Namespace
if namespace == “” {
namespace = api.NamespaceDefault
}
return &api.Event{
ObjectMeta: api.ObjectMeta{
// 事件的命名规则
Name: fmt.Sprintf(“%v.%x”, ref.Name, t.UnixNano()),
Namespace: namespace,
},
InvolvedObject: *ref,
Reason: reason,
Message: message,
FirstTimestamp: t,
LastTimestamp: t,
Count: 1,
Type: eventtype,
}
}

到此恍然大悟,原来前面所说的Events的命名规则:”发生该Events的Pod名称” + “.” + “神秘数字串”实际上是”ref.Name” + “.” + “t.UnixNano())”。

终于找到了Events的真身,原来它是Kubelet负责用来记录多个容器运行过程中的事件,命名由被记录的对象和时间戳构成。前面看起来难以捉摸的表现最终还是逃不过火眼金睛。到此上篇解决了Events从哪儿来的问题,暂告一段落。在下篇中将对Events关于到哪儿去、怎么根据Pod找到对应的Events等进行深度拷问。欢迎继续关注!

本文中出现的curl 之刃、json宝典、源码大法均属于为了轻松阅读体验而凭空捏造的词汇,分别对应用命令行工具curl进行访问和实验、查看该对象的json信息、阅读源码寻找答案释疑。

来源:Kubernetes(K8s)Events介绍(上)

Kubernetes(K8s)Events介绍(上)相关推荐

  1. kubernetes(k8s)全面介绍

    kubernetes简介 Kubernetes(简称k8s)是Google在2014年6月开源的一个容器集群管理系统,使用Go语言开发,用于管理云平台中多个主机上的容器化的应用,Kubernetes的 ...

  2. 学习笔记之-Kubernetes(K8S)介绍,集群环境搭建,Pod详解,Pod控制器详解,Service详解,数据存储,安全认证,DashBoard

    笔记来源于观看黑马程序员Kubernetes(K8S)教程 第一章 kubernetes介绍 应用部署方式演变 在部署应用程序的方式上,主要经历了三个时代: 传统部署:互联网早期,会直接将应用程序部署 ...

  3. kubernetes(k8s)-介绍2

    kubernetes(k8s)-安装(二) 什么是Kubernetes Kubernetes是一个开源平台,用于跨主机群集自动部署,扩展和操作应用程序容器,提供以容器为中心的基础架构. 使用Kuber ...

  4. Kubernetes Events介绍(下)

    https://www.kubernetes.org.cn/1195.html 经过前两回的"踏血寻妖",一个完整的Events原形逐渐浮出水面.我们已经摸清了它的由来和身世,本回 ...

  5. 【kubernetes/k8s概念】Kubernetes1.12从零开始(初):课程介绍与官方文档汇总

    说明 资料和交流方式 Kubernetes的文档介绍 Kubernetes中的术语与资源的操作方法 Kubernetes的API约定与启用方法 Kubernetes中资源(Object)的定义 kub ...

  6. Kubernetes集群(k8s)- 介绍和部署

    目录 1. Kubernetes简介 1. k8s 1.2 Kubernetes的好处 1.3 kubernetes设计架构 1.4 kubernetes设计架构(2) 2. Kubernetes集群 ...

  7. Kubernetes(k8s)从入门到精通

    Kubernetes Kubernetes介绍 1.1 应用部署方式演变 在部署应用程序的方式上,主要经历了三个时代: 传统部署:互联网早期,会直接将应用程序部署在物理机上 优点:简单,不需要其它技术 ...

  8. Kubernetes K8S之存储Volume详解

    K8S之存储Volume概述与说明,并详解常用Volume示例 主机配置规划 服务器名称(hostname) 系统版本 配置 内网IP 外网IP(模拟) k8s-master CentOS7.7 2C ...

  9. Kubernetes ~ k8s 从入门到入坑。

    Kubernetes ~ k8s 从入门到入坑. 文章目录 Kubernetes ~ k8s 从入门到入坑. 1. Kubernetes 介绍. 1.1 应用部署方式演变. 1.2 kubernete ...

最新文章

  1. 1.IocDI和Spring
  2. dialog监听点击空白关闭_为什么App Store打开一片空白?尝试这样解决
  3. cs怎么加电脑人_怎么给电脑文件夹加密码?
  4. java返回值变为文件_Java 文件操作-File
  5. 肝!一文讲解JWT用户认证全过程
  6. Oracle 中使用 fetch bulk collect into 批量效率的读取游标数据
  7. [Java基础]IO流小结
  8. 图片预览------photoswipe 使用
  9. iphone彻底删除照片如何恢复_苹果手机删除的照片如何恢复
  10. springmvc web.xml和application.xml配置详情(附:完整版pom.xml)
  11. 考研南邮和杨大计算机,江苏省这4所“非211”低调有实力,从不争名次,毕业生颇受欢迎...
  12. EK算法(网络流,最大流)
  13. FineBI 的登录锁定配置修改
  14. android下载文件地址,安卓迅雷下载的文件在哪里迅雷下载文件存放位置-独木成林...
  15. 股票涨跌的心理学原理: 过度反应理论
  16. 唯美首页纯静态html引导页
  17. 【概率论与数理统计】猴博士 笔记 p36-37 协方差、相关系数、不相关、相互独立时的期望和方差
  18. 网页调用 iOS/Android 客户端
  19. 低学历转行3D建模有前途吗,游戏3D建模怎么样?
  20. 表单数据序列化之serialize()、serializeArray()方法的使用

热门文章

  1. contiki学习笔记(八)rtimer stimer 计时器库
  2. Anker—学习成长笔记
  3. 天使的微笑——《天使爱美丽》
  4. 基于SSM抑郁症自检测及初级自治疗网站的设计实现
  5. vue报错[wds] disconnected
  6. 前端,通过面试去学习,开放问题(个人对前端发展的理解、项目难点、项目亮点、最复杂的逻辑、团队协作冲突问题、HR面试问题)
  7. Java第一周练习题
  8. Python实现--使用微信定时每天和女友发送定制消息(附代码教程)
  9. 自动化情侣微信早安信息定时推送
  10. 处理WIN7任务栏通知区域图标异常问题