Kubernetes 集群管理—日志架构

news2024/9/22 7:23:41

日志架构

应用日志可以让你了解应用内部的运行状况。日志对调试问题和监控集群活动非常有用。 大部分现代化应用都有某种日志记录机制。同样地,容器引擎也被设计成支持日志记录。 针对容器化应用,最简单且最广泛采用的日志记录方式就是写入标准输出和标准错误流。

但是,由容器引擎或运行时提供的原生功能通常不足以构成完整的日志记录方案。

例如,如果发生容器崩溃、Pod 被逐出或节点宕机等情况,你可能想访问应用日志。

在集群中,日志应该具有独立的存储,并且其生命周期与节点、Pod 或容器的生命周期相独立。 这个概念叫集群级的日志。

集群级日志架构需要一个独立的后端用来存储、分析和查询日志。 Kubernetes 并不为日志数据提供原生的存储解决方案。 相反,有很多现成的日志方案可以集成到 Kubernetes 中。 下面各节描述如何在节点上处理和存储日志。

Pod 和容器日志

Kubernetes 从正在运行的 Pod 中捕捉每个容器的日志。

此示例使用带有一个容器的 Pod 的清单,该容器每秒将文本写入标准输出一次。

debug/counter-pod.yaml

apiVersion: v1
kind: Pod
metadata:
  name: counter
spec:
  containers:
  - name: count
    image: busybox:1.28
    args: [/bin/sh, -c,
            'i=0; while true; do echo "$i: $(date)"; i=$((i+1)); sleep 1; done']

要运行此 Pod,请执行以下命令:

kubectl apply -f https://k8s.io/examples/debug/counter-pod.yaml

输出为:

pod/counter created

要获取这些日志,请执行以下 kubectl logs 命令:

kubectl logs counter

输出类似于:

0: Fri Apr  1 11:42:23 UTC 2022
1: Fri Apr  1 11:42:24 UTC 2022
2: Fri Apr  1 11:42:25 UTC 2022

你可以使用 kubectl logs --previous 从容器的先前实例中检索日志。 如果你的 Pod 有多个容器,请如下通过将容器名称追加到该命令并使用 -c 标志来指定要访问哪个容器的日志:

kubectl logs counter -c count

详见 kubectl logs 文档。

节点的容器日志处理方式

容器运行时对写入到容器化应用程序的 stdout 和 stderr 流的所有输出进行处理和转发。 不同的容器运行时以不同的方式实现这一点;不过它们与 kubelet 的集成都被标准化为 CRI 日志格式

默认情况下,如果容器重新启动,kubelet 会保留一个终止的容器及其日志。 如果一个 Pod 被逐出节点,所对应的所有容器及其日志也会被逐出。

kubelet 通过 Kubernetes API 的特殊功能将日志提供给客户端访问。 访问这个日志的常用方法是运行 kubectl logs。

日志轮转

特性状态: Kubernetes v1.21 [stable]

你可以配置 kubelet 令其自动轮转日志。

如果配置轮转,kubelet 负责轮转容器日志并管理日志目录结构。 kubelet(使用 CRI)将此信息发送到容器运行时,而运行时则将容器日志写到给定位置。

你可以使用 kubelet 配置文件配置两个 kubelet 配置选项、 containerLogMaxSize 和 containerLogMaxFiles。 这些设置分别允许你分别配置每个日志文件大小的最大值和每个容器允许的最大文件数。

当类似于基本日志示例一样运行 kubectl logs 时, 节点上的 kubelet 会处理请求并直接从日志文件读取。kubelet 将返回该日志文件的内容。

说明:

只有最新的日志文件的内容可以通过 kubectl logs 获得。

例如,如果 Pod 写入 40 MiB 的日志,并且 kubelet 在 10 MiB 之后轮转日志, 则运行 kubectl logs 将最多返回 10 MiB 的数据。

系统组件日志

