背景

在 Kubernetes 集群环境中,Pod 日志分散存储在各个节点上,传统方式需要登录到对应节点查看,效率低下且难以进行全局搜索和分析。本文介绍一种基于 Fluentd + Elasticsearch 的日志集中采集方案,实现日志的统一存储、检索和可视化展示。

方案架构

1
Pod(stdout/stderr) → kubelet → 节点日志文件 → Fluentd DaemonSet → Elasticsearch → Kibana/Grafana

核心组件说明

  • Fluentd DaemonSet:部署在每个节点上,以 DaemonSet 方式运行,负责采集节点级日志
  • Elasticsearch:集中存储日志,提供全文检索能力
  • Kibana/Grafana:可视化展示和查询界面

部署步骤

1. 部署 Elasticsearch 集群

推荐使用 operator 模式管理,以下为基础部署示例:

1
2
3
4
5
6
7
8
9
10
11
12
apiVersion: elasticsearch.k8s.elastic.co/v1
kind: Elasticsearch
metadata:
name: es-cluster
namespace: logging
spec:
version: 8.11.0
nodeSets:
- name: default
count: 3
config:
node.store.allow_mmap: false

2. 部署 Fluentd DaemonSet

创建 fluentd 配置 ConfigMap:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
apiVersion: v1
kind: ConfigMap
metadata:
name: fluentd-config
namespace: logging
data:
fluent.conf: |
<source>
@type tail
@id input_container
path /var/log/containers/*.log
pos_file /var/log/fluentd-containers.log.pos
tag kubernetes.*
read_from_head true
<parse>
@type json
time_format %Y-%m-%dT%H:%M:%S.%NZ
</parse>
</source>

<source>
@type tail
@id input_docker
path /var/log/docker.log
pos_file /var/log/fluentd-docker.log.pos
tag docker
<parse>
@type regexp
expression /^(?<time>.{19})(?<stream>stdout|stderr)(?<log>.*)$/
time_format %Y-%m-%dT%H:%M:%S.%NZ
</parse>
</source>

<filter kubernetes.**>
@type kubernetes_metadata
@id kubernetes_metadata
</filter>

<match **>
@type elasticsearch
@id output_elasticsearch
host elasticsearch.logging.svc
port 9200
logstash_format true
logstash_prefix kubernetes
flush_interval 10s
</match>

3. 部署 Fluentd DaemonSet

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: fluentd
namespace: logging
spec:
selector:
matchLabels:
app: fluentd
template:
metadata:
labels:
app: fluentd
spec:
serviceAccountName: fluentd
tolerations:
- operator: Exists
containers:
- name: fluentd
image: fluent/fluentd:v1.16-1
env:
- name: FLUENTD_CONF
value: fluent.conf
resources:
limits:
memory: 512Mi
cpu: 500m
requests:
memory: 256Mi
cpu: 100m
volumeMounts:
- name: varlog
mountPath: /var/log
- name: varlogcontainers
mountPath: /var/log/containers
readOnly: true
- name: fluentd-config
mountPath: /etc/fluent/config.d
volumes:
- name: varlog
hostPath:
path: /var/log
- name: varlogcontainers
hostPath:
path: /var/log/containers
- name: fluentd-config
configMap:
name: fluentd-config

4. 创建 ServiceAccount 并授权

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
apiVersion: v1
kind: ServiceAccount
metadata:
name: fluentd
namespace: logging
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: fluentd
rules:
- apiGroups: [""]
resources:
- pods
- nodes
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: fluentd
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: fluentd
subjects:
- kind: ServiceAccount
name: fluentd
namespace: logging

验证与调试

检查 Fluentd 运行状态

1
2
kubectl get pods -n logging -l app=fluentd
kubectl logs -n logging -l app=fluentd --tail=100

检查 Elasticsearch 数据

1
2
3
4
5
# 检查索引是否创建
curl -s "http://elasticsearch.logging.svc:9200/_cat/indices?v"

# 查看索引文档数
curl -s "http://elasticsearch.logging.svc:9200/_cat/count/kubernetes-$(date +%Y.%m.%d)?v"

常见问题排查

日志未采集到:检查节点路径 /var/log/containers/ 是否存在,确认 Fluentd Pod 已调度到目标节点。

数据写入 Elasticsearch 失败:验证 Elasticsearch 服务可达性,检查 Fluentd 日志中的错误信息,可能是 ES 磁盘空间不足或认证问题。

字段解析异常:检查 JSON 格式是否标准,部分应用输出到 stdout 的格式可能不统一。

优化建议

  1. 日志级别控制:应用层合理设置日志级别,避免大量 DEBUG 日志占用存储
  2. 滚动策略:配置 Elasticsearch ILM 策略,默认 30 天后自动删除旧索引
  3. 资源限制:根据集群规模调整 Fluentd 的 CPU 和内存限制,防止资源抢占
  4. 敏感信息过滤:在 Fluentd 配置中添加脱敏 filter,过滤敏感字段

总结

通过 Fluentd DaemonSet 方案,可以实现 Kubernetes 集群日志的自动采集和集中存储。配合 Elasticsearch 和 Kibana,能够高效进行日志检索和可视化分析,显著提升故障排查和问题定位效率。建议在生产环境部署前,根据实际日志量评估 Elasticsearch 集群规模。