在分布式系统日志管理领域,我们经常会听到两个相似的术语:ELK 和 EFK。它们看起来只有一字之差,但实际上代表了两种不同的技术栈组合。本文将深入剖析ELK与EFK的核心区别,并通过在Kubernetes环境中部署EFK的实战案例,帮助读者全面理解这两种架构的适用场景和实现方式。
一、ELK与EFK:一字之差,有何不同?
1.1 什么是ELK Stack?
ELK 是三个开源项目的首字母缩写:
- Elasticsearch:分布式搜索和分析引擎,负责日志的存储、检索和分析
- Logstash:服务器端数据处理管道,负责日志的采集、过滤和传输
- Kibana:数据可视化平台,负责日志的展示和分析
ELK Stack 是日志管理领域的经典组合,Logstash作为数据采集和处理的核心组件,提供了强大的数据转换能力,支持200多个插件,可以处理各种数据源和格式。
1.2 什么是EFK Stack?
EFK 同样是三个开源项目的首字母缩写,其中的 F 代表 Fluentd:
- Elasticsearch:日志存储和搜索引擎
- Fluentd:开源数据收集器,负责日志的采集和转发
- Kibana:日志可视化工具
EFK 可以看作是 ELK 的一个变种,核心区别在于用 Fluentd 替换了 Logstash 作为日志采集层。
1.3 ELK与EFK的核心区别对比
| 对比维度 | ELK (Logstash) | EFK (Fluentd) |
|---|---|---|
| 开发语言 | Java (Logstash) / Ruby (早期) | C和Ruby混合 |
| 资源消耗 | 较高(Java虚拟机开销) | 较低(轻量级) |
| 部署方式 | 通常作为独立服务部署 | 适合作为DaemonSet每节点部署 |
| 插件生态 | 超过200个插件,生态丰富 | 约500+插件,社区活跃 |
| 配置复杂度 | 配置语法灵活但较复杂 | 配置简洁,采用JSON式配置 |
| 性能特点 | 处理能力强,但内存占用高 | 内存占用小,适合容器环境 |
| 适用场景 | 传统VM/物理机环境 | 云原生、Kubernetes环境 |
1.4 为什么Kubernetes官方推荐EFK?
在Kubernetes环境中,EFK逐渐成为主流选择,主要原因包括:
- 资源效率:Fluentd作为轻量级采集器,内存占用远低于Logstash,适合在每个Node节点上以DaemonSet形式运行
- 容器原生支持:Fluentd对容器日志格式有更好的原生支持,能够轻松获取Docker/containerd的日志
- 云原生适配:Fluentd是CNCF(云原生计算基金会)毕业项目,与Kubernetes生态天然契合
- 配置简洁:Fluentd的配置更符合云原生环境下的声明式配置理念
- 性能稳定:在高并发日志场景下,Fluentd表现出更好的稳定性
二、EFK在Kubernetes中的架构设计
2.1 Kubernetes日志收集的挑战
Kubernetes集群中的日志收集面临几个特殊挑战:
- 日志来源分散:容器日志分布在各个Node节点
- 容器生命周期短:Pod频繁创建销毁,日志采集需动态适应
- 元数据关联:需要将日志与Pod、Namespace等K8s元数据关联
2.2 EFK在K8s中的典型架构
EFK在Kubernetes中的部署架构如下:
┌─────────────────────────────────────────────────────┐
│ Kubernetes Cluster │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Node 1 │ │ Node 2 │ │ Node N │ │
│ │ ┌──────┐ │ │ ┌──────┐ │ │ ┌──────┐ │ │
│ │ │Fluentd│ │ │ │Fluentd│ │ │ │Fluentd│ │ (DaemonSet)
│ │ └──┬───┘ │ │ └──┬───┘ │ │ └──┬───┘ │ │
│ └─────┼─────┘ └─────┼─────┘ └─────┼─────┘ │
│ │ │ │ │
│ └──────────────┼──────────────┘ │
│ │ │
│ ┌──────▼──────┐ │
│ │ Elasticsearch│ │
│ │ Service │ │
│ └──────┬──────┘ │
│ │ │
│ ┌──────▼──────┐ │
│ │ Kibana │ │
│ │ Service │ │
│ └──────────────┘ │
└─────────────────────────────────────────────────────┘
架构特点:
- Fluentd以DaemonSet部署:确保每个Node都有一个日志采集实例
- Elasticsearch作为中心存储:接收所有Fluentd推送的日志
- Kibana提供可视化界面:通过Service暴露访问入口
2.3 数据流向
- 日志产生 :容器 stdout/stderr 输出到 Node 的
/var/log/containers/ - 日志采集:Fluentd 监听该目录,读取新增日志内容
- 元数据增强:Fluentd 通过 Kubernetes API 获取 Pod 元数据(Namespace、Pod名称、标签等)
- 日志传输:Fluentd 将处理后的日志发送到 Elasticsearch
- 存储索引:Elasticsearch 对日志建立索引
- 可视化查询:用户通过 Kibana 界面检索和分析日志
三、EFK实战部署(基于Kubernetes)
3.1 环境准备
部署EFK需要准备以下环境:
- 运行正常的 Kubernetes 集群(本文基于 v1.6.2)
- 所有节点已安装 Docker 并配置为 json-file 日志驱动
- 能够访问 Google Container Registry 或已准备替代镜像
3.2 镜像准备
由于镜像位于 gcr.io 国外仓库,使用以下脚本替换镜像源:
bash
#!/bin/bash
images=(
elasticsearch:v2.4.1-1
kibana:v4.6.1-1
fluentd-elasticsearch:1.22
)
for imageName in ${images[@]} ; do
docker pull docker.io/bigwhite/$imageName
docker tag docker.io/bigwhite/$imageName gcr.io/google_containers/$imageName
docker rmi docker.io/bigwhite/$imageName
done
3.3 部署Fluentd(DaemonSet)
3.3.1 获取配置文件
bash
cd /home/user/k8s/
git clone https://github.com/kubernetes/kubernetes.git
cd kubernetes/cluster/addons/fluentd-elasticsearch
3.3.2 解决节点调度问题
Fluentd 默认只调度到带有特定标签的节点:
bash
# 查看节点标签
kubectl describe nodes node0.localdomain
# 添加所需标签
kubectl label node node0.localdomain beta.kubernetes.io/fluentd-ds-ready=true
# 创建Fluentd
kubectl create -f fluentd-es-ds.yaml
3.3.3 验证Fluentd运行状态
bash
kubectl get pods -n kube-system | grep fluentd
# 输出示例:fluentd-es-v1.22-4g2zl 1/1 Running 0 5m
3.4 解决Docker日志驱动问题
Fluentd无法读取日志的常见原因:Docker日志驱动配置错误
bash
# 检查日志驱动
docker info | grep "Logging Driver"
# 如果输出 journald,需要修改为 json-file
# 修改Docker配置
vi /etc/sysconfig/docker
# 增加 OPTIONS='--log-driver=json-file'
# 重启Docker
systemctl daemon-reload
systemctl restart docker
3.5 部署Elasticsearch和Kibana
3.5.1 创建ReplicationController(同时运行ES和Kibana)
elasticsearch-kibana-rc.yaml:
yaml
apiVersion: v1
kind: ReplicationController
metadata:
name: elasticsearch-kibana
namespace: kube-system
spec:
replicas: 1
selector:
k8s-app: elasticsearch-kibana
template:
metadata:
labels:
k8s-app: elasticsearch-kibana
spec:
containers:
- name: elasticsearch
image: gcr.io/google_containers/elasticsearch:v2.4.1-1
ports:
- containerPort: 9200 # HTTP API
- containerPort: 9300 # 集群通信
volumeMounts:
- name: es-persistent-storage
mountPath: /usr/share/elasticsearch/data
- name: kibana
image: gcr.io/google_containers/kibana:v4.6.1-1
ports:
- containerPort: 5601
env:
- name: ELASTICSEARCH_URL
value: http://localhost:9200 # 通过localhost访问同Pod的ES
volumes:
- name: es-persistent-storage
emptyDir: {} # 生产环境建议使用hostPath或PVC
3.5.2 创建Service(暴露访问入口)
elasticsearch-kibana-svc.yaml:
yaml
apiVersion: v1
kind: Service
metadata:
name: elasticsearch-kibana
namespace: kube-system
spec:
type: NodePort # 对外暴露NodePort
ports:
- name: elasticsearch
port: 9200
targetPort: 9200
- name: kibana
port: 5601
targetPort: 5601
nodePort: 30016 # 指定Kibana访问端口
selector:
k8s-app: elasticsearch-kibana
3.5.3 启动服务
bash
kubectl create -f elasticsearch-kibana-svc.yaml
kubectl create -f elasticsearch-kibana-rc.yaml
3.6 配置Kibana
- 访问Kibana:
http://<任意节点IP>:30016 - 首次进入需配置Index Pattern
- 创建索引后即可在Discover页面查看日志
四、进阶:自定义Fluentd解决认证问题
在自建Kubernetes集群中,Fluentd连接Kubernetes API时可能遇到SSL证书验证失败的问题。
4.1 问题分析
Fluentd的 fluent-plugin-kubernetes_metadata_filter 插件默认使用HTTPS连接Kubernetes API,如果集群未配置有效证书,将导致验证失败。
4.2 解决方案:自定义Fluentd镜像
Dockerfile:
dockerfile
FROM fabric8/fluentd-kubernetes:v1.14
ADD start-fluentd /start-fluentd
start-fluentd(关键修改部分):
bash
# 在fluent.conf中添加以下配置
<filter kubernetes.**>
type kubernetes_metadata
kubernetes_url ${KUBERNETES_URL}
verify_ssl ${VERIFY_SSL} # 新增:控制SSL验证
</filter>
构建镜像:
bash
docker build -t 10.10.50.161:5000/fluentd-custom:v1.0 .
docker push 10.10.50.161:5000/fluentd-custom:v1.0
在DaemonSet中配置环境变量:
yaml
env:
- name: KUBERNETES_URL
value: "http://10.10.50.156:8080/api" # 使用HTTP
- name: VERIFY_SSL
value: "false" # 关闭SSL验证
五、ELK与EFK的选择建议
5.1 选择ELK的场景
- 传统环境:部署在虚拟机或物理机上,资源充足
- 复杂数据处理:需要使用Logstash丰富的数据转换能力
- 已有ELK投资:团队熟悉Logstash配置,现有监控体系基于ELK
5.2 选择EFK的场景
- Kubernetes环境:需要轻量级、每节点部署的日志采集器
- 资源敏感:容器环境资源有限,需最小化日志采集开销
- 云原生架构:追求与CNCF生态更好的集成
- 简化运维:希望统一使用声明式配置管理日志采集
5.3 混合架构的可能性
实际生产环境中,也可以采用混合架构:
- Fluentd + Logstash:Fluentd负责节点级采集,Logstash作为中心管道进行二次处理
- Beats + Logstash:使用Elastic生态的Filebeat采集,Logstash处理
六、常见问题与排障
6.1 Fluentd无日志输出
排查步骤:
- 检查Pod状态:
kubectl logs -n kube-system <fluentd-pod> - 检查Docker日志驱动:
docker info | grep "Logging Driver" - 检查节点目录:
ls -la /var/log/containers/
6.2 Kibana无法连接Elasticsearch
可能原因:
- ELASTICSEARCH_URL配置错误
- Elasticsearch服务未正常启动
- 网络策略限制
排查命令:
bash
kubectl exec -n kube-system <kibana-pod> -- curl http://localhost:9200
6.3 日志显示延迟
优化方案:
- 调整Fluentd的
flush_interval参数 - 增加Elasticsearch的索引刷新间隔
- 检查网络带宽和ES写入性能
总结
ELK与EFK之争,本质上是传统架构与云原生架构在日志领域的映射。ELK作为经典组合,在数据处理能力上依然强大;而EFK凭借轻量、云原生友好的特点,成为Kubernetes环境的首选。理解两者的差异和适用场景,能够帮助我们在不同技术栈中做出更合适的选择。
无论选择哪种方案,核心目标都是让日志数据真正成为系统可观测性的基石,为故障排查、性能优化和安全分析提供有力支撑。