K8s 日志收集:使用 EFK 堆栈(Elasticsearch + Fluentd + Grafana)

在 Kubernetes(K8s)集群中,日志收集是监控和故障排除的关键环节。EFK 堆栈(Elasticsearch + Fluentd + Grafana)提供了一套高效、可扩展的解决方案:Elasticsearch 负责存储和索引日志数据,Fluentd 作为日志收集器,Grafana 用于数据可视化和仪表盘。下面,我将逐步解释如何部署和配置 EFK 堆栈,确保您的 K8s 环境实现可靠的日志管理。整个过程基于真实场景,使用标准工具如 kubectl 和 Helm(如果适用)。

步骤 1: 理解 EFK 组件及其作用
  • Elasticsearch:分布式搜索和分析引擎,存储日志数据并提供查询接口。在 K8s 中,通常部署为 StatefulSet 以处理持久化数据。
  • Fluentd:开源日志收集器,从 K8s 节点、容器和 Pod 收集日志,并转发到 Elasticsearch。它作为 DaemonSet 部署,确保每个节点都有一个实例。
  • Grafana:可视化工具,通过连接 Elasticsearch 数据源创建仪表盘,展示日志分析和指标。它可以替代 Kibana,但需要额外配置。

EFK 的优势包括高吞吐量、实时搜索和灵活的可视化,适合生产环境。部署前,确保您的 K8s 集群已配置存储类(StorageClass)和足够资源(CPU/内存)。

步骤 2: 部署 Elasticsearch

Elasticsearch 需要持久化存储来处理日志数据。推荐使用 Helm 简化部署(需提前安装 Helm)。

  1. 添加 Elasticsearch Helm 仓库

    helm repo add elastic https://helm.elastic.co
    helm repo update
    

  2. 安装 Elasticsearch: 创建自定义 values 文件(如 elastic-values.yaml)以配置资源:

    # elastic-values.yaml
    replicas: 3  # 建议至少 3 个副本以高可用
    resources:
      requests:
        cpu: "1"
        memory: "2Gi"
      limits:
        cpu: "2"
        memory: "4Gi"
    volumeClaimTemplate:
      accessModes: [ "ReadWriteOnce" ]
      storageClassName: "standard"  # 替换为您的存储类
      resources:
        requests:
          storage: "10Gi"
    

    运行 Helm 安装命令:

    helm install elasticsearch elastic/elasticsearch -f elastic-values.yaml
    

    验证部署:

    kubectl get pods -l app=elasticsearch-master  # 检查 Pod 状态为 Running
    kubectl port-forward svc/elasticsearch-master 9200:9200  # 本地访问测试
    curl http://localhost:9200  # 应返回 Elasticsearch 健康信息
    

步骤 3: 部署 Fluentd 作为日志收集器

Fluentd 从 K8s 节点收集日志,并发送到 Elasticsearch。使用 DaemonSet 确保每个节点覆盖。

  1. 创建 Fluentd 配置文件: 创建 fluentd-configmap.yaml 文件,定义日志收集规则:

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: fluentd-config
      namespace: kube-system
    data:
      fluent.conf: |
        <source>
          @type tail
          path /var/log/containers/*.log
          pos_file /var/log/fluentd-containers.log.pos
          tag kubernetes.*
          read_from_head true
          <parse>
            @type json
            time_key time
            time_format %Y-%m-%dT%H:%M:%S.%NZ
          </parse>
        </source>
        <match kubernetes.**>
          @type elasticsearch
          host elasticsearch-master  # Elasticsearch 服务名
          port 9200
          logstash_format true
          logstash_prefix fluentd
          include_tag_key true
          type_name _doc
        </match>
    

    应用配置:

    kubectl apply -f fluentd-configmap.yaml
    

  2. 部署 Fluentd DaemonSet: 创建 fluentd-daemonset.yaml 文件:

    apiVersion: apps/v1
    kind: DaemonSet
    metadata:
      name: fluentd
      namespace: kube-system
      labels:
        k8s-app: fluentd-logging
    spec:
      selector:
        matchLabels:
          name: fluentd
      template:
        metadata:
          labels:
            name: fluentd
        spec:
          tolerations:
          - key: node-role.kubernetes.io/master
            effect: NoSchedule
          containers:
          - name: fluentd
            image: fluent/fluentd-kubernetes-daemonset:v1.16-debian-elasticsearch8
            env:
              - name: FLUENT_ELASTICSEARCH_HOST
                value: "elasticsearch-master"
              - name: FLUENT_ELASTICSEARCH_PORT
                value: "9200"
            resources:
              limits:
                memory: 500Mi
              requests:
                cpu: 100m
                memory: 200Mi
            volumeMounts:
              - name: varlog
                mountPath: /var/log
              - name: config-volume
                mountPath: /fluentd/etc/fluent.conf
                subPath: fluent.conf
          volumes:
            - name: varlog
              hostPath:
                path: /var/log
            - name: config-volume
              configMap:
                name: fluentd-config
    

    应用 DaemonSet:

    kubectl apply -f fluentd-daemonset.yaml
    kubectl get pods -n kube-system -l name=fluentd  # 检查所有节点 Pod 运行中
    

步骤 4: 部署 Grafana 并配置可视化

Grafana 用于创建日志仪表盘,连接到 Elasticsearch 数据源。

  1. 部署 Grafana: 使用 Helm 安装:

    helm install grafana grafana/grafana
    kubectl get pods -l app.kubernetes.io/name=grafana  # 验证状态
    

  2. 配置数据源

    • 访问 Grafana UI:
      kubectl port-forward svc/grafana 3000:80  # 本地浏览器访问 http://localhost:3000
      

    • 登录(默认用户名 admin,密码通过 kubectl get secret grafana -o jsonpath="{.data.admin-password}" | base64 --decode 获取)。
    • 添加数据源:
      • 类型:Elasticsearch
      • URL: http://elasticsearch-master:9200
      • Index name: fluentd-*(匹配 Fluentd 日志前缀)
      • 保存并测试连接。
  3. 创建仪表盘

    • 在 Grafana 中,导入预建仪表盘(如使用 ID 6483 或自定义)。
    • 示例查询:在 Explore 视图,输入 Elasticsearch 查询如 kubernetes.pod_name: "your-pod" 来过滤日志。
    • 可视化日志趋势、错误率等。
步骤 5: 验证和优化
  • 测试日志流: 运行测试 Pod 生成日志:

    kubectl run test-logger --image=busybox --command -- sh -c 'while true; do echo "Test log at $(date)"; sleep 5; done'
    

    在 Grafana 中搜索 kubernetes.pod_name:test-logger 查看实时日志。

  • 常见问题处理

    • 日志延迟:检查 Fluentd 资源限制;增加 Fluentd buffer 大小。
    • 存储不足:扩展 Elasticsearch PVC 或调整保留策略。
    • 权限问题:确保 ServiceAccount 有权限访问日志路径(使用 K8s RBAC)。
  • 最佳实践

    • 使用 Helm 管理版本。
    • 设置日志保留:在 Elasticsearch 配置 ILM(Index Lifecycle Management)。
    • 监控 EFK 堆栈自身:部署 Prometheus 监控资源使用。
总结

通过 EFK 堆栈,您可以在 K8s 中实现高效日志收集、存储和可视化。Elasticsearch 提供强大搜索能力,Fluentd 确保无缝日志聚合,Grafana 赋予直观洞察。部署后,日志管理将提升集群可观测性,加速故障响应。如果您遇到具体问题(如特定错误),提供更多细节,我可以进一步优化建议!

更多推荐