如何通过Kubernetes事件来报告错误

本文涉及的产品
容器服务 Serverless 版 ACK Serverless,952元额度 多规格
容器服务 Serverless 版 ACK Serverless,317元额度 多规格
简介: 在Kubernetes中,有Event机制,可以做到把一些事件,比如警告、错误等信息记录下来

本文首发于 https://robberphex.com/error-reporting-with-kubernetes-events/

组内有维护一个Kubernetes Webhook,可以拦截pod的创建请求,并做一些修改(比如添加环境变量、添加init-container等)。

业务逻辑本身很简单,但是如果过程中产生错误,就很难处理。要不直接阻止pod创建,那么就有可能导致应用无法启动。要么忽略业务逻辑,那么就会导致静默失败,谁也不知道这儿出现了一个错误。

于是,朴素的想法就是接入告警系统,但这会导致当前组件和具体的告警系统耦合起来。

在Kubernetes中,有Event机制,可以做到把一些事件,比如警告、错误等信息记录下来,就比较适合这个场景。

什么是Kubernetes中的事件/Event?

事件(Event)是 Kubernetes 中众多资源对象中的一员,通常用来记录集群内发生的状态变更,大到集群节点异常,小到 Pod 启动、调度成功等等。

比如我们Describe一个pod,就能看到这个pod对应的事件:

kubectl describe pod sc-b-68867c5dcb-sf9hn

pod-events.png

可以看到,从调度、到启动、再到这个pod最终拉取镜像失败,都会通过event的方式记录下来。

我们来看下一个Event的结构:

$ k get events -o json | jq .items[10]

{
  "apiVersion": "v1",
  "count": 1,
  "eventTime": null,
  "firstTimestamp": "2021-12-04T17:02:14Z",
  "involvedObject": {
    "apiVersion": "v1",
    "fieldPath": "spec.containers{sc-b}",
    "kind": "Pod",
    "name": "sc-b-68867c5dcb-sf9hn",
    "namespace": "default",
    "resourceVersion": "322554830",
    "uid": "24df4a07-f41e-42c2-ba26-d90940303b00"
  },
  "kind": "Event",
  "lastTimestamp": "2021-12-04T17:02:14Z",
  "message": "Error: ErrImagePull",
  "metadata": {
    "creationTimestamp": "2021-12-04T17:02:14Z",
    "name": "sc-b-68867c5dcb-sf9hn.16bd9bf933d60437",
    "namespace": "default",
    "resourceVersion": "1197082",
    "selfLink": "/api/v1/namespaces/default/events/sc-b-68867c5dcb-sf9hn.16bd9bf933d60437",
    "uid": "f928ff2d-c618-44a6-bf5a-5b0d3d20e95e"
  },
  "reason": "Failed",
  "reportingComponent": "",
  "reportingInstance": "",
  "source": {
    "component": "kubelet",
    "host": "eci"
  },
  "type": "Warning"
}

可以看到,一个event,比较重要的几个字端:

  • type - 事件类型,可以是Warning、Normal、Error等
  • reason - 事件的原因,可以是Failed、Scheduled、Started、Completed等
  • message - 事件的描述信息
  • involvedObject - 这个事件对应的资源对象,可以是Pod、Node等
  • source - 这个事件的来源,可以是kubelet、kube-apiserver等
  • firstTimestamp,lastTimestamp - 这个事件的第一次和最后一次发生的时间

基于这些信息,我们就可以做一些集群级别的监控、告警了,比如阿里云的ACK,就会将Event发送到SLS中,然后根据对应的规则来做告警。

如何上报事件

前面说了什么是Kubernetes中的Event,但是我们必须要上报事件,才能让Kubernetes集群知道这个事件发生了,从而做出后续的监控和告警。

如何访问Kubernetes API

上报事件的第一步是访问Kubernetes API,这个API是基于Restful API的,Kubernetes也基于这个API,包装了SDK,直接可以用。

通过SDK连接到Kubernetes API,有两种方式

第一种是通过kubeconfg文件来访问(从外部访问),第二种是通过serviceaccount访问(从Pod访问)。

为了简单起见,我们使用第一种方式作为例子:

package main

import (
    "flag"
    "fmt"
    "path/filepath"

    "k8s.io/client-go/kubernetes"
    "k8s.io/client-go/tools/clientcmd"
    "k8s.io/client-go/util/homedir"
)

func main() {
    var kubeconfig *string
    if home := homedir.HomeDir(); home != "" {
        kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "(optional) absolute path to the kubeconfig file")
    } else {
        kubeconfig = flag.String("kubeconfig", "", "absolute path to the kubeconfig file")
    }
    flag.Parse()

    config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
    if err != nil {
        panic(err)
    }
    clientset, err := kubernetes.NewForConfig(config)
    if err != nil {
        panic(err)
    }
    versionInfo, err := clientset.ServerVersion()
    if err != nil {
        panic(err)
    }
    fmt.Printf("Version: %#v\n", versionInfo)
}

运行这段代码,就可以连接到集群中,可以获取到Kubernetes Server版本了:

Version: &version.Info{Major:"1", Minor:"18+", GitVersion:"v1.18.8-aliyun.1", GitCommit:"27f24d2", GitTreeState:"", BuildDate:"2021-08-19T10:00:16Z", GoVersion:"go1.13.15", Compiler:"gc", Platform:"linux/amd64"}

如何创建、上报事件

在上面的例子中,有了clientset对象,我们现在就要依赖这个对象,在Kuberentes集群中创建一个事件:

