2. Kubeflow日志采集基础:日志采集工具介绍与配置实战

日志这东西,说白了就是系统的“黑匣子”。Kubeflow跑起来之后,Pod一多,日志就像洪水一样涌出来。你想想看,几十个训练任务同时跑,每个任务又拆成好几个Pod,要是没有一套好用的采集工具,排查问题简直是大海捞针。

我个人习惯,先把日志采集的“三件套”搞清楚:用什么工具采、怎么配置、怎么打标签。今天咱们就围绕这三个点,把Kubeflow日志采集的基础打扎实。

2.1 日志采集工具:Fluentd vs Filebeat

市面上日志采集工具不少,但在Kubeflow场景下,我主要用两个:FluentdFilebeat。它们各有各的脾气。

特性 Fluentd Filebeat
语言 Ruby + C插件 Go
资源占用 中等(约30-50MB) 轻量(约10-20MB)
插件生态 极其丰富(1000+) 中等(主要围绕ELK)
配置复杂度 较高(DSL配置) 较低(YAML配置)
适用场景 复杂数据管道、多输出 轻量采集、直接送ES

Fluentd 是我在Kubeflow项目中的首选。为什么?因为它插件多,能对接各种输出端。我在项目中遇到过需要同时把日志送到Elasticsearch和S3的场景,Fluentd一个配置就搞定了。但它的配置语法有点绕,新手容易踩坑。

Filebeat 则更轻量。如果你只是想把Kubeflow的Pod日志简单采集到Elasticsearch,Filebeat就够了。它配置简单,资源占用也小。不过,一旦你需要做复杂的数据转换或路由,Filebeat就有点力不从心了。

我的建议: 如果你的Kubeflow集群规模不大(10个节点以内),用Filebeat快速上手。如果集群规模大、日志链路复杂,直接上Fluentd,省得后面再重构。

2.2 日志采集配置实战:以Fluentd为例

嗯,这里咱们直接上实战。我会用Fluentd DaemonSet的方式部署到Kubeflow集群中,采集所有Pod的日志。

先看核心配置:

# fluentd-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: fluentd-config
  namespace: kubeflow
