K8S - 通过 Event 对象观察集群事件

当控制器执行协调对象的实际状态与所需状态的任务时,如对象 spec 字段中指定的那样,它们会生成事件以显示它们所做的事情。存在两种类型的事件:

  1. 正常
  2. 警告

警告 通常由控制器在某些东西阻止它们协调对象时生成。通过监控此类事件,您可以快速了解集群遇到的任何问题。

介绍Event对象

与 Kubernetes 中的其他一切一样,事件由通过 Kubernetes API 创建和读取的事件对象表示。如下图所示,它们包含有关对象发生了什么以及事件源是什么的信息。与其他对象不同,每个 Event 对象在创建后一小时被删除,以减轻 etcd(Kubernetes API 对象的数据存储)的负担。

image-20221030201408047

TIPS:
可以通过 API 服务的命令行选项设置事件的存活时间(多久删除)

使用 kubectl get events 列出事件

事件由命令 kubectl describe <object> 显示。由于它们的性质以及可以在短时间内为对象创建许多事件的事实,它们不是对象本身的一部分。您不会在对象的 YAML 清单中找到它们,因为它们是独立存在的,就像节点和您目前看到的其他对象一样。

笔记

如果您想在您自己的集群中遵循本节中的练习,您可能需要重新启动其中一个节点以确保事件足够新以仍然存在于 etcd 中。如果你不能做到这一点,别担心,自己跳过这些练习,因为你还将在下面的练习中生成和检查事件。

因为事件是独立的对象,你可以使用列出它们 kubectl get events

kubectl get ev
# output
LAST 
SEEN  TYPE    REASON                   OBJECT             MESSAGE
48s   Normal  Starting                 node/kind-worker2  Starting kubelet.
48s   Normal  NodeAllocatableEnforced  node/kind-worker2  Updated Node A...
48s   Normal  NodeHasSufficientMemory  node/kind-worker2  Node kind-work... 
48s   Normal  NodeHasNoDiskPressure    node/kind-worker2  Node kind-work...
48s   Normal  NodeHasSufficientPID     node/kind-worker2  Node kind-work... 
47s   Normal  Starting                 node/kind-worker2  Starting kube-...
笔记

前面的命令中使用短名称 ev 代替 events.

您会注意到列表中显示的某些事件与节点的状态条件匹配。这种情况经常发生,但您还会发现其他事件。有 reason 的两个事件Starting 就是两个这样的例子。它们表明 Kubelet 和 Kube 代理组件已在节点上启动。

了解 Event 对象中的内容

与其他对象一样,该kubectl get命令仅输出最重要的对象数据。要显示其他信息,您可以通过执行带有以下-o wide选项的命令来启用其他列:

kubectl get ev -o wide
# output
LAST SEEN   TYPE     REASON         OBJECT          SUBOBJECT   SOURCE            MESSAGE                                                     FIRST SEEN   COUNT   NAME
8m32s       Normal   nodeAssigned   service/kubia               metallb-speaker   announcing from node "kind-worker" with protocol "layer2"   20h          5       kubia.172296b40e183f90
Event object(Event 对象)的属性
Property Description
Name 此 Event 对象实例的名称。仅当您想从 API 检索给定对象时才有用。
Type 事件的类型。要么 Normal 要么 Warning
Reason 事件的发生原因 – 面向机器的描述。
Source 报告此事件的组件。通常由一个控制器(Controller)报告。
Object 事件引用的对象实例。例如,node/xyz。
Sub-object 事件引用的子对象。例如,pod 中的 容器(Container)。
Message 事件的发生原因 – 面向用户的描述。(可读性强)
First seen 第一次发生此事件。请记住,每个 Event 对象都会在一段时间后被删除,因此这可能不是该事件第一次实际发生。
Last seen 事件经常重复发生。此字段指示此事件上次发生的时间。
Count 此事件发生的次数。
TIP

您可能会发现 kubectl get events 当您每次对您的一个对象进行更改时运行该命令很有用。这将帮助您了解表面之下发生的事情。

仅显示警告事件

kubectl describe 仅显示与您正在描述的对象相关的事件的命令不同,kubectl get events 命令显示所有事件。如果您想检查是否有您应该关注的事件,这很有用。您可能希望忽略 type 是 Normal 的事件,而只关注 type 是 Warning 的事件。

API 提供了一种通过称为字段选择器(field selectors)的机制过滤对象的方法。仅返回指定字段与指定选择器值匹配的对象。您可以使用它来仅显示警告事件。kubectl get命令允许您使用 --field-selector 选项指定字段选择器。要仅列出表示警告的事件,请执行以下命令:

kubectl get ev --field-selector type=Warning
# output
No resources found in default namespace.

如果该命令没有打印任何事件,如上述情况,则说明您的集群中最近没有记录任何警告。

