写点什么

从 Kubernetes 事件中提取价值

作者:玄月九
  • 2022 年 8 月 20 日
    上海
  • 本文字数:4104 字

    阅读完需:约 13 分钟

1. 前言

监控是保障系统稳定性的重要组成部分,在 Kubernetes 开源生态中,资源类的监控工具与组件百花齐放。除了社区自己孵化的 metrics-server,还有从 CNCF 毕业的 Prometheus 等等,可选的方案有很多。但是,只有资源类的监控是远远不够的,因为资源监控存在如下两个主要的缺点:


  • 资源监控的实时性与准确性不足

大部分资源监控都是基于推或者拉的模式进行数据离线,因此通常数据是每隔一段时间采集一次,如果在时间间隔内出现一些毛刺或者异常,而在下一个采集点到达时恢复,大部分的采集系统会吞掉这个异常。而针对毛刺的场景,阶段的采集会自动削峰,从而造成准确性的降低。


  • 资源监控的场景覆盖范围不足

部分监控场景是无法通过资源表述的,例如 Pod 的启动停止,是无法简单的用资源的利用率来计量的,因为当资源为 0 的时候,我们是不能区分这个状态产生的真实原因。


基于上述两个问题,Kubernetes 是怎么解决的呢?

为了让用户对 Kubernetes 的内部状态有更好的了解,Kubernetes 引入了事件(Events)系统,在 Kubernetes 的资源发生变化的时候,会以事件的形式记录在 APIServer 中,并可以通过 API 或者 kubectl 命令去查看。用户可以通过获取事件,实时诊断集群的异常与问题,及时的查看到一些容易被资源监控忽略的问题。

2. Kubernetes Events 介绍

2.1 Kubernetes Events 是什么

Kubernetes Events 是一种 Kubernetes 资源对象,记录了某个组件在某个时间做了某个动作,用于展示集群内发生的情况,当 Kubernetes 集群中资源状态发生变化时,可以产生新的 event 。

Kubernetes 系统中的各个组件会将运行时发生的各种事件(例如调度器做了什么决定,某些 Pod 为什么被从节点中驱逐)上报给 Kubernetes API Server 。Kubernetes API Server 将 event 存储在 Etcd 中,为避免 Etcd 的磁盘空间被填满,默认的保留策略是:在最后一次的事件发生后,删除 1 小时之前发生的事件。

可以通过 kubectl describe $ResourceNamekubectl get event 命令查看相关资源的事件信息或查看 Kubernetes 集群中发生了哪些事件,默认情况下只会显示最近 1 小时内发生的事件。

2.2 kubectl describe 中的 Events

以查看指定 Pod 的事件为例,执行 kubectl describe pod dubbo-ops-1-bccd87fb8-6zh5f -n middleware 命令查看 pod dubbo-ops-1-bccd87fb8-6zh5f 的事件。

这里我们看到了类似 28s (x240979 over 167d) 这样的输出。它的含义表示:该类型的 event 在 167d 中已经发生了 240979 次,最近的一次发生在 28s 之前。但是直接 kubectl get event 的时候,并不会看到有 240979 次重复的 event 。这说明 Kubernetes 会自动将重复的 event 进行合并。

describe 该 pod 所属的 deployment ,却没有事件,如下图。

可以发现,对不同的资源对象进行 describe 的时候,能看到的 event 内容都是与自己有直接关联的。这说明 Event 对象中是包含它所描述的资源对象的信息的,它们是有直接联系的。

2.3 查看指定 namespace 的所有 event

执行 kubectl get event -n bigdata 命令查看 bigdata namespace 下的所有事件。

但是我们会发现默认情况下 kubectl get event 并没有按照 event 发生的顺序进行排列,所以我们往往需要为其增加 --sort-by='{.metadata.creationTimestamp}' 参数来让其输出可以按时间进行排列。

既然 event 是 Kubernetes 集群中的一种资源,正常情况下它的 metadata.name 中应该包含其名称,用于进行单独操作。所以我们可以使用如下命令获取指定 namespace 下所有 event 的名称。

kubectl -n bigdata get event --sort-by='{.metadata.creationTimestamp}' -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}'
复制代码


2.4 单个 Event 对象

随便选择一条 event 并将其内容使用 YAML 格式进行输出:

kubectl get event aitm-customerservice-chatbot-2-65cd489c97-j4scv.1708265c3fe14fcb -n bigdata -o yaml
复制代码


其中主要字段的含义如下:

  • count:表示当前同类的事件发生了多少次 。

  • firstTimestamp 和 lastTimestamp:分别表示这个 event 首次出现和最近一次出现的时间。

  • involvedObject:此 event 所属的资源对象(触发 event 的资源对象)。源码中结构如下:

type ObjectReference struct { Kind string Namespace string Name string UID types.UID APIVersion string ResourceVersion string FieldPath string}
复制代码
  • reason:表示发起这个动作的原因,是对事件的简单总结,固定的代码,比较适合用于做筛选条件,主要是为了让机器可读,当前有超过 50 种这样的代码。

  • message:给一个更易让人读懂的详细说明。

  • source:表示该 event 的创建者,包含 Host(创建者主机名)和 Component(创建者的组件名),源码中结构如下:

type EventSource struct { Component string Host string}
复制代码
  • type:当前只有 Normal(正常事件) 和 Warning(警告事件) 两种类型, 源码中也分别写了其含义:

// staging/src/k8s.io/api/core/v1/types.goconst ( // Information only and will not cause any problems EventTypeNormal string = "Normal" // These events are to warn that something might go wrong EventTypeWarning string = "Warning")
复制代码

Warning 事件,表示产生这个事件的状态转换是在非预期的状态之间产生的;Normal 事件,表示期望达到的状态,和目前达到的状态是一致的。


