- 文档/教程
【免费下载链接】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.
导读
本篇是 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 工作负载类型 | 副本数 | 职责 |
|---|---|---|---|
| Elasticsearch | StatefulSet | 3 | 有状态存储,需稳定的网络标识与持久化卷,组成 es-cluster |
| Kibana | Deployment | 1 | 无状态 Web 界面,通过 Service 对外暴露 5601 端口 |
| Fluentd | DaemonSet | 每个节点 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: 5601Kibana 是无状态应用,以 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.yamlkubectl 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正是此意),因此通配符*可以覆盖全部日志索引。
操作步骤:
- 点击左侧菜单的Discover(发现)标签页;
- 在创建索引模式页面,索引模式输入
*,点击Next step; - 进入第 2 步(Step 2 of 2),从下拉框中选择@timestamp作为时间字段,这会使后续检索结果按时间过滤与排序;
- 点击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.
相关推荐
Kubernetes 集群日志监控实战:基于 90DaysOfDevOps 在 Minikube 上部署 EFK Stack(Elasticsearch + Fluentd + Kibana)
Kubernetes 集群日志监控实战:基于 90DaysOfDevOps 在 Minikube 上部署 EFK Stack(Elasticsearch + F
文档/教程90DaysOfDevOps 实战:在 Kubernetes(Minikube)上部署 EFK 日志监控栈
90DaysOfDevOps 实战:在 Kubernetes(Minikube)上部署 EFK 日志监控栈 导读 本篇是 90DaysOfDevOps 可观测性
文档/教程在 Kubernetes 上部署 EFK Stack 监控日志:Minikube 实战与 Kibana 查询指南
在 Kubernetes 上部署 EFK Stack 监控日志:Minikube 实战与 Kibana 查询指南 本文以 90DaysOfDevOps 项目第
文档/教程
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考