☰
90DaysOfDevOps 实战篇:在 Minikube 上部署 EFK Stack,用 Elasticsearch + Fluentd + Kibana 统一监控 Kubernetes 日志
2026/10/7 15:20:13 网站建设 项目流程
  • 文档/教程

【免费下载链接】90DaysOfDevOps

This repository started out as a learning in public project for myself and has now become a structured learning map for many in the community. We have 3 years under our belt covering all things DevOps, including Principles, Processes, Tooling and Use Cases surrounding this vast topic.

项目地址:https://gitcode.com/gh_mirrors/90/90DaysOfDevOps
点击查看免费下载

导读

本篇是 90DaysOfDevOps 监控专题的第 82 天内容,目标是用 EFK Stack(Elasticsearch + Fluentd + Kibana)在本地 Minikube 集群中构建一套 Kubernetes 日志采集与可视化链路。与上一节 ELK Stack 相比,EFK 只是把数据采集器从 Logstash 换成了更轻量的 Fluentd/FluentBit,其余组件保持一致。读完本文你将掌握:EFK 各组件的分工与 K8s 部署形态(StatefulSet / Deployment / DaemonSet)、完整efk-stack.yaml清单的逐段解读、从minikube start到 Kibana 建索引看日志的端到端操作流程,以及 Kibana 扩展接入 APM、指标、安全事件等数据源的能力。配套的完整部署清单位于仓库 2022/Days/Monitoring/EFK Stack/efk-stack.yaml,可直接复制使用。

从 ELK 到 EFK:为什么要换掉 Logstash

在 Day 80(ELK Stack) 中,我们了解了 ELK 三件套:Elasticsearch 负责分布式存储与检索、Logstash 负责服务端数据采集与转换、Kibana 负责可视化。ELK 的短板在于 Logstash 作为重量级数据管道,资源占用偏高;而在 K8s 这种节点数量多、每个节点都需采集日志的场景下,更轻量的采集器更受欢迎。

EFK Stack 的核心变化只有一处——把采集器 Logstash 替换为 Fluentd(或 FluentBit)。正如 Day 81(Fluentd & FluentBit) 所讲,Fluentd 是开源的统一日志层数据采集器,具备四大特性:统一 JSON 结构化日志、可插拔的插件体系(社区贡献超过 300 个插件对接数十种数据源与输出端)、极低资源占用(原版实例约 30~40MB 内存、单核每秒可处理约 13000 条事件)、以及基于内存/文件缓冲的可靠性与故障转移能力。Fluentd 不绑定任何特定数据源或目的地——任意数据源可进、任意目的地可出,这使其非常适合作为 K8s 集群的日志采集层。

本节的使命就是:用 EFK 监控我们的 Kubernetes 日志,将集群中每个节点、每个容器的日志统一采集进 Elasticsearch,再通过 Kibana 检索与可视化。

EFK 架构总览:三个组件三种部署形态

EFK 由三款软件捆绑组成,各自承担不同职责:

  • Elasticsearch:NoSQL 数据库,负责存储日志数据,并提供搜索与查询日志的接口(REST API,默认端口 9200,节点间通信端口 9300);
  • Fluentd:开源数据采集器,构成统一日志层,负责将 K8s 各节点容器的日志收集、解析后写入 Elasticsearch;
  • Kibana:管理与统计日志的可视化界面,负责从 Elasticsearch 读取数据并展示(默认端口 5601)。

下图是本文要部署到 K8s 集群中的整体架构,注意三个组件各自的部署形态与命名空间归属:

从架构图上可以清晰看到三种不同的 K8s 工作负载类型,这也是 EFK 部署的关键设计点:

组件K8s 工作负载类型副本数职责
ElasticsearchStatefulSet3有状态存储,需稳定的网络标识与持久化卷,组成 es-cluster
KibanaDeployment1无状态 Web 界面,通过 Service 对外暴露 5601 端口
FluentdDaemonSet每个节点 1 个保证每个节点都运行采集器,读取该节点所有容器日志

逐段解读 efk-stack.yaml:一份清单部署整个 EFK