系统组件有两种类型:通常在容器中运行的组件和直接参与容器运行的组件。例如:

  • kubelet 和容器运行时不在容器中运行。kubelet 运行你的容器 (一起按 Pod 分组)
  • Kubernetes 调度器、控制器管理器和 API 服务器在 Pod 中运行 (通常是静态 Pod。 etcd 组件在控制平面中运行,最常见的也是作为静态 Pod。 如果你的集群使用 kube-proxy,则通常将其作为 DaemonSet 运行。

日志位置

kubelet 和容器运行时写入日志的方式取决于节点使用的操作系统:

  • Linux
  • Windows

在使用 systemd 的 Linux 节点上,kubelet 和容器运行时默认写入 journald。 你要使用 journalctl 来阅读 systemd 日志;例如:journalctl -u kubelet。

如果 systemd 不存在,kubelet 和容器运行时将写入到 /var/log 目录中的 .log 文件。 如果你想将日志写入其他地方,你可以通过辅助工具 kube-log-runner 间接运行 kubelet, 并使用该工具将 kubelet 日志重定向到你所选择的目录。

kubelet 始终指示你的容器运行时将日志写入 /var/log/pods 中的目录。

有关 kube-log-runner 的更多信息,请阅读系统日志。

对于在 Pod 中运行的 Kubernetes 集群组件,其日志会写入 /var/log 目录中的文件, 相当于绕过默认的日志机制(组件不会写入 systemd 日志)。 你可以使用 Kubernetes 的存储机制将持久存储映射到运行该组件的容器中。

有关 etcd 及其日志的详细信息,请查阅 etcd 文档。 同样,你可以使用 Kubernetes 的存储机制将持久存储映射到运行该组件的容器中。

说明:

如果你部署 Kubernetes 集群组件(例如调度器)以将日志记录到从父节点共享的卷中, 则需要考虑并确保这些日志被轮转。 Kubernetes 不管理这种日志轮转

你的操作系统可能会自动实现一些日志轮转。例如,如果你将目录 /var/log 共享到一个组件的静态 Pod 中, 则节点级日志轮转会将该目录中的文件视同为 Kubernetes 之外的组件所写入的文件。

一些部署工具会考虑日志轮转并将其自动化;而其他一些工具会将此留给你来处理。

集群级日志架构

虽然 Kubernetes 没有为集群级日志记录提供原生的解决方案,但你可以考虑几种常见的方法。 以下是一些选项:

  • 使用在每个节点上运行的节点级日志记录代理。
  • 在应用程序的 Pod 中,包含专门记录日志的边车(Sidecar)容器。
  • 将日志直接从应用程序中推送到日志记录后端。

使用节点级日志代理

你可以通过在每个节点上使用节点级的日志记录代理来实现集群级日志记录。 日志记录代理是一种用于暴露日志或将日志推送到后端的专用工具。 通常,日志记录代理程序是一个容器,它可以访问包含该节点上所有应用程序容器的日志文件的目录。

由于日志记录代理必须在每个节点上运行,推荐以 DaemonSet 的形式运行该代理。

节点级日志在每个节点上仅创建一个代理,不需要对节点上的应用做修改。

容器向标准输出和标准错误输出写出数据,但在格式上并不统一。 节点级代理收集这些日志并将其进行转发以完成汇总。

使用边车容器运行日志代理

你可以通过以下方式之一使用边车(Sidecar)容器:

  • 边车容器将应用程序日志传送到自己的标准输出。
  • 边车容器运行一个日志代理,配置该日志代理以便从应用容器收集日志。

传输数据流的边车容器

利用边车容器,写入到自己的 stdout 和 stderr 传输流, 你就可以利用每个节点上的 kubelet 和日志代理来处理日志。 边车容器从文件、套接字或 journald 读取日志。 每个边车容器向自己的 stdout 和 stderr 流中输出日志。

这种方法允许你将日志流从应用程序的不同部分分离开,其中一些可能缺乏对写入 stdout 或 stderr 的支持。重定向日志背后的逻辑是最小的,因此它的开销不大。 另外,因为 stdout 和 stderr 由 kubelet 处理,所以你可以使用内置的工具 kubectl logs。

例如,某 Pod 中运行一个容器,且该容器使用两个不同的格式写入到两个不同的日志文件。 下面是这个 Pod 的清单:

admin/logging/two-files-counter-pod.yaml

apiVersion: v1
kind: Pod
metadata:
  name: counter
spec:
  containers:
  - name: count
    image: busybox:1.28
    args:
    - /bin/sh
    - -c
    - >
      i=0;
      while true;
      do
        echo "$i: $(date)" >> /var/log/1.log;
        echo "$(date) INFO $i" >> /var/log/2.log;
        i=$((i+1));
        sleep 1;
      done      
    volumeMounts:
    - name: varlog
      mountPath: /var/log
  volumes:
  - name: varlog
    emptyDir: {}

不建议在同一个日志流中写入不同格式的日志条目,即使你成功地将其重定向到容器的 stdout 流。 相反,你可以创建两个边车容器。每个边车容器可以从共享卷跟踪特定的日志文件, 并将文件内容重定向到各自的 stdout 流。

下面是运行两个边车容器的 Pod 的清单:

admin/logging/two-files-counter-pod-streaming-sidecar.yaml

apiVersion: v1
kind: Pod
metadata:
  name: counter
spec:
  containers:
  - name: count
    image: busybox:1.28
    args:
    - /bin/sh
    - -c
    - >
      i=0;
      while true;
      do
        echo "$i: $(date)" >> /var/log/1.log;
        echo "$(date) INFO $i" >> /var/log/2.log;
        i=$((i+1));
        sleep 1;
      done      
    volumeMounts:
    - name: varlog
      mountPath: /var/log
  - name: count-log-1
    image: busybox:1.28
    args: [/bin/sh, -c, 'tail -n+1 -F /var/log/1.log']
    volumeMounts:
    - name: varlog
      mountPath: /var/log
  - name: count-log-2
    image: busybox:1.28
    args: [/bin/sh, -c, 'tail -n+1 -F /var/log/2.log']
    volumeMounts:
    - name: varlog
      mountPath: /var/log
  volumes:
  - name: varlog
    emptyDir: {}

现在当你运行这个 Pod 时,你可以运行如下命令分别访问每个日志流:

kubectl logs counter count-log-1

输出类似于:

0: Fri Apr  1 11:42:26 UTC 2022
1: Fri Apr  1 11:42:27 UTC 2022
2: Fri Apr  1 11:42:28 UTC 2022
...
kubectl logs counter count-log-2

输出类似于:

Fri Apr  1 11:42:29 UTC 2022 INFO 0
Fri Apr  1 11:42:30 UTC 2022 INFO 0
Fri Apr  1 11:42:31 UTC 2022 INFO 0
...

如果你在集群中安装了节点级代理,由代理自动获取上述日志流,而无需任何进一步的配置。 如果你愿意,你可以将代理配置为根据源容器解析日志行。

即使对于 CPU 和内存使用率较低的 Pod(CPU 为几毫核,内存为几兆字节),将日志写入一个文件, 将这些日志流写到 stdout 也有可能使节点所需的存储量翻倍。 如果你有一个写入特定文件的应用程序,则建议将 /dev/stdout 设置为目标文件,而不是采用流式边车容器方法。

边车容器还可用于轮转应用程序本身无法轮转的日志文件。 这种方法的一个例子是定期运行 logrotate 的小容器。 但是,直接使用 stdout 和 stderr 更直接,而将轮转和保留策略留给 kubelet。

集群中安装的节点级代理会自动获取这些日志流,而无需进一步配置。 如果你愿意,你也可以配置代理程序来解析源容器的日志行。

注意,尽管 CPU 和内存使用率都很低(以多个 CPU 毫核指标排序或者按内存的兆字节排序), 向文件写日志然后输出到 stdout 流仍然会成倍地增加磁盘使用率。 如果你的应用向单一文件写日志,通常最好设置 /dev/stdout 作为目标路径, 而不是使用流式的边车容器方式。

如果应用程序本身不能轮转日志文件,则可以通过边车容器实现。 这种方式的一个例子是运行一个小的、定期轮转日志的容器。 然而,还是推荐直接使用 stdout 和 stderr,将日志的轮转和保留策略交给 kubelet。

具有日志代理功能的边车容器

如果节点级日志记录代理程序对于你的场景来说不够灵活, 你可以创建一个带有单独日志记录代理的边车容器,将代理程序专门配置为与你的应用程序一起运行。

说明:

在边车容器中使用日志代理会带来严重的资源损耗。 此外,你不能使用 kubectl logs 访问日志,因为日志并没有被 kubelet 管理。

下面是两个配置文件,可以用来实现一个带日志代理的边车容器。 第一个文件包含用来配置 fluentd 的 ConfigMap。

admin/logging/fluentd-sidecar-config.yaml

apiVersion: v1
kind: ConfigMap
metadata:
  name: fluentd-config
data:
  fluentd.conf: |
    <source>
      type tail
      format none
      path /var/log/1.log
      pos_file /var/log/1.log.pos
      tag count.format1
    </source>

    <source>
      type tail
      format none
      path /var/log/2.log
      pos_file /var/log/2.log.pos
      tag count.format2
    </source>

    <match **>
      type google_cloud
    </match>    

说明:

你可以将此示例配置中的 fluentd 替换为其他日志代理,从应用容器内的其他来源读取数据。

第二个清单描述了一个运行 fluentd 边车容器的 Pod。 该 Pod 挂载一个卷,flutend 可以从这个卷上拣选其配置数据。

admin/logging/two-files-counter-pod-agent-sidecar.yaml

apiVersion: v1
kind: Pod
metadata:
  name: counter
spec:
  containers:
  - name: count
    image: busybox:1.28
    args:
    - /bin/sh
    - -c
    - >
      i=0;
      while true;
      do
        echo "$i: $(date)" >> /var/log/1.log;
        echo "$(date) INFO $i" >> /var/log/2.log;
        i=$((i+1));
        sleep 1;
      done      
    volumeMounts:
    - name: varlog
      mountPath: /var/log
  - name: count-agent
    image: registry.k8s.io/fluentd-gcp:1.30
    env:
    - name: FLUENTD_ARGS
      value: -c /etc/fluentd-config/fluentd.conf
    volumeMounts:
    - name: varlog
      mountPath: /var/log
    - name: config-volume
      mountPath: /etc/fluentd-config
  volumes:
  - name: varlog
    emptyDir: {}
  - name: config-volume
    configMap:
      name: fluentd-config

从应用中直接暴露日志目录

从各个应用中直接暴露和推送日志数据的集群日志机制已超出 Kubernetes 的范围

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

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

相关文章

stm32 - 基础架构

stm32 - 基础架构 基础架构外设概念系统结构引脚定义晶振工程 基础架构 外设概念 NVIC &#xff08;内核外设&#xff09; SysTick &#xff08;内核外设&#xff09; 其他是片上外设 系统结构 内核引出三条总线 ICode 指令总线&#xff1a; 连接Flash闪存&#xff08;编写的…

数据结构与算法之美学习笔记:47 | 向量空间:如何实现一个简单的音乐推荐系统?

这里写自定义目录标题 前言算法解析总结引申 前言 本节课程思维导图&#xff1a; 很多人都喜爱听歌&#xff0c;以前我们用 MP3 听歌&#xff0c;现在直接通过音乐 App 在线就能听歌。而且&#xff0c;各种音乐 App 的功能越来越强大&#xff0c;不仅可以自己选歌听&#xff0…

【Docker】Linux中Docker镜像结构及自定义镜像,并且上传仓库可提供使用

目录 一、镜像结构 1. 基本结构 2. 常用命令 二、自定义镜像 1. 基本镜像 2. 进阶镜像 3. 完善镜像 三、镜像上传仓库 每篇一获 一、镜像结构 自定义 Docker 镜像有很多用途&#xff0c;以下是一些主要的应用场景&#xff1a; 一致性环境&#xff1a;通过自定义镜像&a…

PPT文档怎么转换PDF?一个方法教你快速实现

在我们的办公、学习中难免会遇到需要将ppt转pdf文件的需求。现在的网络中有各种各样的PDF转换工具&#xff0c;有些操作很复杂&#xff0c;有些需要下载软件非常麻烦。接下来&#xff0c;给大家分享一款草最简单还不用下载软件的PPT转PDF&#xff08;https://www.yasuotu.com/p…

黑马程序员JavaWeb开发|案例:tlias智能学习辅助系统(1)准备工作、部门管理

一、准备工作 1.明确需求 根据产品经理绘制的页面原型&#xff0c;对部门和员工进行相应的增删改查操作。 2.环境搭建 将使用相同配置的不同项目作为Module放入同一Project&#xff0c;以提高相同配置的复用性。 准备数据库表&#xff08;dept, emp&#xff09; 资料中包含…

C#基础-空处理

在c#中&#xff0c;值对象是没有办法赋值为null的。比如说&#xff0c;你想要定义一个布尔值&#xff0c;你的赋值数据要么得是true、要么就得是false&#xff0c;默认情况下我们永远没可能给这个布尔赋值为null&#xff0c;即使只是对这个变量进行声明而不初始化数据&#xff…

代码随想录算法训练营第四天| 24. 两两交换链表中的节点、19.删除链表的倒数第N个节点面试题 02.07. 链表相交、142.环形链表II

文档讲解&#xff1a;虚拟头节点&#xff0c;三指针&#xff0c;快慢指针&#xff0c;链表相交&#xff0c;环形链表&#xff0c; 技巧&#xff1a; 1、对于指针的操作要画图&#xff0c;明确步骤后好做了 2、使用虚拟头节点可以避免对头节点单独讨论&#xff0c;且方便对头节点…

详解CAS及ABA问题

&#x1f308;&#x1f308;&#x1f308;今天给大家分享的是 CAS 问题。 清风的CSDN博客 &#x1f6e9;️&#x1f6e9;️&#x1f6e9;️希望我的文章能对你有所帮助&#xff0c;有不足的地方还请各位看官多多指教&#xff0c;大家一起学习交流&#xff01; ✈️✈️✈️动动…

【工具栏】SequenceDiagram插件的使用(根据代码生成时序图)

1. 安装 2.使用 进入代码页面&#xff0c;点击鼠标右键 选择方法 根据方法中的代码生成时序图

【LangChain学习之旅】—(8) 输出解析:用OutputParser生成鲜花推荐列表

【LangChain学习之旅】—&#xff08;8&#xff09; 输出解析&#xff1a;用OutputParser生成鲜花推荐列表 LangChain 中的输出解析器Pydantic&#xff08;JSON&#xff09;解析器实战第一步&#xff1a;创建模型实例第二步&#xff1a;定义输出数据的格式第三步&#xff1a;创…

AI-数学-高中-4.函数表达式特性-要变一起变

求f(x):换元法&#xff1a;左边代换时&#xff0c;右边也要同时替换&#xff0c;原作者视频&#xff1a;函数】1引导课&#xff1a;高中为什么用f(x)_哔哩哔哩_bilibili 1.什么是函数&#xff1a;给定任意一个x&#xff0c;都有唯一确定的y与之对应&#xff0c;这种x与y的关系就…

猫头虎分享:探索TypeScript的世界 — TS基础入门 ‍

博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝典&#xff01;《IDEA开发秘籍》 — 提升你的IDEA技能&#xff01;《100天精通Golang》…

UML-类图和类图转化为代码

提示&#xff1a;文章详细的讲解了类图的四种关系&#xff0c;以及每种关系如何转化为对应的代码。 UML-类图和类图转化为代码 一、类于类之间的关系1.依赖关系2.关联关系(1) 单向关联(2) 双向关联(3) 自关联(4) 聚合关联(has-a)(5) 组合关联&#xff08;contains-a&#xff09…

当浏览器输入url的时候会发生什么?

说在前面 当我们在浏览器中输入URL并按下回车时&#xff0c;背后发生了一系列神秘的操作。本文将带您深入了解&#xff0c;从URL解析到页面渲染&#xff0c;揭秘浏览器输入URL的完整流程。 具体步骤 当浏览器输入URL时&#xff0c;一般经过以下细节步骤&#xff1a; 1、引言 …

【GDAL】Windows下VS+GDAL开发环境搭建

Step.0 环境说明&#xff08;vs版本&#xff0c;CMake版本&#xff09; 本地的IDE环境是vs2022&#xff0c;安装的CMake版本是3.25.1。 Step.1 下载GDAL和依赖的组件 编译gdal之前需要安装gdal依赖的组件&#xff0c;gdal所依赖的组件可以在官网文档找到&#xff0c;可以根据…

【学习心得】Git深入学习

若您还未安装Git或是只想简单使用&#xff0c;可以先看看我的文章“Git快速上手”http://t.csdnimg.cn/gsaGj 一、深入学习Git必须熟悉两个概念 &#xff08;1&#xff09;【四个区】Git本地有三个区&#xff0c;远程仓库也可以看出成一个区域 工作区、暂存区、本地仓库、远…

AI教我学编程之C#变量及实例演示

前言 在AI教我学编程之AI自刀 这篇文章中&#xff0c;我们知道了变量的基础类型&#xff0c;那么变量在C#中有什么作用呢&#xff1f;我们一起来看看吧&#xff01; 目录 重点先知 变量 变量类型 实例演示 变量声明 实例演示 提出疑问 初始化变量 自动初始化 多变量声明 实…

关于浏览器缓存的一些坑记录

1.js强制刷新浏览器缓存 网络上一搜基本都说用location.reload(true)可以强制刷新缓存&#xff0c;但是没人讲这个方法只准对火狐浏览器生效,火狐浏览器的确可以实现强制刷新并每次请求都是新的没有走缓存&#xff1b;chrome依然是走200 状态 缓存。 MDN解析&#xff1a; 2.m…

Python教程(23)——Python类中常用的特殊成员

在Python中&#xff0c;类特殊成员是指以双下划线开头和结尾的属性和方法&#xff0c;也被称为魔术方法&#xff08;Magic methods&#xff09;或特殊方法&#xff08;Special methods&#xff09;。这些特殊成员在类的定义中具有特殊的语法和功能&#xff0c;用于实现对象的特…

【python入门】day26: 模拟高铁售票系统

界面 代码 #-*- coding:utf-8 -*- import prettytable as pt#---------导入漂亮表格 import os.path filename ticket.txt#更新座位状态 def update(row_num):#------更新购票状态with open(filename,w,encodingutf-8) as wfile:for i in range(row_num):lst1 [f{i1},有票,有…