tags:
– Kubernetes
– K8s系列
– DevOps
– EFK
– ELK
– 日志收集
– 可观测性
K8s 系列 | 第 23 天:日志收集实战:EFK/ELK 栈在 K8s 中部署
第 23/30 天 | 本文是 Kubernetes 系列的第 23 篇,带你从零搭建生产级的 K8s 日志收集系统。
一、引言
在 Kubernetes 生产环境中,容器化应用会产生海量日志,而 Pod 的临时性意味着日志会随容器销毁而丢失。如何集中采集、存储和检索这些日志,是每个运维团队必须解决的难题。
目前业界最主流的方案是 EFK(Elasticsearch + Filebeat/Fluentd + Kibana) 和 ELK(Elasticsearch + Logstash + Kibana)。在 K8s 生态中,Fluentd 和 Filebeat 通常以 DaemonSet 方式部署于每个 Node,自动采集所有 Pod 的日志。
本文将手把手带你完成 EFK 栈在 K8s 中的完整部署,涵盖架构设计、配置详解、常见问题排查。
二、核心概念
2.1 日志采集架构
┌─────────────────────────────────────────────────────┐
│ Kubernetes Cluster │
│ │
│ ┌──────┐ ┌──────┐ ┌──────┐ │
│ │ Pod │ │ Pod │ │ Pod │ ... (应用日志) │
│ └──┬───┘ └──┬───┘ └──┬───┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌─────────────────────────────────────┐ │
│ │ Filebeat DaemonSet (每个 Node 一个) │ │
│ │ 采集 /var/log/containers/*.log │ │
│ └──────────────┬──────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────┐ │
│ │ Elasticsearch│ ← 存储 + 索引 │
│ └──────┬───────┘ │
│ │ │
│ ▼ │
│ ┌──────────────┐ │
│ │ Kibana │ ← 可视化查询 │
│ └──────────────┘ │
└─────────────────────────────────────────────────────┘
2.2 为什么选择 Filebeat 而非 Logstash?
| 对比项 | Filebeat | Logstash |
|---|---|---|
| 资源占用 | 极低(Go 编写) | 较高(JVM 运行) |
| 部署方式 | 二进制/容器 | 需要 JVM 环境 |
| 吞吐量 | 高(轻量级) | 可通过 pipeline 扩展 |
| 过滤能力 | 基础(需配置 module) | 强大(丰富 filter 插件) |
| 适用场景 | 日志采集端 | 日志聚合处理端 |
最佳实践:Node 端用 Filebeat 采集,中心端用 Logstash 做复杂数据处理(如有需要)。
三、实战步骤:在 K8s 中部署 EFK 栈
3.1 准备环境
确保集群满足以下条件:
– K8s 1.20+ 集群
– 每个 Node 有足够的磁盘空间(Elasticsearch 建议至少 10GB 可用)
– 已安装 kubectl 并配置好集群
3.2 部署 Elasticsearch
首先创建 Namespace 和 Elasticsearch 的 StatefulSet:
---
apiVersion: v1
kind: Namespace
metadata:
name: logging
---
apiVersion: v1
kind: Service
metadata:
name: elasticsearch
namespace: logging
labels:
app: elasticsearch
spec:
selector:
app: elasticsearch
ports:
- port: 9200
name: rest
- port: 9300
name: inter-node
clusterIP: None
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: elasticsearch
namespace: logging
spec:
serviceName: elasticsearch
replicas: 3
selector:
matchLabels:
app: elasticsearch
template:
metadata:
labels:
app: elasticsearch
spec:
containers:
- name: elasticsearch
image: docker.elastic.co/elasticsearch/elasticsearch:8.10.2
env:
- name: discovery.type
value: single-node
- name: ES_JAVA_OPTS
value: "-Xms512m -Xmx512m"
- name: xpack.security.enabled
value: "false"
ports:
- containerPort: 9200
- containerPort: 9300
resources:
requests:
memory: "1Gi"
cpu: "500m"
limits:
memory: "2Gi"
cpu: "1000m"
volumeMounts:
- name: data
mountPath: /usr/share/elasticsearch/data
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 10Gi
注意:生产环境建议使用 3 节点集群,并启用 xpack 安全认证。
3.3 部署 Kibana
apiVersion: apps/v1
kind: Deployment
metadata:
name: kibana
namespace: logging
labels:
app: kibana
spec:
replicas: 1
selector:
matchLabels:
app: kibana
template:
metadata:
labels:
app: kibana
spec:
containers:
- name: kibana
image: docker.elastic.co/kibana/kibana:8.10.2
env:
- name: ELASTICSEARCH_HOSTS
value: "http://elasticsearch:9200"
ports:
- containerPort: 5601
---
apiVersion: v1
kind: Service
metadata:
name: kibana
namespace: logging
labels:
app: kibana
spec:
type: ClusterIP
ports:
- port: 5601
targetPort: 5601
selector:
app: kibana
3.4 部署 Filebeat(DaemonSet)
Filebeat 以 DaemonSet 方式部署,确保每个节点自动采集所有容器日志:
apiVersion: v1
kind: ConfigMap
metadata:
name: filebeat-config
namespace: logging
labels:
app: filebeat
data:
filebeat.yml: |
filebeat.autodiscover:
providers:
- type: kubernetes
node: ${NODE_NAME}
hints.enabled: true
hints.default_config:
type: container
paths:
- /var/log/containers/*${data.kubernetes.container.id}.log
processors:
- add_kubernetes_metadata:
host: ${NODE_NAME}
matchers:
- logs_path:
logs_path: "/var/log/containers/"
output.elasticsearch:
hosts: '${ELASTICSEARCH_HOSTS:elasticsearch:9200}'
index: "filebeat-%{[agent.version]}-%{+yyyy.MM.dd}"
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: filebeat
namespace: logging
labels:
app: filebeat
spec:
selector:
matchLabels:
app: filebeat
template:
metadata:
labels:
app: filebeat
spec:
serviceAccountName: filebeat
containers:
- name: filebeat
image: docker.elastic.co/beats/filebeat:8.10.2
args: ["-e", "-strict.perms=false"]
env:
- name: NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
- name: ELASTICSEARCH_HOSTS
value: "elasticsearch:9200"
volumeMounts:
- name: config
mountPath: /usr/share/filebeat/filebeat.yml
subPath: filebeat.yml
- name: varlog
mountPath: /var/log/containers
readOnly: true
- name: varlibdocker
mountPath: /var/lib/docker/containers
readOnly: true
volumes:
- name: config
configMap:
name: filebeat-config
- name: varlog
hostPath:
path: /var/log/containers
- name: varlibdocker
hostPath:
path: /var/lib/docker/containers
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: filebeat
namespace: logging
labels:
app: filebeat
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: filebeat
labels:
app: filebeat
rules:
- apiGroups: [""]
resources:
- nodes
- namespaces
- pods
- services
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: filebeat
labels:
app: filebeat
subjects:
- kind: ServiceAccount
name: filebeat
namespace: logging
roleRef:
kind: ClusterRole
name: filebeat
apiGroup: rbac.authorization.k8s.io
3.5 一键部署所有组件
# 创建日志收集 Namespace 并部署所有组件
kubectl apply -f elasticsearch.yaml
kubectl apply -f kibana.yaml
kubectl apply -f filebeat.yaml
# 验证部署状态
kubectl -n logging get pods -w
# 等待所有 Pod 为 Running 状态后,检查 Elasticsearch 健康状态
kubectl -n logging port-forward svc/elasticsearch 9200:9200 &
curl http://localhost:9200/_cluster/health?pretty
3.6 访问 Kibana
# 端口转发到本地访问 Kibana
kubectl -n logging port-forward svc/kibana 5601:5601 &
浏览器打开 http://localhost:5601,进入 Stack Management → Index Patterns,创建 filebeat-* 索引模式,即可在 Discover 页面查看所有容器日志。
四、常见问题
4.1 Elasticsearch Pod 一直 CrashLoopBackOff
原因:vm.max_map_count 过低导致 Elasticsearch 无法启动。
解决:
# 在每个 Node 上执行
sudo sysctl -w vm.max_map_count=262144
# 永久生效
echo "vm.max_map_count=262144" | sudo tee -a /etc/sysctl.conf
4.2 Filebeat 采集不到日志
排查步骤:
1. 检查 Filebeat Pod 日志:kubectl -n logging logs ds/filebeat
2. 确认 /var/log/containers/ 目录是否存在容器日志文件
3. 检查 RBAC 权限是否正确绑定
4. 验证 Filebeat 配置中的 output.elasticsearch.hosts 是否正确
4.3 Kibana 无法连接 Elasticsearch
检查:
# 测试 Elasticsearch 是否可达
kubectl -n logging exec -it deploy/kibana -- curl -s http://elasticsearch:9200
# 检查 Kibana 环境变量
kubectl -n logging describe pod $(kubectl -n logging get pod -l app=kibana -o name) | grep ELASTICSEARCH
4.4 日志存储占用空间过大
解决方案:
– 配置 ILM(索引生命周期管理)自动删除过期索引
– 通过 Logstash 或 Filebeat processors 过滤不必要的日志
– 采用 Curator 定时任务清理旧索引
# 使用 Curator 删除 7 天前的索引(示例)
curator --host elasticsearch delete_indices --filter_list
'{"filtertype":"age","source":"name","timestring":"%Y.%m.%d","unit":"days","unit_count":7}'
五、总结
本文详细介绍了 EFK 栈在 Kubernetes 中的完整部署流程:
| 组件 | 作用 | 部署方式 |
|---|---|---|
| Elasticsearch | 日志存储与搜索引擎 | StatefulSet(3 副本) |
| Filebeat | 日志采集与传输 | DaemonSet(每个 Node 一个) |
| Kibana | 日志可视化与查询 | Deployment + Service |
核心要点回顾:
1. Filebeat 以 DaemonSet 方式部署,自动采集 /var/log/containers/ 下的所有容器日志
2. 通过 add_kubernetes_metadata 处理器自动注入 Pod 元数据(Namespace、Pod 名、Label 等)
3. Elasticsearch 使用 StatefulSet 保证数据持久化,生产环境建议 3 节点集群
4. Kibana 通过 ClusterIP Service 对内暴露,生产环境应通过 Ingress 对外暴露
生产环境建议:Elasticsearch 节点应使用独立的高性能 SSD 存储,开启 xpack 安全认证,并配置 ILM 策略管理索引生命周期。Filebeat 可根据日志量调整
harvester_buffer_size和backoff参数。
下期预告
第 24 天:RBAC 权限控制:ServiceAccount、Role、ClusterRole 深度解析
我们将深入 K8s 的权限控制体系,从 ServiceAccount 创建到 Role 和 ClusterRole 的绑定策略,再到生产环境中的最小权限原则实践,彻底搞懂 K8s 的 RBAC 机制。
📚 系列目录:
– 第 1 天:Kubernetes 核心概念与架构全景解析
– 第 2 天:手把手搭建 K8s 集群(kubeadm 实战)
– 第 3 天:Pod 详解与生命周期管理
– … 更多内容请访问博客首页
– 第 22 天:监控体系搭建:Prometheus + Grafana + Kube-state-metrics
– → 第 23 天:日志收集实战:EFK/ELK 栈在 K8s 中部署 ← 本文
– 第 24 天:RBAC 权限控制(即将发布)















暂无评论内容