原文档作者在仓库中提供了一个包含全部所需资源的 YAML 清单 efk-stack.yaml,使用kubectl create -f efk-stack.yaml一条命令即可完成部署。下面我们逐段拆解这份清单,理解每一类资源的作用与关键参数。

命名空间与 Elasticsearch Headless Service

清单首先创建一个名为kube-logging的命名空间,将 EFK 全部组件与数据隔离在独立空间内。随后创建一个无头服务(Headless Service):

kind: Service apiVersion: v1 metadata: name: elasticsearch namespace: kube-logging labels: app: elasticsearch spec: selector: app: elasticsearch clusterIP: None ports: - port: 9200 name: rest - port: 9300 name: inter-node

关键点:clusterIP: None使该 Service 变为 Headless,不提供负载均衡 VIP,而是为每个 Pod 提供稳定的 DNS 域名(如es-cluster-0.elasticsearch.kube-logging.svc.cluster.local)。这对 StatefulSet 至关重要——Elasticsearch 三节点集群需要依靠稳定的 DNS 名称互相发现、组成集群,并供 Fluentd 通过elasticsearch.kube-logging.svc.cluster.local域名写入日志。

持久化卷与 Elasticsearch StatefulSet

清单为 Elasticsearch 提供了两类存储:一个 50Gi 的hostPathPersistentVolume(/mnt/data),配合 volumeClaimTemplates 中每个 Pod 申请 5Gi 存储。StatefulSet 部分的核心配置:

kind: StatefulSet metadata: name: es-cluster namespace: kube-logging spec: serviceName: elasticsearch replicas: 3 ... containers: - name: elasticsearch image: docker.elastic.co/elasticsearch/elasticsearch:7.2.0 resources: limits: cpu: 1000m requests: cpu: 100m ports: - containerPort: 9200 name: rest - containerPort: 9300 name: inter-node volumeMounts: - name: data mountPath: /usr/share/elasticsearch/data env: - name: cluster.name value: k8s-logs - name: node.name valueFrom: fieldRef: fieldPath: metadata.name - name: discovery.seed_hosts value: "es-cluster-0.elasticsearch,es-cluster-1.elasticsearch,es-cluster-2.elasticsearch" - name: cluster.initial_master_nodes value: "es-cluster-0,es-cluster-1,es-cluster-2" - name: ES_JAVA_OPTS value: "-Xms512m -Xmx512m"

这段配置的工程要点:

  • 镜像版本固定为 Elasticsearch 7.2.0,后续 Kibana、Fluentd 的 Elasticsearch 插件均与该版本配套;
  • cluster.name: k8s-logs统一集群名;node.name通过fieldRef动态取 Pod 名(es-cluster-0/1/2),保证节点名唯一;
  • discovery.seed_hosts指定三个节点基于 Headless 服务短域名互相发现;cluster.initial_master_nodes声明初始 master 候选节点,完成首次集群引导;
  • ES_JAVA_OPTS: -Xms512m -Xmx512m将 JVM 堆固定为 512MB,适合 Minikube 这类资源受限的本地环境,避免内存配置过高导致 Pod 无法调度;
  • initContainers依次完成三项前置准备:fix-permissions将数据目录属主改为 Elasticsearch 用户(uid 1000);increase-vm-max-map调大内核参数vm.max_map_count=262144(Elasticsearch 启动硬性要求);increase-fd-ulimit把文件描述符上限提升至 65536。

Kibana Deployment 与 Service

kind: Service metadata: name: kibana namespace: kube-logging spec: ports: - port: 5601 selector: app: kibana --- kind: Deployment metadata: name: kibana namespace: kube-logging spec: replicas: 1 ... containers: - name: kibana image: docker.elastic.co/kibana/kibana:7.2.0 resources: limits: cpu: 1000m requests: cpu: 100m env: - name: ELASTICSEARCH_URL value: http://elasticsearch:9200 ports: - containerPort: 5601

Kibana 是无状态应用,以 Deployment 方式运行 1 个副本。核心环境变量ELASTICSEARCH_URL: http://elasticsearch:9200指向 Elasticsearch 的集群内服务名,Kibana 通过它读取索引数据。集群内访问路径为kibana.kube-logging:5601,但本机访问需要后续的kubectl port-forward转发。

