使用 Vector 在 Kubernetes 中收集日志

多年来,我们一直在使用 Vector 在我们的 Kubernetes 平台中收集日志,并成功地将其应用于生产中以满足各种客户的需求,并且非常享受这种体验。因此,我想与更大的社区分享它,以便更多的 K8s 运营商可以看到潜力并考虑他们自己的设置的好处。

为此,我将首先简要回顾一下 Kubernetes 中可以收集哪些类型的信息。然后,我将探讨 Vector、它的架构以及我们为什么如此喜欢它。最后,我将分享我们对 Vector 的实际用例和实际经验。

Kubernetes 中的日志记录

让我们看一下 Kubernetes 中的日志。虽然 Kubernetes 的主要目标是在节点上运行容器,但必须记住,这些容器通常是根据 Heroku 的 12 个因素开发的。那么,他们如何在 Kubernetes 中生成日志,谁是其他生产者,日志驻留在何处?

1. 应用程序(pod)日志

在 K8s 中运行的应用程序将其日志写入 stdout 或 .然后,容器运行时收集这些日志并将其存储在一个目录中,该目录通常为 stderr/var/log/pods.它是可配置的,可以根据特定要求进行定制。

2. 节点服务日志

最重要的是,Kubernetes 节点上有一些服务在容器外部运行,例如 containerd 和 kubelet

牢记这些服务并从 syslog 中收集相关消息(例如 SSH 身份验证消息)至关重要。

此外,在某些情况下,容器会将其日志写入特定的文件路径。例如,kube-apiserver,它通常会写入审计日志。因此,需要从相应的节点收集这些日志。

3. Events

Kubernetes 日志收集的另一个重要方面是事件。它们具有独特的结构,因为它们仅存在于 etcd 中,因此为了收集它们,您必须向 Kubernetes API 发出请求。

由于 reason 字段(请参阅下面的示例清单)和 count 字段(用作计数器,随着记录的事件越来越多而递增),因此可以将事件视为指标

此外,还可以将事件收集为跟踪、特征和字段,这有助于创建全面的甘特图,以说明集群中的所有事件。firstTimestamp lastTimestamp

最后,事件提供人类可读的消息(字段),使它们能够作为日志收集。message

apiVersion: v1
kind: Event
count: 1
metadata:name: standard-worker-1.178264e1185b006fnamespace: default
reason: RegisteredNode
firstTimestamp: '2023-09-06T19:08:47Z'
lastTimestamp: '2023-09-06T19:08:47Z'
involvedObject:apiVersion: v1kind: Nodename: standard-worker-1uid: 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 中有三个容器:

  1. 第一个运行 Vector 本身。其主要目的是收集日志。
  2. 第二个容器称为 Reloader,使我们的平台用户能够创建自己的日志收集和引入管道。我们有一个特殊的运算符,它假设用户定义的规则并为 Vector 生成配置映射。Reloader 容器验证该配置映射并相应地重新加载 Vector。
  3. 第三个容器 Kube RBAC 代理起着至关重要的作用,因为 Vector 公开了有关其收集的日志行的各种指标。由于此信息可能是敏感的,因此必须通过适当的授权对其进行保护。

Vector 被部署为 DaemonSet(参见下面的列表),因为我们必须在 Kubernetes 集群中的所有节点上部署它的代理。

为了有效地收集日志,我们需要将额外的目录挂载到 Vector 中:

  • 目录,因为如前所述,所有 Pod 的日志都存储在那里。/var/log
  • 最重要的是,我们需要将一个持久卷挂载到 Vector 中,用于存储检查点。每次 Vector 发送日志行时,它都会写入一个检查点,以避免重复发送到同一存储的日志。
  • 此外,我们挂载 以查看节点的时区。localtime
apiVersion: apps/v1
kind: DaemonSet
volumes:
- name: var-loghostPath:path: /var/log/
- name: vector-data-dirhostPath:path: /mnt/vector-data
- name: localtimehostPath:path: /etc/localtime
volumeMounts:
- name: var-logmountPath: /var/log/readOnly: true
terminationGracePeriodSeconds: 120
shareProcessNamespace: true

关于此列表的其他一些说明:

  1. 挂载目录时,请务必记住启用该模式。此预防措施可防止未经授权修改日志文件。/var/logreadOnly
  2. 我们使用终止宽限期(120 秒)来确保 Vector 在重新启动之前完成分配给它的所有任务。
  3. 共享进程命名空间对于使 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 继续轮换它们,节点上的可用空间会耗尽。

