大家应该对 Kubernetes Events 并不陌生,特别是当你使用 kubectl describe 命令或 Event API 资源来了解集群中的故障时。

$ kubectl get events

15m         Warning   FailedCreate                                                                                                      replicaset/ml-pipeline-visualizationserver-865c7865bc    

Error creating: pods "ml-pipeline-visualizationserver-865c7865bc-" is forbidden: error looking up service account default/default-editor: serviceaccount "default-editor" not found

尽管这些信息十分有用,但它只是临时的,保留时间最长为30天。如果出于审计或是故障诊断等目的,你可能想要把这些信息保留得更久,比如保存在像 Kafka 这样更持久、高效的存储中。然后你可以借助其他工具(如 Argo Events)或自己的应用程序订阅 Kafka 主题来对某些事件做出响应。

构建K8s事件处理链路

我们将构建一整套 Kubernetes 事件处理链路,其主要构成为:

  • Eventrouter,开源的 Kubernetes event 处理器,它可以将所有集群事件整合汇总到某个 Kafka 主题中。
  • Strimzi Operator,在 Kubernetes 中轻松管理 Kafka broker。
  • 自定义 Go 二进制文件以将事件分发到相应的 Kafka 主题中。

为什么要把事件分发到不同的主题中?比方说,在集群的每个命名空间中存在与特定客户相关的 Kubernetes 资产,那么在使用这些资产之前你当然希望将相关事件隔离开。

本示例中所有的配置、源代码和详细设置指示都已经放在以下代码仓库中:



 

创建 Kafka broker 和主题

我选择使用 Strimzi(strimzi.io/) 将 Kafka 部署到 Kubernetes 中。简而言之,它是用于创建和更新 Kafka broker 和主题的。你可以在官方文档中找到如何安装该 Operator 的详细说明:

首先,创建一个新的 Kafka 集群:

apiVersion: kafka.strimzi.io/v1beta1
kind: Kafka
metadata:
name: kube-events
spec:
entityOperator:
topicOperator: {}
userOperator: {}
kafka:
config:
default.replication.factor: 3
log.message.format.version: "2.6"
offsets.topic.replication.factor: 3
transaction.state.log.min.isr: 2
transaction.state.log.replication.factor: 3
listeners:
- name: plain
port: 9092
tls: false
type: internal
- name: tls
port: 9093
tls: true
type: internal
replicas: 3
storage:
type: jbod
volumes:
- deleteClaim: false
id: 0
size: 10Gi
type: persistent-claim
version: 2.6.0
zookeeper:
replicas: 3
storage:
deleteClaim: false
size: 10Gi
type: persistent-claim

然后创建 Kafka 主题来接收我们的事件:

apiVersion: kafka.strimzi.io/v1beta1
kind: KafkaTopic
metadata:
name: cluster-events
spec:
config:
retention.ms: 7200000
segment.bytes: 1073741824
partitions: 1
replicas: 1

设置 EventRouter

在本教程中使用 kubectl apply 命令即可,我们需要编辑 router 的配置,以指明我们的 Kafka 端点和要使用的主题:

apiVersion: v1
data:
config.json: |-
{
"sink": "kafka",
"kafkaBrokers": "kube-events-kafka-bootstrap.kube-events.svc.cluster.local:9092",
"kafkaTopic": "cluster-events"
}
kind: ConfigMap
metadata:
name: eventrouter-cm

验证设置是否正常工作

我们的 cluster-events Kafka 的主题现在应该收到所有的事件。最简单的方法是在主题上运行一个 consumer 来检验是否如此。为了方便期间,我们使用我们的一个 Kafka broker pods,它已经有了所有必要的工具,你可以看到事件流:

kubectl -n kube-events exec kube-events-kafka-0 -- bin/kafka-console-consumer.sh \
--bootstrap-server kube-events-kafka-bootstrap:9092 \
--topic kube-events \
--from-beginning
{"verb":"ADDED","event":{...}}
{"verb":"ADDED","event":{...}}
...

编写 Golang 消费者

现在我们想将我们的 Kubernetes 事件依据其所在的命名空间分发到多个主题中。我们将编写一个 Golang 消费者和生产者来实现这一逻辑:

  • 消费者部分在 cluster-events 主题上监听传入的集群事件
  • 生产者部分写入与事件的命名空间相匹配的 Kafka 主题中