now := time.Now()
message := "test message at " + now.Format(time.RFC3339)
// 命名空间为default
_, err = clientset.CoreV1().Events("default").Create(&apiv1.Event{
    ObjectMeta: metav1.ObjectMeta{
        GenerateName: "test-",
    },
    Type:           "Warning",
    Message:        message,
    Reason:         "OnePilotFail",
    FirstTimestamp: metav1.NewTime(now),
    LastTimestamp:  metav1.NewTime(now),
    InvolvedObject: apiv1.ObjectReference{
        Namespace: "default",
        Kind:      "Deployment",
        Name:      "sc-b",
    },
})
fmt.Printf("create event with err: %v\n", err)

在上面的例子中,我们在命名空间default下创建了一个名为test-开头的Event,这个Event的类型是Warning。

我们也可以看下最终产生出来的Event:

kubectl get events -o json | jq .items[353]

{
  "apiVersion": "v1",
  "eventTime": null,
  "firstTimestamp": "2021-12-04T17:27:06Z",
  "involvedObject": {
    "kind": "Deployment",
    "name": "sc-b",
    "namespace": "default"
  },
  "kind": "Event",
  "lastTimestamp": "2021-12-04T17:27:06Z",
  "message": "test message at 2021-12-05T01:27:06+08:00",
  "metadata": {
    "creationTimestamp": "2021-12-04T17:27:06Z",
    "generateName": "test-",
    "name": "test-vvjzp",
    "namespace": "default",
    "resourceVersion": "1198057",
    "selfLink": "/api/v1/namespaces/default/events/test-vvjzp",
    "uid": "f2bcdd1c-442f-4f61-921a-e18637ee5871"
  },
  "reason": "OnePilotFail",
  "reportingComponent": "",
  "reportingInstance": "",
  "source": {},
  "type": "Warning"
}

这样,关心对应事件的人,比如运维人员的人,就可以依据这些信息做监控、告警了。

使用场景

和业务事件不同,Kubernetes事件是集群中的资源,关注的人也多是集群的维护者。

所以这种事件上报机制,还是比较适合一些基础组件来使用,可以让集群维护者了解到当前集群的状态。

如果需要有更加灵活的告警、监控,那么可以使用更加贴近业务的、规则更加丰富的时间、告警系统。

相关实践学习
容器服务Serverless版ACK Serverless 快速入门:在线魔方应用部署和监控
通过本实验,您将了解到容器服务Serverless版ACK Serverless 的基本产品能力,即可以实现快速部署一个在线魔方应用,并借助阿里云容器服务成熟的产品生态,实现在线应用的企业级监控,提升应用稳定性。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
相关文章
|
1月前
|
弹性计算 运维 Kubernetes
云原生K8S场景自动化响应ECS系统事件
客户云原生K8S场景下,通过社区开源NPD+Draino+Autoscaler零开发,对接响应ECS主动运维事件,通过自动响应事件减少非预期宕机。
|
Kubernetes 容器 Perl
【kubernetes】解决 k8s “BGP not established with” 错误
【kubernetes】解决 k8s “BGP not established with” 错误
874 2
【kubernetes】解决 k8s “BGP not established with” 错误
|
Kubernetes Go API
开发 k8s 管理平台 - k8sailor 13. 使用 k8s informer 订阅集群事件
开发 k8s 管理平台 - k8sailor 13. 使用 k8s informer 订阅集群事件
229 0
开发 k8s 管理平台 - k8sailor 13. 使用 k8s informer 订阅集群事件
|
运维 监控 Kubernetes
容器可观测-如何为 K8s 中的所有事件提供可观测能力|学习笔记
快速学习容器可观测-如何为 K8s 中的所有事件提供可观测能力
216 0
容器可观测-如何为 K8s 中的所有事件提供可观测能力|学习笔记
|
JSON 运维 Kubernetes
K8s场景下Logtail组件可观测方案升级-Logtail事件监控发布
SLS针对Logtail本身以及Logtail的管控组件alibaba-log-controller,采用K8s事件的方式,将处理流程中的关键事件透出,从而让用户能够更清楚的感知其中发生的异常。
505 0
K8s场景下Logtail组件可观测方案升级-Logtail事件监控发布
|
Kubernetes Cloud Native 安全
云原生|kubernetes|k8s下部署SQLServer以及Navicat连接SQLServer报错:远程主机强迫关闭了一个现有的连接 错误的解决
云原生|kubernetes|k8s下部署SQLServer以及Navicat连接SQLServer报错:远程主机强迫关闭了一个现有的连接 错误的解决
1115 0
|
域名解析 运维 Kubernetes
一次K8s中的Pod解析外网域名错误的问题排查
一次K8s中的Pod解析外网域名错误的问题排查
一次K8s中的Pod解析外网域名错误的问题排查
|
存储 编解码 Kubernetes
Sentry(v20.12.1) K8S 云原生架构探索,JavaScript Enriching Events(丰富事件信息)
Sentry(v20.12.1) K8S 云原生架构探索,JavaScript Enriching Events(丰富事件信息)
315 0
Sentry(v20.12.1) K8S 云原生架构探索,JavaScript Enriching Events(丰富事件信息)
|
消息中间件 运维 Kubernetes
Sentry(v20.12.1) K8S云原生架构探索,玩转前/后端监控与事件日志大数据分析,高性能高可用+可扩展可伸缩集群部署
Sentry(v20.12.1) K8S云原生架构探索,玩转前/后端监控与事件日志大数据分析,高性能高可用+可扩展可伸缩集群部署
910 0
Sentry(v20.12.1) K8S云原生架构探索,玩转前/后端监控与事件日志大数据分析,高性能高可用+可扩展可伸缩集群部署
|
Kubernetes JavaScript 前端开发
Sentry(v20.12.1) K8S 云原生架构探索, SENTRY FOR JAVASCRIPT 手动捕获事件基本用法
Sentry(v20.12.1) K8S 云原生架构探索, SENTRY FOR JAVASCRIPT 手动捕获事件基本用法
152 0