最近遇到一个很头疼的需求:Kubernetes 集群内部事件的监控与追踪。 在日常使用中,总会碰到容器“不经意间”重启的情况,但我完全不知道上次重启是什么时候。容器一旦重启,旧实例就会被销毁,如果旧容器日志没有被收集或转存,就彻底丢失了。这样一来,想通过历史日志排查问题原因就显得非常棘手。
其实,K8s 本身是有事件存储机制的,但它们存在一个 TTL(默认 1 小时)。这意味着如果容器频繁重启,或者事件过了保留时间,你就无法通过事件追溯过去的重启时间。更糟糕的是,当容器多次崩溃重启时,后续的事件可能会覆盖掉前面的问题线索,大大增加了排查难度。
我开始收集网络上的一些现有解决方案,还真找到一个:k8s-event-exporter。
这是一个 GitHub 开源项目,作者的想法是写一个 exporter,监听集群事件并推送到 Loki 存储,然后在 Grafana 上展示,思路非常棒!不过这个项目最后一次提交还是两年前,时间有点久了,但我还是抱着尝试的心理去试用了一下。
然而意外发生了:exporter 拿到的事件并不完整。 最初我以为是 K8s 本身的事件逻辑导致的,因为 K8s 对短时间内频繁发生的同一逻辑事件会自动合并(这点合理,可以避免 etcd 存储的重复事件)。但奇怪的是,我发现有些事件本不是同一个事件,exporter 却依然没有正确推送。
-
🗓️ ➤
Scheduled Pod 被调度到节点
-
📦 ➤
Pulled 镜像拉取完成
-
🛠️ ➤
Created 容器实例被创建
-
🚀 ➤
Started 容器启动成功
-
❤️
Liveness Probe 健康检查开始执行
但实际结果却只有 一个 Pod 事件 成功推送到 Loki,剩下的事件全都丢弃了,提示是“事件过期被丢弃”。最关键的是,我并不知道 exporter 丢弃的到底是不是我想要的事件。所有能调的配置我几乎都试了,可惜还是没能解决,属实出乎我意料 /(ㄒoㄒ)/~~
我的需求其实非常明确: 监听 K8s 集群内的事件,并推送到 Loki。
网上方案里我研究过 k8s-event-exporter、promtail、开启 k8s-auditlog、falco,最后发现只有 exporter 最贴合需求,但它却没能满足我。那怎么办?
👉 不行!那就自己写一个! 我只需要实现一个功能,应该用不了多少脑子……于是,kube-event 就这样横空出世了
一、传统部署方式
需在 K8s Master 节点 部署
# 下载并解压软件 tar xf kube-event.tar.gz && cd kube-event # 修改conf配置文件,主要修改loki的地址,其他几个参数看个人需求吧 vim config.json # 启动服务 ./start.sh # 停止服务 ./stop.sh
二、容器化部署
# 下载镜像 docker pull registry.cn-beijing.aliyuncs.com/nanxi/kube-event:1.0.1
配置清单(kube-event.yaml)参考如下:
apiVersion: v1 kind: ServiceAccount metadata: name: kube-event-sa namespace: default --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: kube-event-reader rules: - apiGroups: [""] resources: ["events"] verbs: ["get", "list", "watch"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: kube-event-reader-binding roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: kube-event-reader subjects: - kind: ServiceAccount name: kube-event-sa namespace: default --- apiVersion: v1 kind: ConfigMap metadata: name: kube-event-conf data: config.json: | { "LOKI_URL": "http://172.21.0.237:32537/loki/api/v1/push", "DATA_DIR": "../data/", "DEDUPLICATE": 0, "PUSH_INTERVAL_SECONDS": 30, "ENABLE_DETAILED": false } logging.yaml: | version: 1 disable_existing_loggers: False formatters: standard: format: "%(asctime)s [%(levelname)s] %(name)s:%(lineno)d - %(message)s" message_only: format: "%(message)s" handlers: console: class: logging.StreamHandler level: INFO formatter: standard stream: ext://sys.stdout file: class: logging.handlers.TimedRotatingFileHandler level: DEBUG formatter: standard filename: ../logs/app.log when: midnight backupCount: 7 encoding: utf-8 detailed_console: class: logging.StreamHandler level: INFO formatter: message_only stream: ext://sys.stdout detailed_file: class: logging.handlers.TimedRotatingFileHandler level: DEBUG formatter: message_only filename: ../logs/app.log when: midnight backupCount: 7 encoding: utf-8 loggers: detailed: level: INFO handlers: [detailed_console,detailed_file] propagate: false root: level: DEBUG handlers: [console,file] --- apiVersion: apps/v1 kind: Deployment metadata: name: kube-event namespace: default spec: replicas: 1 selector: matchLabels: app: kube-event template: metadata: labels: app: kube-event spec: serviceAccountName: kube-event-sa containers: - name: kube-event image: kube-event:1.0.1 volumeMounts: - name: conf-volume mountPath: /app/conf - name: log-volume mountPath: /app/logs - name: catche-data mountPath: /app/data volumes: - name: conf-volume configMap: name: kube-event-conf - name: log-volume hostPath: path: /var/log/kube-event/logs type: DirectoryOrCreate - name: catche-data hostPath: path: /var/log/kube-event/data type: DirectoryOrCreate
三、效果展示
正常启动后输出如下:

然后我们可以配合grafana进行展示:
这个模板编号是17882,原k8s-event-exporter的模板,我们可以直接借用,数据展示的时候修改下查询SQL即可,

以下是kube-event运行成功后正常推送的数据展示:




部署前请认真阅读说明,推荐使用容器部署,欢迎试用并反馈问题!