如果为Kafka配置了适当的选项(默认情况),就不需要特地创建新的主题,因为 Kafka 会默认为你创建主题。这是 Kafka 客户端 API 的一个非常酷的功能。

p, err := kafka.NewProducer(cfg.Endpoint)
if err != nil {
sugar.Fatal("cannot create producer")
}
defer p.Close() c, err := kafka.NewConsumer(cfg.Endpoint, cfg.Topic)
if err != nil {
sugar.Fatal("cannot create consumer")
}
defer c.Close() run := true
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
go func() {
sig := <-sigs
sugar.Infof("signal %s received, terminating", sig)
run = false
}() var wg sync.WaitGroup
go func() {
wg.Add(1)
for run {
data, err := c.Read()
if err != nil {
sugar.Errorf("read event error: %v", err)
time.Sleep(5 * time.Second)
continue
}
if data == nil {
continue
}
msg, err := event.CreateDestinationMessage(data)
if err != nil {
sugar.Errorf("cannot create destination event: %v", err)
}
p.Write(msg.Topic, msg.Message)
}
sugar.Info("worker thread done")
wg.Done()
}() wg.Wait()

完整代码在此处:

当然还有更高性能的选择,这取决于预计的事件量和扇出(fanout)逻辑的复杂性。对于一个更强大的实现,使用 Spark Structured Streaming 的消费者将是一个很好的选择。

部署消费者

构建并将二进制文件推送到 Docker 镜像之后,我们将它封装为 Kubernetes deployment:

apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: events-fanout
name: events-fanout
spec:
replicas: 1
selector:
matchLabels:
app: events-fanout
template:
metadata:
labels:
app: events-fanout
spec:
containers:
- image: emmsys/events-fanout:latest
name: events-fanout
command: [ "./events-fanout"]
args:
- -logLevel=info
env:
- name: ENDPOINT
value: kube-events-kafka-bootstrap:9092
- name: TOPIC
value: cluster-events

检查目标主题是否创建

现在,新的主题已经创建完成:

kubectl -n kube-events get kafkatopics.kafka.strimzi.io -o name

kafkatopic.kafka.strimzi.io/cluster-events
kafkatopic.kafka.strimzi.io/kube-system
kafkatopic.kafka.strimzi.io/default
kafkatopic.kafka.strimzi.io/kafka
kafkatopic.kafka.strimzi.io/kube-events

你会发现你的事件根据其命名空间整齐地存储在这些主题中。

总结

访问 Kubernetes 历史事件日志可以使你对 Kubernetes 系统的状态有了更好的了解,但这单靠 kubectl 比较难做到。更重要的是,它可以通过对事件做出反应来实现集群或应用运维自动化,并以此来构建可靠、反应灵敏的软件。

原文链接:

https://hackernoon.com/monitor-your-kubernetes-cluster-events-with-eventrouter-golang-and-kafka-wh2a35l0

