← 返回文章列表
使用指南 4 分钟阅读 炬鲸团队

Kubernetes 日志接入:从 DaemonSet 到结构化检索

容器日志散落在每个节点的文件系统里,Pod 一重启就丢。本文讲如何用 DaemonSet 部署采集代理、把 stdout 和文件日志统一收进炬鲸 OBSERVE,并注入 Pod、命名空间、容器等元数据,附完整 YAML 与排错要点。

容器日志的两个坑

容器的日志采集和虚拟机不一样。第一,日志默认写到每个节点的文件系统里,Pod 漂移到别的节点后,本地日志就断了;第二,Pod 一重启(哪怕只是滚动更新),容器内的日志文件可能直接消失,出事时想查历史记录已经晚了。

所以 Kubernetes 的日志采集标准做法是:每个节点跑一个采集代理,实时把 stdout 和日志文件都推出去,让日志在平台侧集中落盘,而不是留在节点上。代理用 DaemonSet 部署,节点增减自动跟随。

用 DaemonSet 部署采集代理

把炬鲸的采集代理以 DaemonSet 形式部署,每个节点一个 Pod,挂载宿主机的日志目录:

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: jjhub-agent
spec:
  selector:
    matchLabels: { app: jjhub-agent }
  template:
    metadata:
      labels: { app: jjhub-agent }
    spec:
      containers:
      - name: agent
        image: jjhub/agent:2.5
        env:
        - name: TOKEN
          valueFrom:
            secretKeyRef: { name: jjhub-agent, key: token }
        - name: ENDPOINT
          value: https://ob.example.com
        volumeMounts:
        - { name: varlog, mountPath: /var/log }
        - { name: varlibdocker, mountPath: /var/lib/docker/containers, readOnly: true }
      volumes:
      - { name: varlog, hostPath: { path: /var/log } }
      - { name: varlibdocker, hostPath: { path: /var/lib/docker/containers } }

Token 放 Secret 里,别硬编码进 YAML。代理挂载 /var/log 收系统日志,挂载 Docker/containerd 的容器目录收容器 stdout,两个来源统一推送到平台。

注入 Pod 元数据:检索才能定位到人

光收日志不够,还得知道每条日志属于哪个 Pod、哪个命名空间、哪个部署。代理会自动给日志打上这些标签:

namespace=prod, pod=order-service-7f8c9, container=order, deployment=order-service

有了这些维度,检索时就能按命名空间、按 Pod、按容器过滤,出问题时直接从告警里的 Pod 名反查日志,不用在几十个节点上挨个翻。

对应用侧只有一个要求:日志走 stdout,别写进容器内部的文件。stdout 会被容器运行时自动采集,日志文件则要额外配置采集路径,还容易漏。

排错要点

  1. 日志不完整:检查代理的本地缓冲是否开启,平台短暂不可用时日志应先落盘排队
  2. Pod 重启后查不到历史:确认日志已实时推送到平台,而非依赖节点本地文件
  3. 多行堆栈被打散:Java 异常堆栈是多行的,代理需开启多行合并,否则一条异常被拆成几十条
  4. 磁盘被日志占满:给节点日志目录设轮转和上限,避免采集代理自己把盘写爆

落地建议

先从一个命名空间试点,跑通采集、检索、告警全流程,再全集群铺开。重点检查三类元数据是否齐全(namespace、pod、container),这是后续所有检索和告警的地基。字段名统一用平台约定,避免各团队各写一套。