那么,如何解决这个问题呢?

  1. 首先,您可以从调整缓冲区设置开始。默认情况下,如果 Vector 无法将所有日志发送到存储,则会将其存储在内存中。默认缓冲区容量限制为仅 1000 条消息,这是相当低的。您可以将其扩展到 10000。
  2. 或者,将行为从阻止更改为删除新日志也可能有所帮助。通过该行为,Vector 将简单地丢弃其缓冲区中无法容纳的任何日志。drop newest
  3. 另一种选择是使用磁盘缓冲区而不是内存缓冲区。不利的一面是 Vector 会花费更多时间在输入输出操作上。在这种情况下,在决定此方法是否适合您时,必须考虑性能要求。

消除此问题的经验法则是采用流拓扑。通过允许日志尽快离开节点,可以降低生产应用程序中断的风险。我们当然不想因为监控问题而毁掉生产集群,不是吗?

最后,如果你足够勇敢,你可以用它来调整一个进程的最大打开文件数。但是,我不推荐这种方法。sysctl

案例#2:Prometheus “爆炸”

Vector 在一个节点上运行并执行几个不同的任务。它从 Pod 收集日志,并公开收集的日志行数和遇到的错误数等指标。这要归功于 Vector 卓越的可观测性功能。

但是,许多指标都有特定的文件标签,这可能会导致高基数,这是 Prometheus 无法消化的。这是因为当 Pod 重新启动时,Vector 开始公开新 Pod 的指标,同时仍保留旧 Pod 的指标,这意味着这些指标具有不同的文件标签。此行为是 Prometheus 导出器工作方式(按设计)的结果。不幸的是,在几个吊舱重新启动后,这种情况导致普罗米修斯的负载突然激增,随后发生了“爆炸”。

为了解决这个问题,我们应用了一个指标标签规则来消除麻烦的文件标签。这解决了 Prometheus 的问题——它现在运行正常。

然而,一段时间后,Vector 遇到了自己的问题。问题是,Vector 消耗了越来越多的内存来存储所有这些指标,导致内存泄漏。为了纠正这个问题,我们在 Vector 中使用了一个全局选项,称为:expire_metric_secs

  • 如果将其设置为 60 秒,Vector 将检查它是否仍在从这些 pod 收集数据。
  • 否则,它将停止导出这些文件的指标。

尽管此解决方案有效运行,但它也影响了其他一些指标,例如 Vector 组件错误指标。如下图所示,最初记录了 7 个错误,但在触发过期后,数据中出现了差距。

不幸的是,Prometheus,尤其是 PromQL 函数(和类似函数),无法处理这样的数据差距。相反,Prometheus 希望指标在整个时间段内公开。rate

为了解决这个限制,我们修改了 Vector 的代码,以完全消除文件标签——只需删除几个地方的“文件”条目即可。事实证明,此解决方法已成功解决该问题。

案例 #3:Kubernetes 控制平面中断

有一天,我们注意到当 Vector 实例同时重启时,Kubernetes 控制平面往往会失败。在分析我们的仪表板后,我们确定这个问题源于过度的内存使用,主要是 etcd 内存消耗。

为了更好地理解根本原因,我们首先需要深入研究 Kubernetes API 的内部工作原理。

当 Vector 实例启动时,它向 Kubernetes API 发出请求,以使用 Pod 元数据填充缓存。如前所述,Vector 依赖于此元数据来丰富日志条目。LIST

因此,每个 Vector 实例都请求 Kubernetes API 为 Vector 运行的同一节点上的 Pod 提供元数据。但是,对于每个单独的请求,Kubernetes API 都会从 etcd 读取。

etcd 用作键值数据库。键由资源的种类、命名空间和名称组成。对于节点上涉及 110 个 Pod 的每个请求,Kubernetes API 都会访问 etcd 并检索所有 Pod 的数据。这会导致 kube-apiserver 和 etcd 的内存使用量激增,最终导致它们失败。

此问题有两种可能的解决方案。首先,我们可以采用缓存读取方法。在这种方法中,我们指示 API 服务器从其现有的缓存中读取数据,而不是从 etcd 中读取数据。尽管在某些情况下可能会出现不一致,但这对于监视工具来说是可以接受的。不幸的是,这样的功能在 Kubernetes Rust 客户端中不可用。因此,我们向 Vector 提交了一个拉取请求,启用了该选项。use_apiserver_cache=true

