智享教程网
白蓝主题五 · 清爽阅读
首页  > 日常经验

云原生架构下的日志管理实战经验

最近在公司重构一个微服务项目,从传统部署迁移到 Kubernetes 集群,最头疼的不是接口调用链,而是日志去哪儿了。以前一台服务器,tail -f 日志文件就行,现在 Pod 一会儿起一会儿灭,日志还没看清楚就没了。这才意识到,云原生环境下的日志管理,真不能按老办法来。

问题从哪儿来?

云原生应用通常是容器化、动态调度的,一个服务可能有几十个 Pod 分布在不同节点上,每个 Pod 的生命周期都很短。如果日志还留在容器本地,一旦 Pod 被销毁,日志也就跟着没了。更别提排查问题时要登录十几台节点一个个查,效率低到怀疑人生。

核心思路:集中化 + 结构化

我们最终采用的是 ELK + Filebeat 的组合方案,但做了适配云环境的调整。关键点是让日志不落地到宿主机,而是直接从容器 stdout 收集,通过 Filebeat 发送到 Elasticsearch,再用 Kibana 查看。

在 Kubernetes 中,我们以 DaemonSet 方式部署 Filebeat,确保每个节点都有一个实例运行。它会自动发现本节点上的所有容器,并监听它们的标准输出。

apiVersion: apps/v1
kind: DaemonSet
metadata:
name: filebeat
namespace: logging
spec:
selector:
matchLabels:
k8s-app: filebeat
template:
metadata:
labels:
k8s-app: filebeat
spec:
containers:
- name: filebeat
image: docker.elastic.co/beats/filebeat:7.15.0
volumeMounts:
- name: varlogcontainers
mountPath: /var/log/containers
readOnly: true
volumes:
- name: varlogcontainers
hostPath:
path: /var/log/containers

日志格式要统一

一开始各服务打的日志五花八门,有的 JSON,有的纯文本,时间格式也不一样。后来我们约定:所有服务必须以 JSON 格式输出日志,至少包含 level、timestamp、service_name、trace_id 几个字段。这样在 Kibana 里过滤起来特别方便。

比如 Go 服务中我们用 zap 打日志:

logger, _ := zap.NewProduction()
logger.Info("user login success",
zap.String("user_id", "12345"),
zap.String("ip", "192.168.1.100"))

输出就是一行 JSON,Filebeat 自动解析,存到 ES 后可以直接按字段搜索。

加个缓冲层更稳

刚开始把 Filebeat 直接连 ES,结果 ES 一抖,日志就开始丢。后来中间加了个 Kafka 当缓冲,Filebeat 先发到 Kafka,Logstash 消费写入 ES。虽然链路长了点,但系统抗压能力明显提升,发布高峰期也不怕日志洪峰了。

小团队也能用的轻量方案

如果你们项目没那么大,也可以试试 Loki。它专为 Kubernetes 设计,存储成本低,查询语法和 PromQL 类似,上手快。我们另一个小项目就用的 Grafana + Loki + Promtail 组合,一套下来资源占用不到 ELK 的一半。