如何借助Kafka持久化存储K8S事件数据?的更多相关文章

  1. Scrapy持久化存储-爬取数据转义

    Scrapy持久化存储 爬虫爬取数据转义问题 使用这种格式,会自动帮我们转义 'insert into wen values(%s,%s)',(item['title'],item['content' ...

  2. iOS数据持久化存储

    本文中的代码托管在github上:https://github.com/WindyShade/DataSaveMethods 相对复杂的App仅靠内存的数据肯定无法满足,数据写磁盘作持久化存储是几乎每 ...

  3. k8s集群,使用pvc方式实现数据持久化存储

    环境: 系统 华为openEulerOS(CentOS7) k8s版本 1.17.3 master 192.168.1.244 node1 192.168.1.245 介绍: 在Kubernetes中 ...

  4. vuex数据持久化存储

    想想好还是说下vuex数据的持久化存储吧.依稀还记得在做第一个vue项目时,由于刚刚使用vue,对vue的一些基本概念只是有一个简单的了解.当涉及到非父子组件之间通信时,选择了vuex.只是后来竟然发 ...

  5. 通过Heketi管理GlusterFS为K8S集群提供持久化存储

    参考文档: Github project:https://github.com/heketi/heketi MANAGING VOLUMES USING HEKETI:https://access.r ...

  6. k8s的持久化存储PV&&PVC

    1.PV和PVC的引入 Volume 提供了非常好的数据持久化方案,不过在可管理性上还有不足. 拿前面 AWS EBS 的例子来说,要使用 Volume,Pod 必须事先知道如下信息: 当前 Volu ...

  7. redis多实例与主从同步及高级特性(数据过期机制,持久化存储)

    redis多实例 创建redis的存储目录 vim /usr/local/redis/conf/redis.conf #修改redis的配置文件 dir /data/redis/ #将存储路径配置修改 ...

  8. 4.深入k8s:容器持久化存储

    从一个例子入手PV.PVC Kubernetes 项目引入了一组叫作 Persistent Volume Claim(PVC)和 Persistent Volume(PV)的 API 对象用于管理存储 ...

  9. Kafka分片存储、消息分发和持久化机制

    Kafka 分片存储机制 Broker:消息中间件处理结点,一个 Kafka 节点就是一个 broker,多个 broker 可以组成一个 Kafka集群. Topic:一类消息,例如 page vi ...

  10. 如何接入 K8s 持久化存储?K8s CSI 实现机制浅析

    作者 王成,腾讯云研发工程师,Kubernetes contributor,从事数据库产品容器化.资源管控等工作,关注 Kubernetes.Go.云原生领域. 概述 进入 K8s 的世界,会发现有很 ...

随机推荐

  1. SHELL-反弹shell

    什么是shell? 在我们深入了解发送和接收 shell 的复杂性之前,了解 shell 实际上是什么很重要.用最简单的术语来说,shell 就是我们在与命令行环境 (CLI) 交互时使用的工具.换句 ...

  2. 深入理解 Python 虚拟机:整型(int)的实现原理及源码剖析

    深入理解 Python 虚拟机:整型(int)的实现原理及源码剖析 在本篇文章当中主要给大家介绍在 cpython 内部是如何实现整型数据 int 的,主要是分析 int 类型的表示方式,分析 int ...

  3. Python练习-3.12

    1.给文章中的手机号打上马赛克 也就是在文章中发现手机号之后,用*或者#等这一类无法将手机号直接识别出来的符号代替 # 文章中手机号的马赛克形式化 import re content="白日 ...

  4. Java线程池和Spring异步处理高级篇

    开发过程中我们会遇到很多使用线程池的场景,例如异步短信通知,异步发邮件,异步记录操作日志,异步处理批量Excel解析.这些异步处理的场景我们都可以把它放在线程池中去完成,当然还有很多场景也都可以使用线 ...

  5. ROS话题通信C++(附launch启动方式)

    ROS话题通信C++(附launch启动方式) 创建工作空间 mkdir -p topic_ws/src cd topic_ws catkin_make 设置环境变量 source ./devel/s ...

  6. 面试题锦集:1、数据库三大范式,2、mysql索引类型及作用,3、事务的特性和隔离级别

    目录 面试题集锦 一.数据库三大范式 二.mysql有哪些索引类型及作用 三.事务的特性和隔离级别 1.事务的四大特性 2.事务的隔离级别 3.什么是脏读.不可重复度.幻读 4.解决办法 面试题集锦 ...

  7. [ElasticSearch]修改开源安全组件Search Guard-6 用户密码

    ES有很多的安全组件可用,例如: X-pack,Sarch Guard.但目前开源免费的,仅Search Guard. 1 前置条件 Elastic Search 6 服务安装成功,且成功运行. ES ...

  8. [JavaScript]Base64 ←→ 图像

    1 Base64 → 图像 [demo1] document.getElementById('img').setAttribute( 'src', 'data:image/png;base64,iVB ...

  9. Vue2异步更新及nextTick原理

    vue 官网中是这样描述 nextTick 的 在下次 DOM 更新循环结束之后执行延迟回调.在修改数据之后立即使用这个方法,可以获取更新后的 DOM. 在学习 nextTick 是如何实现之前,我们 ...

  10. STM32启动分析之main函数是怎样跑起来的

    1.MDK目标文件 1)MDK中C程序编译后的结果,即可执行文件数据分类: RAM ZI bss 存储未初始化的或初始化为0的全局变量和静态变量 heap 堆,系统malloc和free操作的内存 s ...