第二种解决方案涉及利用 Kubernetes 优先级和公平性 API 的独特功能。问题是,你可以定义一个请求队列:

apiVersion: flowcontrol.apiserver.k8s.io/v1beta1
kind: PriorityLevelConfiguration
metadata:name: limit-list-custom
spec:type: Limitedlimited:assuredConcurrencyShares: 5limitResponse:queuing:handSize: 4queueLengthLimit: 50queues: 16type: Queue

...并将其与特定服务帐户相关联:

apiVersion: flowcontrol.apiserver.k8s.io/v1beta1
kind: FlowSchema
metadata:name: limit-list-custom
spec:priorityLevelConfiguration:name: limit-list-customdistinguisherMethod:type: ByUserrules:- resourceRules:- apiGroups: [""]clusterScope: truenamespaces: ["*"]resources: ["pods"]verbs: ["list", "get"]subjects:- kind: ServiceAccountserviceAccount:name: ***namespace: ***

通过此类配置,您可以限制并发预检请求的数量,并有效降低峰值的严重性,从而最大程度地减少其影响。

最后,您可以使用 kubelet API 通过向 /pods 端点发送请求来获取 Pod 元数据,而不是依赖 Kubernetes API。但是,此功能尚未在 Vector 中实现。

结论

Vector 非常适合平台工程工作,因为它具有灵活性、多功能性和日志摄取和传输选项的广度。我全心全意地推荐 Vector,并鼓励您充分利用它的功能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/640146.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【 CSS 】基础1

