首页 > 其他分享 >14-日志采集:如何在 Kubernete 中做日志收集与管理?

14-日志采集:如何在 Kubernete 中做日志收集与管理?

时间:2024-01-11 13:47:56浏览次数:30  
标签:容器 14 收集 日志 Kubernetes Kubernete Pod name

说到日志,你应该不陌生。日志中不仅记录了代码运行的实时轨迹,往往还包含着一些关键的数据、错误信息,等等。日志方便我们进行分析统计及监控告警,尤其是在后期问题排查的时候,我们通过日志可以很方便地定位问题、现场复现及问题修复。日志也是做可观测性(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 自身提供的各项能力,可以帮助我们解决日志收集的诉求。根据上面提到的三大基本日志需求,一般来说我们有如下有三种方案来做日志收集:

  1. 直接在应用程序中将日志信息推送到采集后端;

  2. 在节点上运行一个 Agent 来采集节点级别的日志;

  3. 在应用的 Pod 内使用一个 Sidecar 容器来收集应用日志。

我们来分别看看这三种方式。

先来看直接在应用程序中将日志信息推送到采集后端,即Pod 内的应用直接将日志写到后端的日志中心

image (2).png

https://github.com/kubernetes/website/blob/master/static/images/docs/user-guide/logging/logging-from-application.png

通常有两种做法,一个就是应用程序通过对应的日志 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 的这套体系中,直接将日志写到后端日志采集系统中去,并不是特别好的做法。

我们来看第二种方法,在节点上运行一个 Agent 来采集节点级别的日志。如下图所示,我们可以在每一个 Kubernetes Node 上都部署一个 Agent,该 Agent 负责对该节点上运行的所有容器进行日志收集,并推送到后端的日志存储系统里。这个 Agent 通常需要可以访问到宿主机上的指定目录,比如/var/lib/docker/containers/

image (3).png

https://github.com/kubernetes/website/blob/master/static/images/docs/user-guide/logging/logging-with-node-agent.png

由于这样的 Agent 需要在每个 Node 上都运行,因此我们都是通过 上节课讲到的DaemonSet的方式来部署的。对于 Kubernetes 集群来说,这种使用节点级的DaemonSet日志代理是最常用,也是最被推荐的方式,不仅可以节约资源,而且对于应用来说也是无侵入的。

但是这种方式也有个缺点,就是只适应于容器内应用日志是标准输出的场景,即应用把日志输出到stdoutstderr

最后来看通过 Sidecar 来收集容器日志。 在 Pod 里面,容器的输出日志可以是stdoutstderr和日志文件。那么基于这三种形式,我们可以借助于 Sidecar 容器

将基于文件的日志来帮助我们。

  • 通过Sidecar 容器读取日志文件,并定向到自己的标准输出。如下图所示,这里streaming container就是一个 Sidecar 容器,可以将app-container的日志文件重新定向到自己的标准输出。同时还可以归并多个日志文件。而且这里也可以使用多个 Sidecar 容器,你可以参考这个例子

image (4).png

  • Sidecar容器运行一个日志代理,配置该日志代理以便从应用容器收集日志。这种方式就解决了我们上面方案一的问题,将日志处理部分和应用程序本身进行了解耦,可以方便切换到其他的日志系统中。可以参考这个使用 fluentd 的例子

image (5).png

https://github.com/kubernetes/website/blob/master/static/images/docs/user-guide/logging/logging-with-sidecar-agent.png

可以看到,通过 Sidecar 的方式来收集日志,会增加额外的开销。在集群规模较小的情况下可以忽略不计,但是对于大规模集群来说,这些开销还是不可忽略的。

那么,上面的这几套方案,在实际使用的时候,又该如何选择呢?社区又有什么推荐方案呢?

基于 Fluentd + ElasticSearch 的日志收集方案

Kubernetes 社区官方推荐的方案是使用 Fluentd+ElasticSearch+Kibana 进行日志的收集和管理,通过Fluentd将日志导入到Elasticsearch中,用户可以通过Kibana来查看到所有的日志。

image (6).png

(https://docs.fluentd.org/container-deployment/kubernetes)

关于 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: fluentd
  namespace: kube-system
  labels:
    k8s-app: fluentd-logging
    version: v1
spec:
  selector:
    matchLabels:
      k8s-app: fluentd-logging
      version: v1
  template:
    metadata:
      labels:
        k8s-app: fluentd-logging
        version: v1
    spec:
      tolerations:
      - key: node-role.kubernetes.io/master
        effect: NoSchedule
      containers:
      - name: fluentd
        image: fluent/fluentd-kubernetes-daemonset:v1-debian-elasticsearch
        env:
          - name:  FLUENT_ELASTICSEARCH_HOST
            value: "elasticsearch-logging"
          - name:  FLUENT_ELASTICSEARCH_PORT
            value: "9200"
          - name: FLUENT_ELASTICSEARCH_SCHEME
            value: "http"
          # Option to configure elasticsearch plugin with self signed certs
          # ================================================================
          - name: FLUENT_ELASTICSEARCH_SSL_VERIFY
            value: "true"
          # Option to configure elasticsearch plugin with tls
          # ================================================================
          - name: FLUENT_ELASTICSEARCH_SSL_VERSION
            value: "TLSv1_2"
          # X-Pack Authentication
          # =====================
          - name: FLUENT_ELASTICSEARCH_USER
            value: "elastic"
          - name: FLUENT_ELASTICSEARCH_PASSWORD
            value: "changeme"
          # Logz.io Authentication
          # ======================
          - name: LOGZIO_TOKEN
            value: "ThisIsASuperLongToken"
          - name: LOGZIO_LOGTYPE
            value: "kubernetes"
        resources:
          limits:
            memory: 200Mi
          requests:
            cpu: 100m
            memory: 200Mi
        volumeMounts:
        - name: varlog
          mountPath: /var/log
        - name: varlibdockercontainers
          mountPath: /var/lib/docker/containers
          readOnly: true
      terminationGracePeriodSeconds: 30
      volumes:
      - name: varlog
        hostPath:
          path: /var/log
      - name: varlibdockercontainers
        hostPath:
          path: /var/lib/docker/containers

写在最后

在实际采集日志的时候,你可以根据自己的场景和集群规模选择适用的方案。或者也可以将上面的这几种方案进行合理地组合。

到这里这节课就结束了,如果你对本节课有什么想法或者疑问,欢迎你在留言区留言,我们一起讨论。


标签:容器,14,收集,日志,Kubernetes,Kubernete,Pod,name
From: https://www.cnblogs.com/huangjiale/p/17958398

相关文章

  • 13-服务守护进程:如何在 Kubernete 中运行 DaemonSet 守护进程?
    通过前面课程的学习,我们对Kubernetes中一些常见工作负载已经有所了解。比如无状态工作负载Dployment可以帮助我们运行指定数目的服务副本,并维护其状态,而对于有状态服务来说,我们同样可以采用StatefulSet来做到这一点。但是,在实际使用的时候,有些场景,比如监控各个节点的状态,使......
  • 15-Prometheu:Kubernete 怎样实现自动化服务监控告警?
    通过之前的学习,我们已经对Kubernetes有了一定的理解,也知道如何在Kubernetes中部署自己的业务系统。Kubernetes强大的能力让我们非常方便地使用容器部署业务。Kubernetes自带的副本保持能力,可以避免部署的业务系统出现单点故障,提高可用性。各种探针也可以帮助我们对运行中的......
  • 17-案例实战:教你快速搭建 Kubernete 监控平台
    Prometheus和Grafana可以说是Kubernetes监控解决方案中最知名的两个。Prometheus负责收集、存储、查询数据,而Grafana负责将Prometheus中的数据进行可视化展示,当然Grafana还支持其他平台,比如ElasticSearch、InfluxDB、Graphite等。CNCF博客也将这两者称为黄金组合,目......
  • 16-迎战流量峰值:Kubernete 怎样控制业务的资源水位?
    通过前面的学习,相信你已经见识到了Kubernetes的强大能力,它能帮你轻松管理大规模的容器服务,尤其是面对复杂的环境时,比如节点异常、容器异常退出等,Kubernetes内部的Service、Deployment会动态地进行调整,比如增加新的副本、关联新的Pod等。当然Kubernetes的这种自动伸缩能......
  • 18-权限分析:Kubernete 集群权限管理那些事儿
    你好,我是正范。通过前面的课程学习,你已经学会了使用kubectl命令行,或者直接发送REST请求,以及使用各种语言的client库来跟APIServer进行交互。那么你是否知道在这其中Kubernetes是如何对这些请求进行认证、授权的呢?这节课,我们就来一探究竟。任何请求访问Kubernetes的kub......
  • 19-资源限制:如何保障你的 Kubernete 集群资源不会被打爆
    前面的课时中,我们曾提到通过HPA控制业务的资源水位,通过ClusterAutoscaler自动扩充集群的资源。但如果集群资源本身就是受限的情况下,或者一时无法短时间内扩容,那么我们该如何控制集群的整体资源水位,保障集群资源不会被“打爆”?今天我们就来看看Kubernetes中都有哪些能力可以......
  • 20-资源优化:Kubernete 中有 GC(垃圾回收)吗?
    GarbageCollector即垃圾回收,通常简称GC,和你之前在其他编程语言中了解到的GC基本上是一样的,用来清理一些不用的资源。Kubernetes中有各种各样的资源,当然需要GC啦,今天我们就一起来了解下Kubernetes中的GC。你可能最先想到的就是容器的清理,即Kubelet侧的GC,清理许多处于......
  • 02-高屋建瓴:Kubernete 的架构为什么是这样的?
    通过上一课时的学习,我们已经对Kubernetes的前世今生有所了解。接下来,我们开始具体学习如何将Kubernetes应用到自己的项目中,首先就需要了解Kubernetes的架构。所以,在本节课程中,我们会一起学习Kubernetes的架构设计,以及背后的设计哲学。Google使用Linux容器有超过15年......
  • 03-集群搭建:手把手教你玩转 Kubernete 集群搭建
    通过上一节课的学习,我们已经对Kubernetes的架构有了清楚的认识。但是到现在还没有和Kubernetes集群真正打过交道,所以你可能有一种“不识庐山真面目”的云里雾里的感觉。那么本节课,我们就来学习如何搭建Kubernetes集群,开启探索Kubernetes的第一站。在线Kubernetes集群......
  • 04-核心定义:Kubernete 是如何搞定“不可变基础设施”的?
    在上一节课,我们已经了解了Kubernetes集群的搭建方式。从现在开始,我们就要跟Kubernetes集群打交道了。本节课我们会学习Kubernetes中最重要、也最核心的对象——Pod。在了解Pod之前,我们先来看一下CNCF官方是怎么定义云原生的。云原生技术有利于各组织在公有云、私有云......