我们用一个 Pod 的生命周期进行举例,当创建一个 Pod 的时候,首先 Pod 会进入 Pending 的状态,等待调度、镜像拉取、容器启动等动作,当健康检查通过的时候,Pod 的状态就变为 Running,此时会生成 Normal 事件。而如果在运行中,由于 OOM 或者其他原因造成 Pod 宕掉,进入 Failed 的状态,而这种状态是非预期的,那么此时会产生 Warning 事件。针对这种场景,如果我们能够监控事件的产生,就可以非常及时的查看到一些容易被资源监控忽略的问题。

3. node-problem-detector

Kubernetes 的多个组件(例如 kubelet、deployment-controller、job-controller 等)均会产生 event ,但内置组件只关注容器管理相关的问题,对于 Kubernetes 节点(Node)的操作系统、容器运行时、依赖系统(网络、存储等)并不会提供更多的检测能力,当 Kubernetes 节点出现异常时,并不会有节点相关的 event 产生。容器的稳定运行强依赖 Kubernetes 节点的稳定性,但节点的管理在 Kubernetes 中是比较弱的,可能对于 Kubernetes 的初始设计来说,节点管理应该是 IaaS 的事。但是随着 Kubernetes 的发展,它越来越像是云原生时代的操作系统,它管理的内容也越来越多,因此延伸出了 NPD 项目( node-problem-detector ),以增强 Kubernetes 节点的监控能力。


NPD 是 Kubernetes 中负责节点诊断检查的一个 DaemonSet ,需要额外部署。NPD 的检查输出完全遵循 Kubernetes 的事件规范,可以将节点的异常( 例如 Docker Engine Hang、Linux Kernel Hang、网络异常、文件描述符异常 )转换为 Node 的事件,推送到 APIServer 中,统一由 APIServer 进行事件管理。当节点被 NPD 检测到异常,就会产生一条关于异常节点的事件,运维人员可以通过 kubectl describe node $nodeName 的方式快速查看节点的异常信息和异常原因。


NPD 架构如下图。

NPD 支持多种异常检查,例如:

  • 基础服务问题:NTP 服务未启动

  • 硬件问题:CPU、内存、磁盘、网卡损坏

  • Kernel 问题:KernelDeadlock,文件系统损坏

  • Kubelet 问题:KubeletUnhealthy,Kubelet 频繁重启

  • 容器运行时问题:ContainerRuntimeUnhealthy,Docker 频繁重启,Containerd 频繁重启

4. 持久化存储 Kubernetes 事件

Kubernetes 中的事件在 etcd 中只保存了 1 个小时,并且 etcd 并不支持复杂的分析操作,默认 Kubernetes 只提供了非常简单的过滤方式,例如根据 Reason、时间、类型等进行过滤。同时这些事件只是被动的存在 etcd 中,并不支持主动推送到其他系统,通常只能手动的用 kubectl describe $resourceNamekubectl get event 命令去查看。


而实际上我们对 Kubernetes 事件的使用需求非常高,例如:

  • 排查问题时需要查询更长时间范围的事件。

  • 对异常事件做实时告警,例如 Failed、Evicted、FailedMount、FailedScheduling 等。

  • 订阅这些事件去做自定义监控。

  • 按照各种维度去做过滤、筛选。

  • 事件支持归类统计,例如能够计算事件发生的趋势以及与上一时间段对比,以便基于统计指标进行判断和决策。


为了更便捷的使用 Kubernetes 事件,需要使用 Kubernetes 事件离线工具对 Kubernetes 事件进行持久化存储。用的比较多的有 kubernetes-event-exporterkube-eventer 等。


其中 kube-eventer 是阿里云开源的,以 Deployment 的形式部署在 Kubernetes 集群即可。kube-eventer 支持离线 Kubernetes 事件到钉钉机器人、阿里云日志服务 SLS 、Kafka 、时序数据库 InfluxDB 、Elasticsearch 等,架构如下图。

5. 阿里云 Kubernetes 事件中心

为了让大家更便捷的使用 Kubernetes 事件功能,阿里云容器服务 Kubernetes 和日志服务 SLS 合作推出了 Kubernetes 事件中心,支持将 Kubernetes 中的事件实时采集到 SLS 中。整体逻辑是在 Kubernetes 集群中安装 node-problem-detector 和 kube-eventer ,node-problem-detector 负责将节点的异常转换成 Kubernetes 事件,kube-eventer 负责将 Kubernetes 事件离线存储到 SLS ,并基于 SLS 的查询、分析、可视化、告警能力进行 Dashboard 展示和异常事件实时告警。架构图如下:

5.1 可视化报表

  • 事件总览

  • Node 事件查询

  • Pod 事件查询

5.2 实时告警

为了更好的管理和监控集群,事件中心内置了 Kubernetes 常见的错误类型统计以及实时告警,当有错误发生时,会通过 SLS 实时通知,通知方式支持短信、电话、邮件、钉钉群,也支持自定义的 WebHook 对接企业自己的告警中心。

6. 总结

Kubernetes 事件中包含了很多有用的信息,对运维人员日常观察 Kubernetes 资源的变更以及定位问题均有帮助。本文对 Kubernetes Event 资源对象、产生 Node 事件的 NPD 组件、事件离线工具 kube-eventer 做了简单介绍,并分享了阿里 Kubernetes 事件中心的可视化报表和实时告警。事件监控是 Kubernetes 中的另一种监控方式,可以弥补资源监控在实时性、准确性和场景上的欠缺。


发布于: 刚刚阅读数: 3
用户头像

玄月九

关注

人生就是不停地战斗 2018.08.08 加入

亦狂亦侠亦温文

评论

发布
暂无评论
从 Kubernetes 事件中提取价值_Kubernetes_玄月九_InfoQ写作社区