跳到主要内容

Loki vs EFK:Kubernetes 日志方案性能对比与落地指南

场景与目标

  • 需要在 K8s 中统一采集 Pod 日志,并在问题发生时快速检索。
  • 希望理解 Loki 与 EFK(Elasticsearch + Fluentd/Fluent Bit + Kibana)的取舍,并能实际部署验证。

本文提供可直接执行的部署、配置与验证步骤,同时给出资源占用与适用场景对比。

方案对比速览

维度LokiEFK
存储模型Chunk + Index(按流拆分,索引轻量)倒排索引,索引体积大
存储成本低:对象存储友好高:索引+数据盘占用大
查询性能对结构化 label 查询快;全文需要范围扫描全文检索强,复杂查询更快
资源占用低:CPU/内存相对友好高:Elasticsearch 需要更多内存与高性能存储
运维复杂度低:组件少,易横向扩展中-高:ES 集群运维与分片管理复杂
适用场景性能/成本敏感,标签化日志需要强大全文检索、聚合分析

结论:

  • 成本敏感、标签化查询为主 → Loki。
  • 需要复杂全文检索/聚合 → 保留 EFK,或混合使用:热点日志在 ES,存量日志归档到对象存储/Loki。

部署 Loki Stack(Helm)

  1. 准备命名空间与 Helm 仓库:
kubectl create namespace logging --dry-run=client -o yaml | kubectl apply -f -
helm repo add grafana https://grafana.github.io/helm-charts
helm repo update
  1. 安装 Loki + Promtail(最小化示例):
helm upgrade --install loki grafana/loki-stack \
--namespace logging \
--set grafana.enabled=true \
--set prometheus.enabled=false \
--set loki.persistence.enabled=false \
--set promtail.enabled=true
kubectl -n logging wait --for=condition=Ready pod -l app.kubernetes.io/name=loki --timeout=180s

生产可开启持久化:--set loki.persistence.enabled=true --set loki.persistence.size=50Gi,并根据节点规模调整副本。

  1. 验证采集:
kubectl -n logging port-forward svc/loki-grafana 3000:80 &
# 浏览器访问 http://localhost:3000 (admin/prom-operator),添加 Loki 数据源 URL: http://loki:3100
# 在 Explore 中查询:{namespace="default"} | line_format "{{.app}} {{.message}}"

部署 EFK(Elasticsearch + Fluent Bit + Kibana)

  1. 安装 Elasticsearch(单节点演示):
helm repo add elastic https://helm.elastic.co
helm upgrade --install es elastic/elasticsearch \
--namespace logging \
--set replicas=1 \
--set minimumMasterNodes=1 \
--set persistence.enabled=false
kubectl -n logging wait --for=condition=Ready pod -l app=elasticsearch-master --timeout=300s
  1. 安装 Kibana:
helm upgrade --install kibana elastic/kibana --namespace logging \
--set service.type=ClusterIP
kubectl -n logging wait --for=condition=Ready pod -l app=kibana --timeout=180s
  1. 部署 Fluent Bit(采集容器标准输出):
# fluent-bit.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: fluent-bit
namespace: logging
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: fluent-bit-read
rules:
- apiGroups: [""]
resources: ["namespaces", "pods"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: fluent-bit-read
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: fluent-bit-read
subjects:
- kind: ServiceAccount
name: fluent-bit
namespace: logging
---
apiVersion: v1
kind: ConfigMap
metadata:
name: fluent-bit-config
namespace: logging
data:
fluent-bit.conf: |
[SERVICE]
Flush 5
Log_Level info
[INPUT]
Name tail
Path /var/log/containers/*.log
Parser docker
Tag kube.*
Mem_Buf_Limit 20MB
[FILTER]
Name kubernetes
Match kube.*
[OUTPUT]
Name es
Match kube.*
Host es-master.logging.svc
Port 9200
Index fluentbit
Type _doc
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: fluent-bit
namespace: logging
spec:
selector:
matchLabels:
app: fluent-bit
template:
metadata:
labels:
app: fluent-bit
spec:
serviceAccountName: fluent-bit
tolerations:
- operator: Exists
containers:
- name: fluent-bit
image: cr.fluentbit.io/fluent/fluent-bit:3.0.4
volumeMounts:
- name: varlibdockercontainers
mountPath: /var/log/containers
readOnly: true
- name: config
mountPath: /fluent-bit/etc/
volumes:
- name: varlibdockercontainers
hostPath:
path: /var/log/containers
- name: config
configMap:
name: fluent-bit-config

应用:

kubectl apply -f fluent-bit.yaml
kubectl -n logging get pods -l app=fluent-bit
  1. 验证:
kubectl -n logging port-forward svc/kibana-kibana 5601:5601 &
# 浏览器访问 http://localhost:5601 ,在 “Stack Management -> Index Patterns” 创建 fluentbit-*,在 Discover 查询日志。

性能与成本提示

  • Loki 写入/查询主要依赖对象存储/块存储,CPU/内存占用低,带宽开销低;适合高日志量、成本敏感场景。
  • EFK 提供强大的全文检索,但 Elasticsearch 对内存/存储 IOPS 要求较高,需规划分片、副本和冷热分层。
  • 可采用混合模式:实时/近期日志用 ES 提供全文搜索,历史日志周期性导出或同时推送到 Loki 以降低存储成本。

排障清单

  • Loki 查询为空:检查 Promtail 是否在节点运行;kubectl logs -n logging -l app.kubernetes.io/name=promtail;确认日志路径挂载 /var/log/containers 存在。
  • Grafana 不显示数据源:确认已在 Grafana 中添加 Loki 数据源或数据源 URL 正确。
  • ES 集群 Yellow/Red:增加副本、检查存储空间和 JVM 内存(可调 esJavaOpts)。
  • Fluent Bit 发送失败:查看 Pod 日志,确认 Output Host/Port 是否正确;ES 是否开启了鉴权。
  • Kibana 无数据:确认索引名称(如 fluentbit-*) 与配置一致,时间范围是否覆盖当前日志时间。

总结

Loki 更轻量、成本低,适合以标签过滤为主的日志检索;EFK 提供更强的全文检索与分析能力但运维成本更高。可根据需求选择其一,或结合使用实现“热数据在 ES,冷数据在 Loki”的平衡方案。以上部署与验证步骤可直接在集群执行,用于快速评估两种方案的效果。