Fluentd:ServiceAccount + RBAC + DaemonSet 三段式

Fluentd 在 K8s 中的部署需要三块配套资源,这份清单把它们写全了:

1. ServiceAccount 与 RBAC 授权:Fluentd 需要调用 Kubernetes API Server 读取 Pod 与命名空间的元数据(用于给日志打上 k8s 标签),因此清单创建了同名ServiceAccount、ClusterRole(对 pods、namespaces 资源授予 get/list/watch 权限)以及ClusterRoleBinding将两者绑定。

2. DaemonSet 主体:

kind: DaemonSet metadata: name: fluentd namespace: kube-logging spec: ... template: spec: serviceAccount: fluentd serviceAccountName: fluentd tolerations: - key: node-role.kubernetes.io/master effect: NoSchedule containers: - name: fluentd image: fluent/fluentd-kubernetes-daemonset:v1.4.2-debian-elasticsearch-1.1 env: - name: FLUENT_ELASTICSEARCH_HOST value: "elasticsearch.kube-logging.svc.cluster.local" - name: FLUENT_ELASTICSEARCH_PORT value: "9200" - name: FLUENT_ELASTICSEARCH_SCHEME value: "http" - name: FLUENTD_SYSTEMD_CONF value: disable resources: limits: memory: 512Mi 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

要点解读:

  • 镜像选用官方fluentd-kubernetes-daemonset的 Elasticsearch 输出插件版本,因此无需自定义配置即可直连 ES;
  • tolerations容忍 master 节点上的NoSchedule污点,确保 Fluentd 也能跑在主节点采集其日志;
  • 通过hostPath挂载宿主机/var/log与/var/lib/docker/containers,DaemonSet 保证每个节点恰好运行一个 Fluentd Pod,逐节点读取该节点上所有容器写入的日志文件;
  • FLUENT_ELASTICSEARCH_HOST指向 Elasticsearch 在集群内的完整 DNS 名(elasticsearch.kube-logging.svc.cluster.local),端口 9200、协议 http;
  • 资源限制设为 512Mi 内存上限、100m CPU 请求,配合 Day 81 中 Fluent Bit 的Mem_Buf_Limit 5MB等思路,体现了日志采集器"轻量常驻"的设计取向。

实战部署:从 minikube start 到集群就绪

第一步:启动 Minikube 集群

原文档作者在 Windows + WSL2 环境下执行minikube start启动本地集群。如果你的机器尚未初始化驱动与镜像,这一步会依次完成驱动选择、镜像拉取、Kubernetes 组件初始化和 RBAC 配置等流程:

第二步:一键创建全部资源

集群就绪后,在仓库目录下执行:

kubectl create -f efk-stack.yaml

kubectl create会按清单顺序创建命名空间、Service、PV、StatefulSet、Deployment、ServiceAccount、ClusterRole、ClusterRoleBinding 与 DaemonSet,终端会依次打印各类资源创建成功的信息。

第三步:监控 Pod 进入 Ready 状态

首次部署需要拉取 Elasticsearch、Kibana、Fluentd 及 initContainers 的镜像,因此 Pod 进入 Ready 需要几分钟。先用-w参数持续观察变化:

kubectl get pods -n kube-logging -w

确认全部就绪后,再用不带-w的命令做最终核对:

kubectl get pods -n kube-logging

此时应当看到符合预期的 5 个 Pod:

  • 3 个 Elasticsearch Pod(es-cluster-0 / es-cluster-1 / es-cluster-2,StatefulSet 有序命名)
  • 1 个 Fluentd Pod(DaemonSet,单节点集群下 1 个)
  • 1 个 Kibana Pod(Deployment)

还可以用kubectl get all -n kube-logging查看命名空间内的全部资源,验证三种工作负载类型——Fluentd 为 DaemonSet、Kibana 为 Deployment、Elasticsearch 为 StatefulSet,这与架构图的设计一一对应。

