之前我写了一篇《更优雅的 Kubernetes 集群事件度量方案》,利用 Jaeger 利用 tracing 的方式来采集 Kubernetes 集群中的 events 并进行展示。最终效果如下:
写那篇文章的时候,立了个 flag 要详细介绍下其中的原理,鸽了很久,现在年底了,也该发出来了。
Eents 概览
我们先来做个简单的示例,来看看 Kubernetes 集群中的 events 是什么。
创建一个新的名叫 moelove 的 namespace ,然后在其中创建一个叫做 redis 的 deployment接下来查看这个 namespace 中的所有 events
kubectlcreatensmoelovenamespace/moelovecreatedkubectl—nmoelovecreatedeploymentredis——image=ghcr.io/moelove/redis:alpinedeployment.apps/rediscreatedkubectl—nmoelovegetdeployNAMEREADYUP—TO—DATEAVAILABLEAGEredis1/11111s
但是我们会发现默认情况下 kubectl get events 并没有按照 events 发生的顺序进行排列,所以我们往往需要为其增加 ——sort—by='.metadata.creationTimestamp' 参数来让其输出可以按时间进行排列。
这也是为何 Kubernetes v1.23 版本中会新增 kubectl alpha events 命令的原因。
按时间排序后可以看到如下结果:
。kubectl—nmoelovegetevents——sort—by='.metadata.creationTimestamp'LASTSEENTYPEREASONOBJECTMESSAGE2m12sNormalScheduledpod/redis—687967dbc5—27vmrSuccessfullyassignedmoelove/redis—687967dbc5—27vmrtokind—worker32m13sNormalSuccessfulCreatereplicaset/redis—687967dbc5Createdpod:redis—687967dbc5—27vmr2m13sNormalScalingReplicaSetdeployment/redisScaledupreplicasetredis—687967dbc5to12m12sNormalPullingpod/redis—687967dbc5—27vmrPullingimage"ghcr.io/moelove/redis:alpine"2m6sNormalPulledpod/redis—687967dbc5—27vmrSuccessfullypulledimage"ghcr.io/moelove/redis:alpine"in6.814310968s2m5sNormalCreatedpod/redis—687967dbc5—27vmrCreatedcontainerredis2m5sNormalStartedpod/redis—687967dbc5—27vmrStartedcontainerredis
通过以上的操作,我们可以发现 events 实际上是 Kubernetes 集群中的一种资源当 Kubernetes 集群中资源状态发生变化时,可以产生新的 events
深入 Events 单个 Event 对象
既然 events 是 Kubernetes 集群中的一种资源,正常情况下它的 metadata.name 中应该包含其名称,用于进行单独操作。所以我们可以使用如下命令输出其 name :
。。kubectl—nmoelovegetevents——sort—by='.metadata.creationTimestamp'—ojsonpath='range.items.metadata.name" "end'redis—687967dbc5—27vmr.16c4fb7bde8c69d2redis—687967dbc5.16c4fb7bde6b54c4redis.16c4fb7bde1bf769redis—687967dbc5—27vmr.16c4fb7bf8a0ab35redis—687967dbc5—27vmr.16c4fb7d8ecaeff8redis—687967dbc5—27vmr.16c4fb7d99709da9redis—687967dbc5—27vmr.16c4fb7d9be30c06
选择其中的任意一条 event 记录,将其输出为 YAML 格式进行查看:
。kubectl—nmoelovegeteventsredis—687967dbc5—27vmr.16c4fb7bde8c69d2—oyamlaction:BindingapiVersion:v1eventTime:"2021—12—28T19:31:13.702987Z"firstTimestamp:nullinvolvedObject:apiVersion:v1kind:Podname:redis—687967dbc5—27vmrnamespace:moeloveresourceVersion:"330230"uid:71b97182—5593—47b2—88cc—b3f59618c7aakind:EventlastTimestamp:nullmessage:Successfullyassignedmoelove/redis—687967dbc5—27vmrtokind—worker3metadata:creationTimestamp:"2021—12—28T19:31:13Z"name:redis—687967dbc5—27vmr.16c4fb7bde8c69d2namespace:moeloveresourceVersion:"330235"uid:e5c03126—33b9—4559—9585—5e82adcd96b0reason:ScheduledreportingComponent:default—schedulerreportingInstance:default—scheduler—kind—control—planesource:type:Normal
可以看到其中包含了很多信息, 这里我们先不展开我们看另一个例子
kubectl describe 中的 Events
我们可以分别对 Deployment 对象和 Pod 对象执行 describe 的操作,可以得到如下结果:
对 Deployment 操作 kubectl—nmoelovedescribedeploy/redisName:redisNamespace:moelove...Events:TypeReasonAgeFromMessage—NormalScalingReplicaSet15mdeployment—controllerScaledupreplicasetredis—687967dbc5to1 对 Pod 操作
我们可以发现 对不同的资源对象进行 describe 的时候,能看到的 events 内容都是与自己有直接关联的在 describe Deployment 的时候,看不到 Pod 相关的 Events
这说明, Event 对象中是包含它所描述的资源对象的信息的,它们是有直接联系的。Velero可以备份或恢复集群中的所有对象,还可以按类型,名称空间或标签过滤对象。Velero是Kubernetes进行灾难恢复的理想选择,也是在集群上执行系统操作(如升级)之前对应用程序状态进行快照的理想选择。
结合前面我们看到的单个 Event 对象,我们发现 involvedObject 字段中内容就是与该 Event 相关联的资源对象的信息。
更进一步了解 Events
我们来看看如下的示例,创建一个 Deployment ,但是使用一个不存在的镜像:
kubectl—nmoelovecreatedeploymentnon—exist——image=ghcr.io/moelove/non—existdeployment.apps/non—existcreated
我们可以看到当前的 Pod 处于一个 ErrImagePull 的状态。查看当前 namespace 中的 events
。kubectl—nmoelovegetevents——sort—by='.metadata.creationTimestamp'LASTSEENTYPEREASONOBJECTMESSAGE35sNormalSuccessfulCreatereplicaset/non—exist—d9ddbdd84Createdpod:non—exist—d9ddbdd84—tnrhd35sNormalScalingReplicaSetdeployment/non—existScaledupreplicasetnon—exist—d9ddbdd84to135sNormalScheduledpod/non—exist—d9ddbdd84—tnrhdSuccessfullyassignedmoelove/non—exist—d9ddbdd84—tnrhdtokind—worker317sWarningFailedpod/non—exist—d9ddbdd84—tnrhdError:ErrImagePull17sWarningFailedpod/non—exist—d9ddbdd84—tnrhdFailedtopullimage"ghcr.io/moelove/non—exist":rpcerror:code=Unknowndesc=failedtopullandunpackimage"ghcr.io/moelove/non—exist:latest":failedtoresolvereference"ghcr.io/moelove/non—exist:latest":failedtoauthorize:failedtofetchanonymoustoken:unexpectedstatus:403Forbidden18sNormalPullingpod/non—exist—d9ddbdd84—tnrhdPullingimage"ghcr.io/moelove/non—exist"4sWarningFailedpod/non—exist—d9ddbdd84—tnrhdError:ImagePullBackOff4sNormalBackOffpod/non—exist—d9ddbdd84—tnrhdBack—offpullingimage"ghcr.io/moelove/non—exist"
对这个 Pod 执行 describe 操作:
。韦莱罗的每一项业务都是CRD的定制资源。kubectl—nmoelovedescribepodsnon—exist—d9ddbdd84—tnrhd...Events:TypeReasonAgeFromMessage—NormalScheduled4mdefault—schedulerSuccessfullyassignedmoelove/non—exist—d9ddbdd84—tnrhdtokind—worker3NormalPulling2m22skubeletPullingimage"ghcr.io/moelove/non—exist"WarningFailed2m21skubeletFailedtopullimage"ghcr.io/moelove/non—exist":rpcerror:code=Unknowndesc=failedtopullandunpackimage"ghcr.io/moelove/non—exist:latest":failedtoresolvereference"ghcr.io/moelove/non—exist:latest":failedtoauthorize:failedtofetchanonymoustoken:unexpectedstatus:403ForbiddenWarningFailed2m21skubeletError:ErrImagePullWarningFailed2m9skubeletError:ImagePullBackOffNormalBackOff115skubeletBack—offpullingimage"ghcr.io/moelove/non—exist"
我们可以发现,这里的输出和之前正确运行 Pod 的不一样最主要的区别在于 Age 列这里我们看到了类似 115s 这样的输出
它的含义表示:该类型的 event 在 3m58s 中已经发生了 7 次,最近的一次发生在 115s 之前
但是当我们去直接 kubectl get events 的时候,我们并没有看到有 7 次重复的 event 这说明 Kubernetes 会自动将重复的 events 进行合并
选择最后一条 Events 并将其内容使用 YAML 格式进行输出:
。kubectl—nmoelovegeteventsnon—exist—d9ddbdd84—tnrhd.16c4fce570cfba46—oyamlapiVersion:v1count:43eventTime:nullfirstTimestamp:"2021—12—28T19:57:06Z"involvedObject:apiVersion:v1fieldPath:spec.containersnon—existkind:Podname:non—exist—d9ddbdd84—tnrhdnamespace:moeloveresourceVersion:"333366"uid:33045163—146e—4282—b559—fec19a189a10kind:EventlastTimestamp:"2021—12—28T18:07:14Z"message:Back—offpullingimage"ghcr.io/moelove/non—exist"metadata:creationTimestamp:"2021—12—28T19:57:06Z"name:non—exist—d9ddbdd84—tnrhd.16c4fce570cfba46namespace:moeloveresourceVersion:"334638"uid:60708be0—23b9—481b—a290—dd208fed6d47reason:BackOffreportingComponent:""reportingInstance:""source:component:kubelethost:kind—worker3type:Normal
这里我们可以看到其字段中包括一个 count 字段,表示同类 event 发生了多少次以及 firstTimestamp 和 lastTimestamp 分别表示了这个 event 首次出现了最近一次出现的时间这样也就解释了前面的输出中 events 持续的周期了
彻底搞懂 Events
以下内容是从 Events 中随便选择的一条,我们可以看到它包含的一些字段信息:
apiVersion:v1count:1eventTime:nullfirstTimestamp:"2021—12—28T19:31:13Z"involvedObject:apiVersion:apps/v1kind:ReplicaSetname:redis—687967dbc5namespace:moeloveresourceVersion:"330227"uid:11e98a9d—9062—4ccb—92cb—f51cc74d4c1dkind:EventlastTimestamp:"2021—12—28T19:31:13Z"message:'Createdpod:redis—687967dbc5—27vmr'metadata:creationTimestamp:"2021—12—28T19:31:13Z"name:redis—687967dbc5.16c4fb7bde6b54c4namespace:moeloveresourceVersion:"330231"uid:8e37ec1e—b3a1—420c—96d4—3b3b2995c300reason:SuccessfulCreatereportingComponent:""reportingInstance:""source:component:replicaset—controllertype:Normal
其中主要字段的含义如下:
count: 表示当前同类的事件发生了多少次 involvedObject: 与此 event 有直接关联的资源对象 , 结构如下: typeObjectReferencestructKindstringNamespacestringNamestringUIDtypes.UIDAPIVersionstringResourceVersionstringFieldPathstring source: 直接关联的组件, 结构如下: typeEventSourcestructComponentstringHoststring reason: 简单的总结,比较适合用于做筛选条件,主要是为了让机器可读,当前有超过 50 种这样的代码, message: 给一个更易让人读懂的详细说明 type: 当前只有 Normal 和 Warning 两种类型, 源码中也分别写了其含义: //staging/src/k8s.io/api/core/v1/types.goconst
所以,当我们将这些 Events 都作为 tracing 的 span 采集回来后,就可以按照其 source 进行分类,按 involvedObject 进行关联,按时间进行排序了。
总结
在这篇文章中,我主要通过两个示例,一个正确部署的 Deploy,以及一个使用不存在镜像部署的 Deploy,深入的介绍了 Events 对象的实际的作用及其各个字段的含义。
对于 Kubernetes 而言,Events 中包含了很多有用的信息,但是这些信息却并不会对 Kubernetes 造成什么影响,它们也并不是实际的 Kubernetes 的日志默认情况下 Kubernetes 中的日志在 1 小时后就会被清理掉,以便释放对 etcd 的资源占用
。郑重声明:此文内容为本网站转载企业宣传资讯,目的在于传播更多信息,与本站立场无关。仅供读者参考,并请自行核实相关内容。