您可能想知道我是如何知道要在字段选择器中使用的字段的确切名称以及它的确切值应该是什么(例如,它应该是小写的)。如果您猜到此信息是由kubectl explain events命令提供的,请让我表示由衷的敬佩。由于事件是常规 API 对象,您可以使用它来查找有关事件对象结构的文档。在那里,您将了解到该对象的 type 字段可以有两个值:

  • Normal
  • Warning

探索 Event 对象的 YAML

要检查集群中的事件,命令 kubectl describekubectl get events 应该足够了。与其他对象不同,您可能永远不必显示 Event 对象的完整 YAML。但我想借此机会向您展示一个关于 API 返回的 Kubernetes 对象清单的烦人之处。

事件对象没有规范和状态部分

如果您使用 kubectl explain 来探索 Event 对象的结构,您会注意到它没有specstatus部分。不幸的是,这意味着它的字段不像 Node 对象 那样组织良好。

检查以下 YAML 并查看是否可以轻松找到对象的 kindmetadata 等其他字段。

apiVersion: v1 # apiVersion 字段很容易发现
count: 1
eventTime: null
firstTimestamp: "2020-05-17T18:16:40Z"
involvedObject:
  kind: Node
  name: kind-worker2
  uid: kind-worker2
kind: Event # kind 字段非常难找到
lastTimestamp: "2020-05-17T18:16:40Z"
message: Starting kubelet.
metadata: # 从这里开始,对象的元数据出现在元数据部分
  creationTimestamp: "2020-05-17T18:16:40Z"
  name: kind-worker2.160fe38fc0bc3703 # 对象的名称隐藏在这里
  namespace: default
  resourceVersion: "3528471"
  selfLink: /api/v1/namespaces/default/events/kind-worker2.160f...
  uid: da97e812-d89e-4890-9663-091fd1ec5e2d
reason: Starting
reportingComponent: ""
reportingInstance: ""
source:
  component: kubelet
  host: kind-worker2
type: Normal

您肯定会同意清单中的 YAML 清单是杂乱无章的。这些字段按字母顺序列出,而不是组织成连贯的组。这使我们人类难以阅读。它看起来如此混乱,难怪很多人讨厌处理 Kubernetes YAML 或 JSON 清单,因为两者都存在这个问题。

相比之下,Node 对象的早期 YAML 清单相对容易阅读,因为顶级字段的顺序是人们所期望的:apiVersion, kind, metadata, specstatus.。您会注意到这仅仅是因为五个字段的字母顺序恰好是有意义的。但是这些字段下的字段也存在同样的问题,因为它们也是按字母顺序排序的。

YAML 应该易于人们阅读,但 Kubernetes YAML 中的字母字段顺序打破了这一点。幸运的是,大多数对象都包含 specstatus 部分,因此至少这些对象中的顶级字段组织得很好。至于其余的,您只能接受并处理 Kubernetes 清单的展示问题。

总结

在本章中,您学习了:

  • Kubernetes 提供了一个 RESTful API 用于与集群交互。API 对象映射到构成集群的实际组件,包括应用程序、负载平衡器、节点、存储卷等。
  • 一个对象实例可以由许多资源表示。单个对象类型可以通过多个资源公开,这些资源只是同一事物的不同表示。
  • Kubernetes API 对象在 YAML 或 JSON 清单中描述。对象是通过将清单发布到 API 来创建的。对象的状态存储在对象本身中,并且可以通过使用 GET 请求从 API 请求对象来检索。
  • 所有 Kubernetes API 对象都包含类型和对象元数据,并且大多数都有一个 specstatus 部分。一些对象类型没有这两个部分,因为它们只包含静态数据。
  • 控制器通过不断观察对象 spec 的变化、更新集群状态并通过对象的 status 字段报告当前状态。
  • 当控制器管理 Kubernetes API 对象时,它们会发出事件以显示它们执行了哪些操作。与其他一切一样,事件由 Event 对象表示,并且可以通过 API 检索。事件表明节点或其他对象正在发生什么。它们显示了该物体最近发生的事情,并可以提供关于它为什么被破坏的线索。
  • kubectl explain 命令提供了一种从命令行查找有关特定对象类型及其字段的文档的快速方法。
  • Node 对象 中的状态(status)包含有关节点的 IP 地址主机名其资源容量条件(condition)缓存的容器图像有关节点的其他信息。在节点上运行的 Pod 不是节点状态的一部分,但kubectl describe node命令会从 pods 资源中获取此信息。
  • 许多对象类型使用状态条件来表示对象所代表的组件的状态。对于节点,这些条件是 MemoryPressureDiskPressurePIDPressure。每个条件要么是 True 要么是 FalseUnknown。相关联的 reasonmessage 可以来解释条件为何处于这个状态。

好好学习,天天向上