data:
  fluent.conf: |
    <source>
      @type tail
      path /var/log/containers/*.log
      pos_file /var/log/fluentd-containers.log.pos
      tag kubeflow.*
      format json
      read_from_head true
    </source>

    <filter kubeflow.**>
      @type parser
      key_name log
      reserve_data true
      <parse>
        @type json
      </parse>
    </filter>

    <match kubeflow.**>
      @type elasticsearch
      host elasticsearch.kubeflow.svc.cluster.local
      port 9200
      logstash_format true
      logstash_prefix kubeflow-logs
      flush_interval 5s
    </match>

这段配置我拆开讲:

  • source:监听宿主机上的容器日志文件。路径是 /var/log/containers/*.log,这是Kubernetes默认的日志存放位置。
  • filter:对日志做解析。因为Kubernetes的容器日志默认是JSON格式,但里面还包了一层,所以需要把真正的日志内容解析出来。
  • match:把处理后的日志发送到Elasticsearch。这里我设置了每5秒刷新一次,保证日志的实时性。

小技巧: 配置里的 pos_file 很重要。它记录了日志文件的读取位置,防止Fluentd重启后重复读取。我曾经因为忘了配这个,导致ES里日志量翻倍,排查了半天才发现。

部署DaemonSet:

# fluentd-daemonset.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: fluentd
  namespace: kubeflow
spec:
  selector:
    matchLabels:
      name: fluentd
  template:
    metadata:
      labels:
        name: fluentd
    spec:
      containers:
      - name: fluentd
        image: fluent/fluentd-kubernetes-daemonset:v1.16-debian-elasticsearch7-1
        env:
        - name: FLUENT_ELASTICSEARCH_HOST
          value: "elasticsearch.kubeflow.svc.cluster.local"
        - name: FLUENT_ELASTICSEARCH_PORT
          value: "9200"
        volumeMounts:
        - name: varlog
          mountPath: /var/log
        - name: config
          mountPath: /fluentd/etc
      volumes:
      - name: varlog
        hostPath:
          path: /var/log
      - name: config
        configMap:
          name: fluentd-config

部署命令很简单:

kubectl apply -f fluentd-config.yaml
kubectl apply -f fluentd-daemonset.yaml

跑完之后,检查一下Pod状态:

kubectl get pods -n kubeflow | grep fluentd

如果看到每个节点都有一个Running状态的Pod,说明采集器已经就绪了。

2.3 日志标签与元数据:让日志“会说话”

日志采集上来只是第一步。怎么让日志变得有用?关键在标签和元数据。

我举个例子。你在Kubeflow里跑了一个训练任务,叫 mnist-training,它产生了100个Pod的日志。如果没有标签,你搜出来的日志就是一堆乱码。但如果你给每条日志打上 pipeline_name=mnist-trainingrun_id=20240301pod_name=worker-0 这些标签,那搜索起来就方便多了。

在Fluentd里,我们可以通过 record_transformer 插件来添加元数据:

<filter kubeflow.**>
  @type record_transformer
  enable_ruby true
  <record>
    cluster_name ${record["kubernetes"]["namespace_name"]}
    pipeline_name ${record["kubernetes"]["labels"]["pipeline/run-name"]}
    run_id ${record["kubernetes"]["labels"]["pipeline/run-id"]}
    pod_name ${record["kubernetes"]["pod_name"]}
    container_name ${record["kubernetes"]["container_name"]}
  </record>
</filter>

这段配置做了几件事:

  • 从Kubernetes的元数据中提取 namespacepod_namecontainer_name
  • 从Pod的Label中提取 pipeline/run-namepipeline/run-id
  • 把这些信息作为新的字段添加到日志记录中

注意: Kubeflow Pipeline的Pod标签命名有规律。我记得有一次,因为Pipeline版本升级,标签名从 pipeline/run-id 变成了 pipelines.kubeflow.org/run-id,导致日志标签全部丢失。所以,建议你在配置里加上多个标签匹配规则,或者定期检查一下。

最终,你在Elasticsearch里看到的日志记录会是这样的:

{
  "log": "Training accuracy: 0.9823",
  "cluster_name": "kubeflow",
  "pipeline_name": "mnist-training",
  "run_id": "20240301-abc123",
  "pod_name": "mnist-training-worker-0",
  "container_name": "main",
  "@timestamp": "2024-03-01T10:30:00Z"
}

有了这些元数据,你就可以在Kibana里轻松筛选出某个特定训练任务的所有日志,或者按Pod维度查看日志分布。说白了,标签就是日志的“身份证”,没有它,日志就是一堆废纸。

2.4 知识体系总览

下面这张图,是我梳理的本章知识结构。你可以把它当作一个“地图”,方便回顾。

Kubeflow日志采集基础 工具选择 Fluentd(复杂管道) Filebeat(轻量采集) 按场景选择 配置实战 Source(日志源) Filter(解析过滤) Match(输出目标) 标签与元数据 K8s元数据提取 Pipeline标签注入 record_transformer 核心目标:让Kubeflow日志可采集、可解析、可检索 工具选对 → 配置跑通 → 标签打准 → 日志好用

这张图把本章内容串起来了。从左到右,先是选工具,然后是配采集,最后是打标签。每一步都踩过坑,才敢说这些经验。

避坑指南: 我曾经在生产环境遇到过Fluentd内存暴涨的问题。后来发现是日志量太大,flush_interval设置得太长,导致日志在内存里积压。解决办法是缩短flush间隔,或者启用缓冲插件。嗯,这个坑你们大概率也会遇到,提前打个预防针。

好了,日志采集的基础就聊到这儿。工具选好了,配置跑通了,标签打上了,接下来就可以放心地让Kubeflow跑任务了。日志在手,排查不愁。


公众号:蓝海资料掘金营,微信deep3321