第四步:端口转发访问 Kibana

Pod 全部就绪后,另开一个终端执行端口转发(注意你自己的 Pod 名称与示例不同,可用kubectl get pods -n kube-logging查询):

kubectl port-forward kibana-84cf7f59c-v2l8v 5601:5601 -n kube-logging

然后在浏览器访问http://localhost:5601,即可进入 Kibana 首页。首次进入时可能看到初始配置引导页,也可能看到示例数据入口——无论哪种,都可以按需尝试,示例数据正是 Day 80 讲解 ELK 时加载过的样本数据集。

在 Kibana 中创建索引模式并查看 K8s 日志

Kibana 界面默认不会直接展示数据,必须先创建索引模式(Index Pattern)。Fluentd 写入 Elasticsearch 的索引名通常以logstash-*或日期后缀开头(Day 81 的 Fluent Bit 配置中Logstash_Format On正是此意),因此通配符*可以覆盖全部日志索引。

操作步骤:

  1. 点击左侧菜单的Discover(发现)标签页;
  2. 在创建索引模式页面,索引模式输入*,点击Next step;
  3. 进入第 2 步(Step 2 of 2),从下拉框中选择@timestamp作为时间字段,这会使后续检索结果按时间过滤与排序;
  4. 点击Create pattern创建索引模式,过程可能需要几秒钟。

创建完成后,回到Discover标签页,稍等片刻即可看到来自 Kubernetes 集群的日志数据源源不断地流入。你可以按时间范围、关键字进行检索,也可以针对某个 Pod、某个节点过滤日志——这正是监控 K8s 日志的核心场景。

扩展数据源:APM、指标、安全事件与更多日志接入

EFK 运行起来后,Kibana 还提供丰富的扩展接入能力。点击 Kibana 首页左上角 Logo 回到主页,可以看到四类可添加的数据:

  • APM(Application Performance Monitoring):收集应用内部的深度性能指标与错误信息,支持实时监控成千上万个应用的性能;
  • Log data(日志数据):除 Fluentd/FluentBit 外,还可以从大量日志源接入,列表中同样包含 ELK 中的 Logstash,意味着 EFK 与 ELK 两种采集链路可以共存使用;
  • Metric data(指标数据):可以添加 Prometheus 等多种监控服务的指标源;
  • Security events(安全事件):接入安全相关的事件数据。

对 APM 感兴趣的话,可以进一步查阅 Elastic 官方的应用性能监控文档继续深入(本文不展开)。

小结与资源

至此,我们完成了 EFK Stack 在 Minikube 上的完整落地:通过一份 efk-stack.yaml 清单,以 StatefulSet 部署 3 节点 Elasticsearch、以 Deployment 部署 Kibana、以 DaemonSet 在每个节点部署 Fluentd,并使用kubectl port-forward将 Kibana 暴露到本机,最后通过创建*索引模式在 Discover 中检索 Kubernetes 日志。整个链路印证了 Day 80/81 的核心观点:Elastic 系方案聚焦日志,Fluentd 负责轻量采集,Kibana 负责可视化检索。

如果想进一步理解日志采集与监控的背景,可参考以下资料(均来自原文档):

  • Understanding Logging: Containers & Microservices
  • The Importance of Monitoring in DevOps
  • Understanding Continuous Monitoring in DevOps?
  • DevOps Monitoring Tools
  • Top 5 - DevOps Monitoring Tools
  • How Prometheus Monitoring works
  • Introduction to Prometheus monitoring
  • Promql cheat sheet with examples
  • Log Management for DevOps | Manage application, server, and cloud logs with Site24x7
  • Log Management what DevOps need to know
  • What is ELK Stack?
  • Fluentd simply explained

下一篇内容请继续阅读 Day 83。

  • 文档/教程

【免费下载链接】90DaysOfDevOps

This repository started out as a learning in public project for myself and has now become a structured learning map for many in the community. We have 3 years under our belt covering all things DevOps, including Principles, Processes, Tooling and Use Cases surrounding this vast topic.

项目地址:https://gitcode.com/gh_mirrors/90/90DaysOfDevOps
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询