既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
Kubernetes 日志收集的另一个重要方面是事件。它们具有独特的结构,因为它们仅存在于 etcd 中,因此为了收集它们,您必须向 Kubernetes API 发出请求。
由于 reason 字段(请参阅下面的示例清单)和 count 字段(用作计数器,随着记录的事件越来越多而递增),因此可以将事件视为指标。
此外,还可以将事件收集为跟踪、特征和字段,这有助于创建全面的甘特图,以说明集群中的所有事件。firstTimestamp``lastTimestamp
最后,事件提供人类可读的消息(字段),使它们能够作为日志收集。message
apiVersion: v1
kind: Event
count: 1
metadata:
name: standard-worker-1.178264e1185b006f
namespace: default
reason: RegisteredNode
firstTimestamp: '2023-09-06T19:08:47Z'
lastTimestamp: '2023-09-06T19:08:47Z'
involvedObject:
apiVersion: v1
kind: Node
name: standard-worker-1
uid: 50fb55c5-d97e-4851-85c6-187465154db6
message: 'Registered Node standard-worker-1 in Controller'
从本质上讲,Kubernetes 可以收集 Pod 日志、节点服务日志和事件。但是,在本文中,我们将重点关注 Pod 日志和节点服务日志,因为事件需要额外的软件来抓取它们,这涉及到 Kubernetes API,因此将其扩展到我们的范围之外。
什么是 Vector
现在,让我们看看 Vector 是怎么回事。
Vector 显著特征(以及我们使用它的原因)
根据官方网站的说法,Vector 是一个“用于构建可观测性管道的轻量级、超快速工具”。但是,作为 Vector 用户,我想稍微改写一下这个定义,强调与我们的情况最相关的功能:
Vector 是一个开源的高效工具,用于构建日志收集管道。
对我们来说,这个定义中有什么重要意义?
- 开源是我们必须在其上构建可信的、持久的解决方案并将其推荐给其他人的必要条件。
- 另一个重要因素是 Vector 的效率。如果一个工具是轻量级的,但不能处理大量数据,它就不能满足我们的要求。同样,如果一个工具速度超快,但消耗大量资源,它也不适合作为日志收集器。因此,效率起着至关重要的作用。
- 值得一提的是,Vector 收集其他类型数据的能力对我们来说并不重要,因为我们目前的重点是日志。
Vector 的一个特殊功能是其**与供应商无关。**尽管 Vector 归 Datadog 所有,但它与其他各种供应商的解决方案无缝集成,包括 Splunk、Grafana Cloud 和 Elasticsearch Cloud。这种灵活性确保了单个软件解决方案可以跨多个供应商使用。
Vector 提供的另一个令人愉快的好处是它消除了在 Rust 中重写 Go 应用程序以提高其性能的需要。Vector 已经是用 Rust 编写的。
此外,它被设计为高性能。这是如何实现的?Vector 具有一个 CI 系统,可以对任何提议的拉取请求运行基准测试。维护人员会严格评估新功能对 Vector 性能的影响。如果出现任何不利影响,请贡献者及时纠正问题,因为性能仍然是 Vector 团队的首要任务。
此外,Vector 是一个灵活的构建块,我们将在下面详细介绍。
Vector 的架构
作为一种处理工具,Vector 从各种来源收集数据。它通过抓取或充当 HTTP 服务器来积累其他工具摄取的数据来做到这一点。
Vector 擅长转换日志条目,可以将多条消息修改、删除或聚合为一条消息。(不要被下面架构图中所示的转换数量所迷惑,它提供了更多功能。
在此转换之后,Vector 处理消息并将其转发到存储或队列系统。
Vercor 架构:收集日志、转换日志并发送日志
简而言之,Vector 包含一种强大的转换语言,称为矢量重映射语言 (VRL),允许无限数量的可能转换。
矢量重映射语言示例
让我们快速浏览一下 VRL,然后从日志过滤开始。在下面的代码片段中,我们使用 VRL 表达式来确保 severity 字段不等于 :info
[transforms.filter_severity]
type = "filter"
inputs = ["logs"]
condition = '.severity != "info"'
当 Vector 收集 Pod 日志时,它还会使用其他 Pod 元数据(例如 Pod 名称、Pod IP 和 Pod 标签)来丰富日志行。但是,在 Pod 标签中,可能有一些标签只有 Kubernetes 控制器使用,因此对人类用户没有价值。为了获得最佳存储性能,我们建议删除以下标签:
[transforms.sanitize_kubernetes_labels]
type = "remap"
inputs = ["logs"]
source = '''
if exists(.pod_labels."controller-revision-hash") {
del(.pod_labels."controller-revision-hash")
}
if exists(.pod_labels."pod-template-hash") {
del(.pod_labels."pod-template-hash")
}
'''
下面是如何将多个日志行连接成一行的示例:
[transforms.backslash_multiline]
type = "reduce"
inputs = ["logs"]
group_by = ["file", "stream"]
merge_strategies."message" = "concat_newline"
ends_when = '''
matched, err = match(.message, r'[^\\]$');
if err != null {
false;
} else {
matched;
}
'''
在本例中,该字段将向消息字段添加换行符。最重要的是,该部分使用 VRL 表达式来检查一行是否以反斜杠结尾(以连接多行 Bash 注释的方式)。merge_strategies``ends_when
日志收集拓扑
好了,是时候探索几种不同的日志收集拓扑以用于 Vector 了。第一种是分布式拓扑,其中 Vector 代理部署在 Kubernetes 集群中的所有节点上。然后,这些代理收集、转换日志并将其直接发送到存储。
第二个是集中式拓扑。在其中,Vector 代理也在所有节点上运行,尽管它们不执行任何复杂的转换:聚合器会处理这些转换。这种设置的好处是其出色的负载可预测性。您可以为聚合器部署专用节点,并在必要时对其进行扩展,从而优化 Vector 在集群节点上的资源消耗。
第三种拓扑是基于流的方法。在其中,Kubernetes Pod 会尽快“摆脱”日志。日志被直接摄取到存储中,然后 Elasticsearch 解析日志行并调整索引,这可能是一个占用大量资源的过程。尽管如此,在 Kafka 的案例中,消息被简单地视为字符串。因此,我们可以轻松地从 Kafka 中检索这些日志,以便进一步存储和分析。
请注意,在本文中,我们不会介绍 Vector 充当聚合器的拓扑结构。相反,我们将只关注它作为群集节点上的日志收集代理的角色。
Kubernetes 中的 Vector
我们将如何看待 Kubernetes 中的 Vector?让我们看一下下面的 pod:
Kubernetes 部署为 DaemonSet 后的 Vector 容器
这样的设计乍一看可能很复杂,但这背后是有原因的。我们在这个 pod 中有三个容器:
- 第一个运行 Vector 本身。其主要目的是收集日志。
- 第二个容器称为 Reloader,使我们的平台用户能够创建自己的日志收集和引入管道。我们有一个特殊的运算符,它假设用户定义的规则并为 Vector 生成配置映射。Reloader 容器验证该配置映射并相应地重新加载 Vector。
- 第三个容器 Kube RBAC 代理起着至关重要的作用,因为 Vector 公开了有关其收集的日志行的各种指标。由于此信息可能是敏感的,因此必须通过适当的授权对其进行保护。
Vector 被部署为 DaemonSet(参见下面的列表),因为我们必须在 Kubernetes 集群中的所有节点上部署它的代理。
为了有效地收集日志,我们需要将额外的目录挂载到 Vector 中:
- 目录,因为如前所述,所有 Pod 的日志都存储在那里。
/var/log
- 最重要的是,我们需要将一个持久卷挂载到 Vector 中,用于存储检查点。每次 Vector 发送日志行时,它都会写入一个检查点,以避免重复发送到同一存储的日志。
- 此外,我们挂载 以查看节点的时区。
localtime
apiVersion: apps/v1
kind: DaemonSet
volumes:
- name: var-log
hostPath:
path: /var/log/
- name: vector-data-dir
hostPath:
path: /mnt/vector-data
- name: localtime
hostPath:
path: /etc/localtime
volumeMounts:
- name: var-log
mountPath: /var/log/
readOnly: true
terminationGracePeriodSeconds: 120
shareProcessNamespace: true
关于此列表的其他一些说明:
- 挂载目录时,请务必记住启用该模式。此预防措施可防止未经授权修改日志文件。
/var/log``readOnly
- 我们使用终止宽限期(120 秒)来确保 Vector 在重新启动之前完成分配给它的所有任务。
- 共享进程命名空间对于使 Reloader 能够向 Vector 发送信号以重新启动它至关重要。
这总结了我们在 Kubernetes 中部署 Vector 的设置。
接下来,让我们继续讨论最有趣的部分——实际用例。所有这些都不是假设的场景——它们是我们在值班期间遇到的真实世界的停电。
实际用例
案例 #1:设备空间不足
有一天,由于磁盘空间不足,所有 Pod 都被逐出节点。我们展开了调查,发现 Vector 实际上保留了已删除的文件。现在,为什么会这样?
- Vector 监视目录中的文件。
/var/log/pods
- 当应用程序主动写入日志时,文件大小会超过 10 兆字节的限制,达到 20、30、40、50…兆 字节。
- 在某些时候,kubelet 会轮换日志文件,使其恢复到原始大小 10 MB。
- 然而,与此同时,Vector 试图将日志发送给 Loki。不幸的是,Loki 无法处理如此大量的数据!
- Vector 作为一个负责任的软件,仍然打算将所有日志发送到存储中。
不幸的是,应用程序不会等待所有这些内部操作完成,它们只是继续运行。这导致 Vector 尝试保留所有日志文件,并且随着 kubelet 继续轮换它们,节点上的可用空间会耗尽。
那么,如何解决这个问题呢?
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
65632)]
[外链图片转存中…(img-jgDIzNfv-1715892065632)]
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!