当控制器执行协调对象的实际状态与所需状态的任务时,如对象的规范字段中指定的那样,它们会生成事件以显示它们所做的事情。存在两种类型的事件:正常和警告。后一种类型的事件通常由控制器在某些东西阻止它们协调对象时生成。通过监控此类事件,您可以快速了解集群遇到的任何问题。

介绍 Event 对象

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

保留事件的时间可通过 API 服务器的命令行选项进行配置。

使用 kubectl get events 列出事件

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

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

因为事件是独立的对象,您可以使用 kubectl get events 列出它们,如下面的清单所示。

  1. $ kubectl get ev
  2. LAST
  3. SEEN TYPE REASON OBJECT MESSAGE
  4. 48s Normal Starting node/kind-worker2 Starting kubelet.
  5. 48s Normal NodeAllocatableEnforced node/kind-worker2 Updated Node A...
  6. 48s Normal NodeHasSufficientMemory node/kind-worker2 Node kind-work...
  7. 48s Normal NodeHasNoDiskPressure node/kind-worker2 Node kind-work...
  8. 48s Normal NodeHasSufficientPID node/kind-worker2 Node kind-work...
  9. 47s Normal Starting node/kind-worker2 Starting kube-...

前面的清单使用短名称 ev 代替 events。

您会注意到列表中显示的某些事件与节点的状态条件匹配。这通常是这种情况,但您还会发现其他事件。以Starting 为理由的两个事件就是两个这样的例子。在手头的案例中,它们表明 Kubelet 和 Kube 代理组件已在节点上启动。您还不需要担心这些组件。它们在本书的第三部分进行了解释。

了解 Event 对象中的内容

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

  1. $ kubectl get ev -o wide

该命令的输出范围极广,本书未在此处列出。相反,下表解释了显示的信息。

Property Description
Name The name of this Event object instance. Useful only if you want to retrieve the given object from the API.
Type The type of the event. Either Normal or Warning.
Reason The machine-facing description why the event occurred.
Source The component that reported this event. This is usually a controller.
Object The object instance to which the event refers. For example, node/xyz.
Sub-object The sub-object to which the event refers. For example, what container of the pod.
Message The human-facing description of the event.
First seen The first time this event occurred. Remember that each Event object is deleted after a while, so this may not be the first time that the event actually occurred.
Last seen Events often occur repeatedly. This field indicates when this event last occurred.
Count The number of times this event has occurred.

仅显示警告事件

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

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

  1. $ kubectl get ev --field-selector type=Warning
  2. No resources found in default namespace.

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

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

检查 Event 对象的 YAML

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

事件对象没有 spec 和 status 部分

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

检查以下列表,看看您是否可以轻松找到对象种类、元数据和其他字段。

  1. apiVersion: v1
  2. count: 1
  3. eventTime: null
  4. firstTimestamp: "2020-05-17T18:16:40Z"
  5. involvedObject:
  6. kind: Node
  7. name: kind-worker2
  8. uid: kind-worker2
  9. kind: Event
  10. lastTimestamp: "2020-05-17T18:16:40Z"
  11. message: Starting kubelet.
  12. metadata:
  13. creationTimestamp: "2020-05-17T18:16:40Z"
  14. managedFields:
  15. - ...
  16. name: kind-worker2.160fe38fc0bc3703 #D
  17. namespace: default
  18. resourceVersion: "3528471"
  19. selfLink: /api/v1/namespaces/default/events/kind-worker2.160f...
  20. uid: da97e812-d89e-4890-9663-091fd1ec5e2d
  21. reason: Starting
  22. reportingComponent: ""
  23. reportingInstance: ""
  24. source:
  25. component: kubelet
  26. host: kind-worker2
  27. type: Normal

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

相比之下,Node 对象的早期 YAML 清单相对容易阅读,因为顶级字段的顺序是人们所期望的:apiVersion、种类、元数据、规范和状态。你会注意到这仅仅是因为五个字段的字母顺序恰好是有意义的。但是这些字段下的字段也存在同样的问题,因为它们也是按字母顺序排序的。

YAML 应该易于人们阅读,但 Kubernetes YAML 中的字母字段顺序打破了这一点。幸运的是,大多数对象都包含 spec 和 status 部分,因此至少这些对象中的顶级字段组织良好。至于其余的,你只需要接受处理 Kubernetes 清单的这个不幸的方面。