#yyds干货盘点# 如何在 Kubernete 中做日志收集与管理(14)
说到日志,你应该不陌生。日志中不仅记录了代码运行的实时轨迹,往往还包含着一些关键的数据、错误信息,等等。日志方便我们进行分析统计及监控告警,尤其是在后期问题排查的时候,我们通过日志可以很方便地定位问题、现场复现及问题修复。日志也是做可观测性(Observability)必不可少的一部分。
因此在使用 Kubernetes 的过程中,对应的日志收集也是我们不得不考虑的问题。我们需要日志去了解集群内部的运行状况。
我们先来看看 Kubernetes 的日志收集和以往的日志收集有什么差别,以及为什么我们需要为 Kubernetes 的日志收集单独设计方案。
Kubernetes 中的日志收集 VS 传统日志收集
对于传统的应用来说,它们大都都是直接运行在宿主机上的,会将日志直接写入本地的文件中或者由 systemd-journald 直接管理。在做日志收集的时候,只需要访问这些日志所在的目录即可。此类日志系统解决方案非常多,也相对比较成熟,在这里就不再过多说明。我们重点来看看 Kubernetes 的日志系统建设问题。
在 Kubernetes 中,日志采集相比传统虚拟机、物理机方式要复杂很多。
首先,日志的形式非常多样化。日志需求主要集中在如下三个部分:
- 系统各组件的日志,比如 Kubernetes 自身各大组件的日志(包括 kubelet、kube-proxy 等),容器运行时的日志(比如 Docker);
- 以容器化方式运行的应用程序自身的日志,比如 Nginx、Tomcat 的运行日志;
- Kubernetes 内部各种 Event(事件),比如通过
kubebctl create
创建一个 Pod 后,可以通过kubectl describe pod pod-xxx
命令查看到的这个 Pod 的 Event 信息。
其次,集群环境时刻在动态变化。我们都知道 Pod “用完即焚”,Pod 销毁后日志也会一同被删除。但是这个时候我们仍然希望可以看到具体的日志,用于查看和分析业务的运行情况,以及帮助我们发现出容器异常的原因。
同时新的 Pod 可能随时会“飘”到别的节点上重新“生长”出来,我们无法提前预知具体是哪个节点。而且 Kubernetes 的节点也会存在宕机等异常情况。所以说,Kubernetes 的日志系统在设计的时候,必须得独立于节点和 Pod 的生命周期,且保证日志数据可以实时采集到服务端,即完全独立于 Kubernetes 系统,使用自己的后端存储和查询工具。
再次,日志规模会越来越大。很多人在 Kubernetes 中喜欢使用 hostpath 来保存 Pod 的日志,并且不做日志轮转(可以配置 Docker 的log-opts
来设置容器的日志轮转 ),这很容易将宿主机的磁盘“打爆”。这里你是不是觉得如果做了轮转,磁盘打爆的问题就可以完美解决了?
其实虽有所缓解,并不会让你安全无忧。虽说日志轮转可以有效减少日志的文件大小,但是你会丢失掉不少日志,后续想要分析和排查问题时就无从下手了。想想看如果容器内的应用出现异常并疯狂报错,这个时候又有大量的并发请求,那么日志就会急剧增多。
配置了日志轮转,会让你丢失很多重要的上下文信息。如果没有配置日志轮转,这些日志很快就会将磁盘打爆。还有可能引发该节点的 Kubelet 异常,导致该节点上的 Pod 被驱逐。我们在一些生产实践中,就遇到过这种情况。同时当 Pod 被删除后,这些 hostpath 的文件并不会被及时删除,会继续占用很多磁盘空间。此外,随着业务逐渐增长,在这个节点上运行过的 Pod 也会变多,这就会残留大量的日志文件。
此外,日志非常分散且种类多变。单纯查找一个应用的日志,就需要查看其关联的分散在各个节点上的各个 Pod 的日志。在出现紧急情况需要排查的时候,这种方式极其低效,会严重影响到问题修复和服务恢复。如果这个应用还通过 Ingress 对外暴露服务,并使用了 Service Mesh 等,那么此时做日志收集就更复杂了。
随着在 Kubernetes 上落地越来越多的微服务,各个服务之间的依赖也越来越多。这个时候各个维度的日志关联也是一个非常困难的问题。那么,下面我们就来看看如何对 Kubernetes 做日志收集。
几种常见的 Kubernetes 日志收集架构
Kubernetes 集群本身其实并没有提供日志收集的解决方案,但依赖 Kubernetes 自身提供的各项能力,可以帮助我们解决日志收集的诉求。根据上面提到的三大基本日志需求,一般来说我们有如下有三种方案来做日志收集:
- 直接在应用程序中将日志信息推送到采集后端;
- 在节点上运行一个 Agent 来采集节点级别的日志;
- 在应用的 Pod 内使用一个 Sidecar 容器来收集应用日志。
我们来分别看看这三种方式。
logging from application
先来看直接在应用程序中将日志信息推送到采集后端,即Pod 内的应用直接将日志写到后端的日志中心。
通常有两种做法,一个就是应用程序通过对应的日志 SDK 进行接入,不过这种做法一般不推荐,和应用本身耦合太严重,也不方便后续对接其他的日志系统。
还有一种做法就是通过容器运行时提供的 Logging Driver 来实现。以最常用的 Docker 为例,目前已经支持了十多种 Logging Driver。比如你可以配置为fluentd
,这个时候 Docker 就会将容器的标准输出日志(stdout、stderr)直接写到fluentd
中。你也可以设置成awslogs
,这样就会直接将日志写到 Amazon CloudWatch Logs 中。但是在和 Kubernetes 一起使用的时候,使用较多的是json-file
,这也是 Docker 默认的 Logging Driver。
$ docker info |grep 'Logging Driver'
Logging Driver: json-file
你经常使用的kubectl logs
就是基于json-flle
这种 Logging Driver 来实现的,目前 Kubernetes 也只支持json-flle
这一种 Logging Driver。
所以在 Kubernetes 的这套体系中,直接将日志写到后端日志采集系统中去,并不是特别好的做法。
logging with node agent
我们来看第二种方法,在节点上运行一个 Agent 来采集节点级别的日志。如下图所示,我们可以在每一个 Kubernetes Node 上都部署一个 Agent,该 Agent 负责对该节点上运行的所有容器进行日志收集,并推送到后端的日志存储系统里。这个 Agent 通常需要可以访问到宿主机上的指定目录,比如/var/lib/docker/containers/
。
由于这样的 Agent 需要在每个 Node 上都运行,因此我们都是通过 上节课讲到的DaemonSet
的方式来部署的。对于 Kubernetes 集群来说,这种使用节点级的DaemonSet
日志代理是最常用,也是最被推荐的方式,不仅可以节约资源,而且对于应用来说也是无侵入的。
但是这种方式也有个缺点,就是只适应于容器内应用日志是标准输出的场景,即应用把日志输出到stdout
和stderr
。
logging with sidecar agent
最后来看通过 Sidecar 来收集容器日志。 在 Pod 里面,容器的输出日志可以是stdout
、stderr
和日志文件。那么基于这三种形式,我们可以借助于 Sidecar 容器将基于文件的日志来帮助我们。
- 通过Sidecar 容器读取日志文件,并定向到自己的标准输出。如下图所示,这里
streaming container
就是一个 Sidecar 容器,可以将app-container
的日志文件重新定向到自己的标准输出。同时还可以归并多个日志文件。而且这里也可以使用多个 Sidecar 容器,你可以参考这个例子。
- Sidecar容器运行一个日志代理,配置该日志代理以便从应用容器收集日志。这种方式就解决了我们上面方案一的问题,将日志处理部分和应用程序本身进行了解耦,可以方便切换到其他的日志系统中。可以参考这个使用 fluentd 的例子。
可以看到,通过 Sidecar 的方式来收集日志,会增加额外的开销。在集群规模较小的情况下可以忽略不计,但是对于大规模集群来说,这些开销还是不可忽略的。
那么,上面的这几套方案,在实际使用的时候,又该如何选择呢?社区又有什么推荐方案呢?
基于 Fluentd + ElasticSearch 的日志收集方案
Kubernetes 社区官方推荐的方案是使用 Fluentd+ElasticSearch+Kibana 进行日志的收集和管理,通过Fluentd将日志导入到Elasticsearch中,用户可以通过Kibana来查看到所有的日志。
关于 ElasticSearch 和 Kibana 如何部署,在此就不过多地介绍了,你可以通过添加 helm 的 repo 即helm repo add elastic https://helm.elastic.co
,然后通过 helm来快速地自行部署,相关的 Chart 见https://github.com/elastic/helm-charts。
Fluentd 提供了强大的日志统一接入能力,同时内置了插件,可以对接 ElasticSearch。这里 Fluentd 主要有如下四个配置:
fluent.conf
这个文件主要是用来设置一些地址,比如 ElasticSearch 的地址等;.kubernetes.conf
这个文件记录了与 Kubernetes 相关的配置,比如 Kubernetes 各组件的日志配置、容器的日志收集规则,等等;prometheus.conf
这个文件定义了 Prometheus 的地址,方便 Fluentd 暴露自己的统计指标;systemd.conf
这个文件可以配置 Fluentd 通过 systemd-journal 来收集哪些服务的日志,比如 Docker 的日志、Kubelet 的日志等。
上面的这些配置,都默认内置到了 fluent/fluentd-kubernetes-daemonset的镜像中,你可以使用官方的默认配置。如果你想要定制化更改一些,可以参照这份默认示例配置。
如下的 YAML 是一段 fluentd 的 DaemonSet 定义,源自这里:
apiVersion: apps/v1
kind: DaemonSet
metadata:name: fluentdnamespace: kube-systemlabels:k8s-app: fluentd-loggingversion: v1
spec:selector:matchLabels:k8s-app: fluentd-loggingversion: v1template:metadata:labels:k8s-app: fluentd-loggingversion: v1spec:tolerations:- key: node-role.kubernetes.io/mastereffect: NoSchedulecontainers:- name: fluentdimage: fluent/fluentd-kubernetes-daemonset:v1-debian-elasticsearchenv:- name: FLUENT_ELASTICSEARCH_HOSTvalue: "elasticsearch-logging"- name: FLUENT_ELASTICSEARCH_PORTvalue: "9200"- name: FLUENT_ELASTICSEARCH_SCHEMEvalue: "http"# Option to configure elasticsearch plugin with self signed certs# ================================================================- name: FLUENT_ELASTICSEARCH_SSL_VERIFYvalue: "true"# Option to configure elasticsearch plugin with tls# ================================================================- name: FLUENT_ELASTICSEARCH_SSL_VERSIONvalue: "TLSv1_2"# X-Pack Authentication# =====================- name: FLUENT_ELASTICSEARCH_USERvalue: "elastic"- name: FLUENT_ELASTICSEARCH_PASSWORDvalue: "changeme"# Logz.io Authentication# ======================- name: LOGZIO_TOKENvalue: "ThisIsASuperLongToken"- name: LOGZIO_LOGTYPEvalue: "kubernetes"resources:limits:memory: 200Mirequests:cpu: 100mmemory: 200MivolumeMounts:- name: varlogmountPath: /var/log- name: varlibdockercontainersmountPath: /var/lib/docker/containersreadOnly: trueterminationGracePeriodSeconds: 30volumes:- name: varloghostPath:path: /var/log- name: varlibdockercontainershostPath:path: /var/lib/docker/containers
最后
在实际采集日志的时候,你可以根据自己的场景和集群规模选择适用的方案。或者也可以将上面的这几种方案进行合理地组合。
欢迎大家扫码关注,获取更多信息
#yyds干货盘点# 如何在 Kubernete 中做日志收集与管理(14)相关推荐
- #yyds干货盘点# 如何在 Kubernete 中运行 DaemonSet 守护进程?(13)
通过前面章节的学习,我们对 Kubernetes 中一些常见工作负载已经有所了解.比如无状态工作负载 Dployment 可以帮助我们运行指定数目的服务副本,并维护其状态,而对于有状态服务来说,我们同 ...
- HTML设置单边圆角,如何在html中做圆角矩形和 只有右边的分隔线
其实是对(理论上是对所有的)html元素: 而实际 常用的是 div块, 链接a 等运用圆角矩形的样式 这个圆角是通过元素: div, a的 css 样式来实现的: 样式: border-radius ...
- SpringBoot整合Graylog做日志收集
日志收集折腾过程 ELK 之前整合过ELK做日志采集,就是Elasticsearch + Logstash + Kibana: Elasticsearch:存储引擎,存放日志内容,利于全文检索 Log ...
- a标签不可点击_如何在Notion中做多级标签?-Notion102
Notion102的意思是:比101(入门级)高出一点点,但操作上仍属于新手级别. 模板链接见最下方. Notion 最新重要更新 @ 20.11.11 Timeline (数据库中增加了时间线视图. ...
- 如何在 Java 中进行日志记录
您可以使用本指南为您的应用程序发现.理解和使用正确的 Java 日志库,例如 Log4j2.Logback 或 java.util.logging. 日志"似乎"是一个非常简单的主 ...
- python如何写日志_【Python】教你如何在python中添加日志
背景 起因是这次的项目用thrift来连接算法(python)和业务逻辑(java),因此有必要在python中添加日志来记录传入的参数.这样,当算法端没有正确响应时,就能方便地排查原因. 简易版实现 ...
- 企业生产过程中的日志和时间管理详解
系统中的日志管理 1.什么时是系统日志? 系统日志是记录系统中硬件.软件和系统问题的信息,同时还可以监视系统中发生的事件.用户可以通过它来检查错误发生的原因,或者寻找受到攻击时攻击者留下的痕迹.系统日 ...
- 自学虚幻引擎图文笔记:如何在UE4中做积雪材质
废话不多说,直接来干货! 首先要思考一下 积雪是什么样的,比如积雪有厚的 有薄的,但是整体都可以总结为A+B,A物体,B是雪. 那么问题来了,这个积雪的材质怎么做呢?很难吗? 不!很简单~ 往下看 捋 ...
- 必看干货:如何在 JavaScript 中实现 8 种基本图形算法
在本文中,我将实现8 种图算法,探索 JavaScript 中图的搜索和组合问题(图遍历.最短路径和匹配). 这些问题是从<Java编程面试要素>一书中借来的.本书中的解决方案是用 Jav ...
最新文章
- .gitignore和.gitkeep有什么区别?
- 【错误记录】Android Studio 编译报错 ( Could not determine java version from ‘11.0.8‘. ② | 升级 Gradle 版本 )
- 前端含金量较高的网站推荐
- 正则表达式引擎的构建——基于编译原理DFA(龙书第三章)——1 概述
- PLSQL连接oracel数据库_用户无法登陆_oci.dll_配置问题
- Hadoop简介与分布式安装
- 创意促销海报设计思路,年底忙的设计师来看!
- 专题:CentOS社区企业操作系统
- 联合多企业成立泛娱乐IP联盟 迅雷将打造新内容消费生态
- Matlab 绘制箱线图
- Androd 如何使andorid应用程序的icon不在Launcher界面上显示
- 微信公众号扫码登录(一)—— 获取微信公众号二维码
- 苹果手机装android应用程序,Android/iOS手机安装HP打印机的详细方法和操作步骤
- 用python自动制作ppt——第三讲——插入文本框
- 加性高斯白噪声 AWGN
- android 添加蒙版实现护眼模式(夜间模式)
- 汇编3-计算机程序是如何运行的
- 长沙市民吴先生乘坐滴滴D1后,取消了买特斯拉的计划
- 在sweetalert弹出窗插件中加入html代码
- 粒子摇摆 shader