02 - K8s 日志管理
K8s 日志架构
┌──────────────────────────────────────────────────────────┐
│ 方案 1: 节点级日志收集 (推荐) │
│ │
│ Node │
│ ├── Pod A → stdout/stderr → /var/log/containers/ │
│ ├── Pod B → stdout/stderr → /var/log/containers/ │
│ └── DaemonSet (日志收集器) │
│ └── Fluentd / Fluent Bit / Promtail │
│ │ │
│ ▼ │
│ Elasticsearch / Loki │
│ │ │
│ ▼ │
│ Kibana / Grafana │
│ │
├──────────────────────────────────────────────────────────┤
│ 方案 2: Sidecar 模式 │
│ │
│ Pod │
│ ├── App Container → 写日志到共享 Volume │
│ └── Sidecar Container → 读取并转发日志 │
└──────────────────────────────────────────────────────────┘日志查看基础
bash
# 查看 Pod 日志
kubectl logs <pod-name>
# 持续跟踪
kubectl logs -f <pod-name>
# 查看前一个容器的日志(重启后)
kubectl logs <pod-name> --previous
# 多容器 Pod 指定容器
kubectl logs <pod-name> -c <container-name>
# 按标签查看所有 Pod 日志
kubectl logs -l app=web --all-containers
# 最近 1 小时的日志
kubectl logs <pod-name> --since=1h
# 最后 100 行
kubectl logs <pod-name> --tail=100方案对比
| 方案 | 组件 | 存储 | 查询 | 资源消耗 | 适用场景 |
|---|---|---|---|---|---|
| EFK | Elasticsearch + Fluentd + Kibana | Elasticsearch | 强大全文检索 | 高 | 大规模、复杂查询 |
| Loki + Grafana | Promtail + Loki + Grafana | 对象存储 | 标签+grep | 低 | 中小规模、已用 Grafana |
| ELK | Elasticsearch + Logstash + Kibana | Elasticsearch | 全文检索 | 高 | 需要复杂管道 |
Loki 方案(轻量推荐)
Loki 是 Grafana 出品的日志系统,设计理念类似 Prometheus:
bash
# 使用 Helm 安装 Loki Stack
helm repo add grafana https://grafana.github.io/helm-charts
helm repo update
helm install loki grafana/loki-stack \
--namespace monitoring \
--set grafana.enabled=false # 复用已有的 Grafana在 Grafana 中添加 Loki 数据源,即可查询日志:
logql
# LogQL 查询示例
# 按标签筛选
{namespace="default", app="web"}
# 包含关键词
{app="web"} |= "error"
# 不包含
{app="web"} != "health"
# 正则匹配
{app="web"} |~ "status=[45].."
# 统计错误率
rate({app="web"} |= "error" [5m])日志最佳实践
- 应用日志输出到 stdout/stderr,不要写文件
- 结构化日志(JSON 格式),便于解析和查询
- 合理设置日志级别(INFO/WARN/ERROR)
- 不要记录敏感信息(密码、token)
- 设置日志保留策略,防止存储爆满
python
# 结构化日志示例
import json
import logging
class JsonFormatter(logging.Formatter):
def format(self, record):
return json.dumps({
"timestamp": self.formatTime(record),
"level": record.levelname,
"message": record.getMessage(),
"module": record.module,
})