“坚持就是胜利。” - 温斯顿丘吉尔 【 CSS 】基础 1 CSS 简介 CSS 是层叠样式表 ( Cascading Style Sheets ) 的简称.有时我们也会称之为 CSS 样式表或级联样式表。CSS 也是一种标记语言CSS 主要用于设置 HTML 页面中的文本内容(字体、大小、对齐方式等&#xff…

Python使用gRPC入门,定义proto文件和收发消息

gRPC 一开始由 google 开发,是一款语言中立、平台中立、开源的远程过程调用(RPC)系统。 本文通过一个简单的 Hello World 例子来向您介绍 gRPC 。 Grpc官方文档地址:Quick start | Python | gRPC gRPC 是什么? gRPC 也是基于以下理念&#…

Python武器库开发-武器库篇之Quake360-API使用(四十七)

Python武器库开发-武器库篇之Quake360-API使用(四十七) Quake360是一款网络资产搜索引擎,旨在帮助用户快速定位和识别网络上的资产信息。它具有强大的搜索功能,可以搜索并展示各种类型的网络资产,包括域名、IP地址、子域名、端口信息等。同时…

Unity编程#region..#endregion以及面板提示语标签[Tooltip(““)]

C#中的#region..#endregion 在Unity中,#region和#endregion是用于代码折叠的预处理指令。它们并不是Unity特有的,而是C#语言本身提供的功能。 #region用于标记一段代码的开始,而#endregion用于标记一段代码的结束。在编辑器中,可…

橡木桶陈酿:木材选择、烤制程度与陈酿时间

在威士忌的酿造过程中,橡木桶陈酿是一个至关重要的环节。橡木桶不仅为威士忌提供了特别的香气和风味,还赋予其丰富的颜色和味蕾。本文将深入探讨橡木桶陈酿的奥秘,特别是木材选择、烤制程度以及陈酿时间对威士忌风味的影响,以雷盛…

【Linux】解决普通用户无法进行sudo提权

当某个普通用户进行sudo指令提权的时候,可能存在无法操作的问题,如下图: 这个图中有一个细节,我们使用sudo进行提权的时候,用的可是zhangsan的密码,因此有人可能会有疑问,这不是有问题吗&#x…

安泰电子电压放大器的三个特性是指什么

电压放大器是一种主要用于将输入电压信号放大的电子器件。它的工作原理是通过增加电压信号的幅度,使得输出信号比输入信号有更大的电压差。电压放大器通常具有许多特性,其中三个主要特性包括增益、带宽和线性度。 增益是电压放大器最重要的特性之一。增益…

RabbitMQ-消息延迟

一、死信交换机 1、描述 一个队列接收到的消息有过期时间,消息过期之后,如果配置有死信队列,消息就会进去死信队列。 2、图解 3、过程 当生产者将消息发送到exchange1,然后交换机将消息路由到队列queue1,但是队列que…

JavaScript进阶:WebAPIs重点知识整理1

目录 1 DOM修改元素内容 2 DOM修改元素常见属性 3 修改元素样式属性 3.1 通过style修改元素样式 3.2 通过类名className修改元素样式 3.3 通过classList修改元素样式 4 操作表单元素属性 5 自定义属性 6 定时器 7 事件监听 7.1 点击事件 click 7.2 鼠mouseenter和移…

【Linux】权限 !

Linux 权限 Liunx Linux 权限1 什么是权限1.1 Linux用户1.2 切换用户 2 权限管理2.1 文件访问者的分类2.2 文件类型和访问权限2.3 文件权限的设置方法chmod 命令chown 命令chgrp 命令umask 命令file 指令 2.4 目录权限粘滞位 3 权限总结 1 什么是权限 关于Linux的权限问题&…

项目风险管理

风险分类: 分类性质:纯粹风险,投机风险---对应火灾,股票买卖 产生原因:自然,社会,政治,经济,技术 风险性质:客观性,偶然性,相对性&a…

28个炫酷的纯CSS特效动画示例(含源代码)

CSS是网页的三驾马车之一,是对页面布局的总管家,2024年了,这里列出28个超级炫酷的纯CSS动画示例,让您的网站更加炫目多彩。 文章目录 1. 涌动的弹簧效果2. 超逼真的3D篮球弹跳,含挤压弹起模态3. 鼠标放div上&#xff0…

基于ICEEMDAN-SpEn(样本熵)联合小波阈值去噪

代码原理 以样本熵为阈值的ICEEMDAN(Incomplete Ensemble Empirical Mode Decomposition with Adaptive Noise)联合小波阈值去噪是一种信号处理方法,用于去除信号中的噪声。它结合了ICEEMDAN分解和小波阈值去噪方法。 以下是该方法的步骤&a…

MySQL---多表分组查询综合练习

创建dept表 CREATE TABLE dept ( deptno INT(2) NOT NULL COMMENT 部门编号, dname VARCHAR (15) COMMENT 部门名称, loc VARCHAR (20) COMMENT 地理位置 ); 添加dept表主键 mysql> alter table dept add primary key(deptno); Query OK, 0 rows affected (0.02 s…

CPMS靶场练习

关键:找到文件上传点,分析对方验证的手段 首先查看前端发现没有任何上传的位置,找到网站的后台,通过弱口令admin 123456可以进入 通过查看网站内容发现只有文章列表可以进行文件上传;有两个图片上传点 图片验证很严格…

a16z Web3行业展望 2024:新的一年,新的理念,新的方式

原文标题:《new year, new ideas, new ways》 撰文:a16z Crypto 编译:Carl,Techub News 原文链接:a16z Web3行业展望 2024:新的一年,新的理念,新的方式 a16z 此前发布了2024 年「…

ubuntu使用docker compose一键部署项目

1、将前面手动部署的容器和镜像全部删除 docker rmi hmall (hmall镜像名) docker rmi image_id rmi 是删除多个 rm是删除一个 2、执行命令 docker compose up -d http://192.168.79.129:18080/search.html 访问安装成功! 该ip是虚拟机ubuntu的ip 3、docker-compos…

pnpm使用

文章目录 前言一、安装二、设置镜像三、使用总结如有启发,可点赞收藏哟~ 前言 pnpm 全称 performant npm,意思为 高性能的 npm 速度快、节约磁盘空间、支持 monorepo、安全性高。 一、安装 npm install -g pnpm or brew install pnpm二、设置镜像 #…

Vue.js在养老院管理系统前端开发中的应用与优化

✍✍计算机编程指导师 ⭐⭐个人介绍:自己非常喜欢研究技术问题!专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目:有源码或者技术上的问题欢迎在评论区一起讨论交流! ⚡⚡ Java实战 |…

【Java程序员面试专栏 专业技能篇】MySQL核心面试指引(二):核心机制策略

关于MySQL部分的核心知识进行一网打尽,包括三部分:基础知识考察、核心机制策略、性能优化策略,通过一篇文章串联面试重点,并且帮助加强日常基础知识的理解,全局思维导图如下所示 本篇Blog为第二部分:核心机制策略,子节点表示追问或同级提问 日志机制 关于MySQL的几…