3、日志采集基础:如何通过 Sidecar 或 DaemonSet 采集 CoreDNS 日志到 ELK/Loki

CoreDNS 作为 Kubernetes 集群的 DNS 核心组件,其日志是排查服务发现异常、域名解析超时、缓存污染等问题的第一手数据。在生产环境中,CoreDNS 通常以 Deployment 形式运行,日志采集方案需兼顾资源开销、采集可靠性与运维复杂度。本章聚焦两种主流采集模式:Sidecar(每个 Pod 内伴生采集器)与 DaemonSet(节点级采集代理),并分别给出输出到 ELK(Elasticsearch + Logstash + Kibana)与 Loki 的完整链路。

3.1 采集架构总览

下图展示了两种采集模式在 Kubernetes 集群中的部署位置与数据流向。Sidecar 模式将采集器注入 CoreDNS Pod 内,与容器共享日志文件;DaemonSet 模式则在每个节点上运行采集代理,通过挂载宿主机路径或 CRI 接口获取日志。

CoreDNS 日志采集架构:Sidecar vs DaemonSet CoreDNS 日志采集架构:Sidecar vs DaemonSet Sidecar 模式 CoreDNS 容器 日志输出到 stdout / 共享卷 emptyDir / hostPath 共享卷 Filebeat / Fluent Bit 读取共享卷日志 → 发送 ELK / Loki 通过 HTTP / gRPC 输出 DaemonSet 模式 Kubernetes 节点 /var/log/pods / /var/log/containers Fluentd / Logstash 挂载宿主机日志路径 ELK / Loki 通过 HTTP / gRPC 输出 DaemonSet 模式无需修改 CoreDNS 部署 但需注意日志轮转与权限挂载

3.2 Sidecar 模式:精准采集,隔离性强

Sidecar 模式在 CoreDNS 的 Deployment 定义中额外添加一个日志采集容器(如 Filebeat、Fluent Bit),两个容器共享一个 emptyDir 卷。CoreDNS 容器将日志写入共享卷,采集容器读取并转发。此模式适用于对日志格式有定制需求、或需要避免节点级采集器干扰的场景。

3.2.1 部署示例:CoreDNS + Filebeat Sidecar

以下 YAML 片段展示了在 CoreDNS Deployment 中注入 Filebeat Sidecar 的核心配置:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: coredns
  namespace: kube-system
spec:
  template:
    spec:
      containers:
      - name: coredns
        image: coredns/coredns:1.11.1
        args: [ "-conf", "/etc/coredns/Corefile" ]
        volumeMounts:
        - name: log-volume
          mountPath: /var/log/coredns
      - name: filebeat
        image: docker.elastic.co/beats/filebeat:8.12.0
        args: [ "-c", "/etc/filebeat.yml", "-e" ]
        volumeMounts:
        - name: log-volume
          mountPath: /var/log/coredns
          readOnly: true
        - name: filebeat-config
          mountPath: /etc/filebeat.yml
          subPath: filebeat.yml
      volumes:
      - name: log-volume
        emptyDir: {}
      - name: filebeat-config
        configMap:
          name: filebeat-config

3.2.2 Filebeat 配置要点

Filebeat 的配置文件需指定输入源为共享卷中的日志文件,并设置多行合并规则以处理 CoreDNS 的堆栈日志:

filebeat.inputs:
- type: log
  enabled: true
  paths:
    - /var/log/coredns/*.log
  multiline.pattern: '^\d{4}-\d{2}-\d{2}'
  multiline.negate: true
  multiline.match: after

output.elasticsearch:
  hosts: ["http://elasticsearch:9200"]
  index: "coredns-%{+yyyy.MM.dd}"

# 若输出到 Loki,则使用 output.logstash 或 elasticsearch 的 Loki 插件
最佳实践:Sidecar 模式下,建议将 CoreDNS 日志格式改为 JSON(通过 Corefile 的 log 插件配置 output file /var/log/coredns/access.log 并设置 format json),便于采集器直接解析结构化字段,减少后续 Logstash 或 Loki 的解析开销。

3.3 DaemonSet 模式:零侵入,运维简单

DaemonSet 模式在每个节点上部署一个日志采集代理(如 Fluentd、Logstash),通过挂载宿主机 /var/log/pods 或 /var/log/containers 路径读取所有 Pod 的日志。CoreDNS 的日志文件位于 /var/log/pods/kube-system_coredns-* 下,采集器通过路径匹配或 Kubernetes 元数据过滤获取。

3.3.1 部署示例:Fluentd DaemonSet

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: fluentd
  namespace: kube-system
spec:
  selector:
    matchLabels:
      name: fluentd
  template:
    metadata:
      labels:
        name: fluentd
    spec:
      containers:
      - name: fluentd
        image: fluent/fluentd-kubernetes-daemonset:v1.16-debian-elasticsearch
        env:
        - name: FLUENT_ELASTICSEARCH_HOST
          value: "elasticsearch"
        - name: FLUENT_ELASTICSEARCH_PORT
          value: "9200"
        volumeMounts:
        - name: varlog
          mountPath: /var/log
        - name: dockercontainers
          mountPath: /var/lib/docker/containers
          readOnly: true
      volumes:
      - name: varlog
        hostPath:
          path: /var/log
      - name: dockercontainers
        hostPath:
          path: /var/lib/docker/containers

3.3.2 Fluentd 配置:过滤 CoreDNS 日志

在 Fluentd 的配置中,使用 @label 和 kubernetes_metadata 插件过滤出 CoreDNS 的日志流:

<source>
  @type tail
  path /var/log/containers/coredns-*.log
  pos_file /var/log/fluentd-coredns.pos
  tag kubernetes.coredns.*
  format json
  read_from_head true
</source>

<filter kubernetes.coredns.*>
  @type kubernetes_metadata
</filter>

<match kubernetes.coredns.*>
  @type elasticsearch
  host "#{ENV['FLUENT_ELASTICSEARCH_HOST']}"
  port "#{ENV['FLUENT_ELASTICSEARCH_PORT']}"
  index_name coredns
  <buffer>
    flush_interval 5s
  </buffer>
</match>

3.4 两种模式对比与选型

对比维度 Sidecar 模式 DaemonSet 模式
资源开销 每个 CoreDNS Pod 额外占用 1 个采集容器(约 50-100MB 内存) 每个节点 1 个采集代理,节点数远少于 Pod 数时更省资源
采集隔离性 高,采集器故障不影响其他 Pod 低,节点级采集器故障影响该节点所有 Pod 日志
部署复杂度 需修改 CoreDNS Deployment,注入 Sidecar 容器与 ConfigMap 独立部署 DaemonSet,无需修改 CoreDNS
日志格式灵活性 高,可在 Sidecar 内定制解析逻辑 中,需通过标签或路径过滤,可能采集到无关日志
适用场景 CoreDNS 日志格式特殊、需独立处理;集群规模较小 大规模集群、希望统一管理所有日志采集

3.5 输出到 ELK 与 Loki 的差异

无论采用哪种采集模式,最终日志都会发送到后端存储。ELK 与 Loki 在日志存储、查询方式上存在本质区别,直接影响采集器的输出配置:

特性 ELK (Elasticsearch + Logstash + Kibana) Loki (Grafana Loki)
存储模型 全文索引,存储原始日志与倒排索引 仅压缩存储日志内容,索引元数据(标签)
采集器输出协议 HTTP Bulk API / Logstash 输出插件 HTTP Push API (Promtail 原生支持)
日志解析位置 Logstash 或采集器端解析为结构化字段 采集器端(Promtail)或查询时(LogQL)解析
查询语言 Kibana Query Language (KQL) / Lucene LogQL(类 PromQL 语法)
资源消耗 高(索引写入与存储开销大) 低(无索引,存储成本低)
适用场景 需要复杂全文搜索、聚合分析、历史趋势 快速日志检索、与 Prometheus 指标关联、成本敏感

3.6 输出到 Loki 的采集配置示例(Promtail)

若选择 Loki 作为日志后端,推荐使用 Promtail 作为采集器。以下为 Promtail 的 Sidecar 配置片段,直接输出到 Loki:

# promtail-config.yaml
scrape_configs:
- job_name: coredns
  static_configs:
  - targets: [localhost]
    labels:
      job: coredns
      namespace: kube-system
      __path__: /var/log/coredns/*.log
  pipeline_stages:
  - regex:
      expression: '^(?P<time>\S+)\s+(?P<level>\S+)\s+(?P<msg>.*)'
  - labels:
      level:
  - timestamp:
      source: time
      format: RFC3339

clients:
- url: http://loki:3100/loki/api/v1/push
注意:Loki 不提供全文索引,因此采集器端应尽量提取关键标签(如 level、query_type、rcode),以便在 LogQL 中高效过滤。避免将高基数字段(如客户端 IP)直接作为标签,否则会导致索引膨胀。

3.7 日志采集的可靠性保障

无论采用 Sidecar 还是 DaemonSet,都需要考虑以下可靠性措施:

  • 日志轮转兼容:CoreDNS 默认不轮转日志,建议在 Corefile 中配置 log 插件的 rotate 参数,或依赖容器运行时(如 containerd)的日志轮转策略。采集器需支持 copytruncate 或 inode 跟踪。
  • 断点续传:Filebeat 和 Fluentd 均支持 registry / position 文件,记录已读取的偏移量。确保这些文件存储在持久卷或 hostPath 上,避免 Pod 重启后重复采集。
  • 背压与缓冲:当后端(Elasticsearch / Loki)不可用时,采集器应具备本地缓冲能力。Filebeat 使用 queue.mem,Fluentd 使用 buffer 插件,Promtail 使用 client 的 buffer 配置。
  • 监控采集器自身:为采集器暴露 Prometheus 指标(如 filebeat_input_events、fluentd_output_status_buffer_queue_length),纳入可观测性体系。

3.8 本章小结