容器日志的正确处理方式分为三个层次:
基础层:熟练使用 kubectl logs 命令,包括 –tail、–since、-f、–previous 等参数。多容器 Pod 必须指定容器名称。
架构层:理解容器日志的存储机制(/var/log/pods 目录)、日志轮转配置、kubelet 的日志处理逻辑。
平台层:建立分布式日志收集架构(EFK、Loki),实现日志的集中存储、搜索和分析。
运维工程师应避免进入容器内部查看日志的习惯,这不仅效率低下,还可能因为容器重启或进入调试状态而影响业务。正确的做法是通过 kubectl logs 或日志收集系统查看日志。
日志的规范性同样重要:结构化输出(JSON)、合理的日志级别、规范的字段命名,这些都为后续的日志分析和问题定位提供基础。
一、容器日志的基础机制
1.1 容器日志的存储位置
在 containerd 环境中,容器日志默认存储在节点上的 /var/log/pods/<namespace>/<pod_name>/<container_name>/ 目录下。
查看容器日志文件:
# 查看节点的容器日志目录
ls -la /var/log/pods/
# 查看特定 Pod 的日志
ls -la /var/log/pods/default_nginx-deployment-6d9f4c8b7-x2m9n_abc123/
# 查看特定容器的日志文件
ls -la /var/log/pods/default_nginx-deployment-6d9f4c8b7-x2m9n_abc123/nginx/
# 查看日志内容
cat /var/log/pods/default_nginx-deployment-6d9f4c8b7-x2m9n_abc123/nginx/0.log
容器日志文件的命名规则:<container_name>/<restart_count>.log。restart_count 从 0 开始,每次容器重启后递增。
1.2 kubelet 的日志处理
kubelet 负责将容器的主进程 stdout 和 stderr 重定向到日志文件。当容器主进程向 stdout/stderr 写入时,Docker/containerd 会将这些输出捕获并写入日志文件。
kubelet 还负责日志轮转,当日志文件达到一定大小后会进行轮转:
# 查看日志轮转配置
cat /var/lib/kubelet/config.yaml | grep -A 5 "logging"
# 默认配置
# containerLogMaxSize: 10Mi
# containerLogMaxFiles: 5
1.3 containerd-shim 的作用
containerd-shim 是容器运行时的一个中间进程,它的作用是:
作为容器的父进程,处理容器的退出信号。
保持容器在 kubelet 重启后仍然运行。
管理容器的 stdin/stdout 流。
查看 containerd-shim 进程:
# 查看所有 containerd-shim 进程
ps aux | grep containerd-shim
# 查看 containerd-shim 管理的容器
sudo ctr -n k8s.io containers list
二、kubectl logs 的正确使用方式
2.1 基本用法
kubectl logs 是查看容器日志最常用的方式:
# 查看当前最新的日志
kubectl logs nginx-deployment-6d9f4c8b7-x2m9n
# 查看上一个 terminated 容器的日志(容器重启后)
kubectl logs nginx-deployment-6d9f4c8b7-x2m9n --previous
# 持续跟踪日志(类似 tail -f)
kubectl logs -f nginx-deployment-6d9f4c8b7-x2m9n
# 查看最近 100 行日志
kubectl logs nginx-deployment-6d9f4c8b7-x2m9n --tail=100
# 查看指定时间范围内的日志
kubectl logs nginx-deployment-6d9f4c8b7-x2m9n --since=1h
kubectl logs nginx-deployment-6d9f4c8b7-x2m9n --since-time="2026-01-01T00:00:00Z"
2.2 多容器 Pod 的日志查看
当 Pod 包含多个容器时,必须指定容器名称:
# 查看多容器 Pod 中特定容器的日志
kubectl logs <pod-name> -c <container-name>
# 持续跟踪特定容器的日志
kubectl logs -f <pod-name> -c <container-name>
# 同时查看所有容器的日志
kubectl logs <pod-name> --all-containers=true
# 使用标签选择器查看多个 Pod 的日志
kubectl logs -l app=nginx --tail=100
2.3 常见错误与解决方案
错误一:Pod 未找到
kubectl logs nginx
Error from server (NotFound): pods "nginx" not found
# 解决:指定正确的命名空间
kubectl logs nginx -n production
kubectl logs nginx -n production --all-namespaces
错误二:容器未找到
kubectl logs multi-container-pod
Error from server (BadRequest): a container name must be specified for pod multi-container-pod, choose one of: [nginx sidecar]
# 解决:使用 -c 参数指定容器名
kubectl logs multi-container-pod -c nginx
kubectl logs multi-container-pod -c sidecar
错误三:Pod 处于 Terminating 状态
kubectl logs nginx-deployment-6d9f4c8b7-x2m9n
Error from server (NotFound): pods "nginx-deployment-6d9f4c8b7-x2m9n" not found
# 解决:使用 --previous 查看上一个容器的日志
kubectl logs nginx-deployment-6d9f4c8b7-x2m9n --previous
# 如果 Pod 已经彻底删除,查看节点上的日志文件
ssh <node-name> "cat /var/log/pods/<pod-id>/<container-name>/0.log"
三、日志过滤与格式化
3.1 日志级别过滤
大多数应用使用结构化日志,支持不同的日志级别(DEBUG、INFO、WARN、ERROR):
# 查看 ERROR 级别的日志
kubectl logs nginx-deployment-6d9f4c8b7-x2m9n | grep ERROR
# 查看最近 1 小时的 ERROR 日志
kubectl logs nginx-deployment-6d9f4c8b7-x2m9n --since=1h | grep -E "ERROR|FATAL|CRITICAL"
# 统计各级别日志数量
kubectl logs nginx-deployment-6d9f4c8b7-x2m9n --since=24h | awk '{print $5}' | sort | uniq -c
3.2 时间戳过滤
# 提取特定时间范围的日志
kubectl logs nginx-deployment-6d9f4c8b7-x2m9n --since=1h | \
awk -F'[] []' '$2 " " $3 >= "2026-01-15 10:00:00" && $2 " " $3 <= "2026-01-15 11:00:00"'
# 使用 sed 进行时间范围过滤
kubectl logs nginx-deployment-6d9f4c8b7-x2m9n | \
sed -n '/2026-01-15 10:00:00/,/2026-01-15 11:00:00/p'
3.3 JSON 格式日志解析
如果应用输出 JSON 格式的日志,可以使用 jq 进行解析:
# 安装 jq(如果尚未安装)
kubectl exec -it <pod-name> -- apk add jq
# 解析 JSON 日志
kubectl logs <pod-name> | jq -r '.level, .message'
# 统计各错误类型的数量
kubectl logs <pod-name> --since=24h | jq -r '.error // "no-error"' | sort | uniq -c | sort -rn
# 提取特定字段
kubectl logs <pod-name> | jq -r 'select(.level == "error") | .timestamp, .message'
四、节点级别的日志访问
4.1 直接访问日志文件
当 kubectl 无法使用时,可以直接访问节点上的日志文件:
# 连接到节点
ssh <node-name>
# 查看 Pod 日志目录
ls -la /var/log/pods/
# 使用 journalctl 查看容器日志
sudo journalctl -u kubelet --since "1 hour ago" | grep <pod-name>
# 使用 ctr 查看容器信息
sudo ctr -n k8s.io containers list | grep <container-name>
sudo ctr -n k8s.io tasks logs <container-id>
4.2 containerd 日志
containerd 自身的日志通常由 systemd 管理:
# 查看 containerd 日志
sudo journalctl -u containerd --since "1 hour ago" | grep -E "error|warn" --color=never
# 查看 containerd 服务状态
sudo systemctl status containerd
# 查看 containerd 配置文件
cat /etc/containerd/config.toml | grep -E "sandbox|log_level"
4.3 kubelet 日志
kubelet 日志对于诊断节点级别的问题非常重要:
# 查看 kubelet 日志
sudo journalctl -u kubelet --since "30 minutes ago" --no-pager
# 查看 kubelet 日志中的错误
sudo journalctl -u kubelet --since "1 hour ago" | grep -i error
# 实时跟踪 kubelet 日志
sudo journalctl -u kubelet -f
五、分布式日志收集架构
5.1 EFK 日志架构
EFK(Elasticsearch + Fluentd + Kibana)是 Kubernetes 环境中最常用的日志解决方案之一。
架构组件:
Fluentd/Fluent Bit:日志收集器,运行在每个节点上,负责收集容器日志并转发到 Elasticsearch。
Elasticsearch:分布式搜索引擎,存储和索引日志数据。
Kibana:可视化界面,用于查询和分析日志。
5.1.1 Fluentd/Fluent Bit 部署
# DaemonSet 方式部署 Fluent Bit
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: fluent-bit
namespace: kube-system
spec:
selector:
matchLabels:
k8s-app: fluent-bit
template:
metadata:
labels:
k8s-app: fluent-bit
spec:
containers:
- name: fluent-bit
image: fluent/fluent-bit:3.0.0
ports:
- name: http
containerPort: 2020
volumeMounts:
- name: varlog
mountPath: /var/log
readOnly: true
- name: varlibdockercontainers
mountPath: /var/lib/docker/containers
readOnly: true
- name: fluent-bit-config
mountPath: /fluent-bit/etc
volumes:
- name: varlog
hostPath:
path: /var/log
- name: varlibdockercontainers
hostPath:
path: /var/lib/docker/containers
- name: fluent-bit-config
configMap:
name: fluent-bit-config
---
apiVersion: v1
kind: ConfigMap
metadata:
name: fluent-bit-config
namespace: kube-system
data:
fluent-bit.conf: |
[SERVICE]
Flush 5
Log_Level info
Daemon off
Parsers_File parsers.conf
[INPUT]
Name tail
Path /var/log/containers/*.log
Parser docker
Tag kube.containers.*
Refresh_Interval 5
[OUTPUT]
Name es
Match kube.containers.*
Host elasticsearch.logging.svc
Port 9200
Index kubernetescontainers
Type flb_type
Retry_Limit 2
parsers.conf: |
[PARSER]
Name docker
Format json
Time_Key time
Time_Format %Y-%m-%dT%H:%M:%S.%L
5.1.2 Fluent Bit 配置详解
Fluent Bit 的核心配置包括:
INPUT:定义日志来源,tail 插件读取容器日志文件。
FILTER:处理和转换日志数据,添加元信息。
OUTPUT:定义日志输出目标。
BUFFER:缓冲配置,指定内存或磁盘缓冲策略。
# 添加 Kubernetes 元信息的 Filter
[FILTER]
Name kubernetes
Match kube.containers.*
Kube_URL https://kubernetes.default.svc:443
Kube_CA_File /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
Kube_Token_File /var/run/secrets/kubernetes.io/serviceaccount/token
Kube_Tag_Prefix kube.containers.var.log.containers.
Merge_Log On
Keep_Log Off
K8S-Logging.Parser On
K8S-Logging.Exclude On
5.2 Loki 日志架构
Loki 是 Grafana 实验室开发的日志聚合系统,与 Prometheus 架构类似,具有资源占用低、易于部署的优点。
# Loki 部署示例
apiVersion: apps/v1
kind: Deployment
metadata:
name: loki
namespace: monitoring
spec:
replicas: 2
selector:
matchLabels:
app: loki
template:
metadata:
labels:
app: loki
spec:
containers:
- name: loki
image: grafana/loki:3.0.0
ports:
- name: http
containerPort: 3100
args:
- -config.file=/etc/loki/local-config.yaml
- -target=all
resources:
limits:
cpu: "2"
memory: 4Gi
requests:
cpu: "500m"
memory: 1Gi
---
# Promtail 配置(收集 Kubernetes 日志)
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: promtail
namespace: monitoring
spec:
selector:
matchLabels:
app: promtail
template:
metadata:
labels:
app: promtail
spec:
containers:
- name: promtail
image: grafana/promtail:3.0.0
args:
- -config.file=/etc/promtail/promtail.yaml
volumeMounts:
- name: config
mountPath: /etc/promtail
- name: varlog
mountPath: /var/log
- name: pods
mountPath: /var/log/pods
- name: dockercontainers
mountPath: /var/lib/docker/containers
volumes:
- name: config
configMap:
name: promtail-config
- name: varlog
hostPath:
path: /var/log
- name: pods
hostPath:
path: /var/log/pods
- name: dockercontainers
hostPath:
path: /var/lib/docker/containers
5.3 日志收集的最佳实践
5.3.1 结构化日志
应用应输出结构化日志(JSON 格式),便于后续解析和分析:
{
"timestamp": "2026-01-15T10:30:00.123Z",
"level": "error",
"message": "Database connection failed",
"service": "user-api",
"request_id": "abc123",
"error_code": "DB_CONN_001",
"stack_trace": "..."
}
5.3.2 日志级别规范
ERROR:影响功能的问题,需要立即处理。
WARN:潜在问题或配置不当。
INFO:重要的业务事件和状态变更。
DEBUG:开发调试信息,生产环境应关闭。
5.3.3 日志保留策略
根据合规要求和存储成本制定日志保留策略:
热存储(Elasticsearch/Loki):7-30 天
温存储(对象存储):30-90 天
冷存储(归档):90 天以上
六、应用日志的最佳实践
6.1 应用层日志配置
6.1.1 日志输出到 stdout/stderr
容器环境的标准做法是将日志输出到 stdout/stderr,由容器运行时收集:
# Python 示例
import logging
import sys
logging.basicConfig(
level=logging.INFO,
format='{"timestamp": "%(asctime)s", "level": "%(levelname)s", "message": "%(message)s"}',
handlers=[logging.StreamHandler(sys.stdout)]
)
6.1.2 日志轮转配置
应用层也应配置日志轮转,避免单文件过大:
# Logback 配置示例(Java)
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>/var/log/app/application.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>/var/log/app/application.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>30</maxHistory>
<totalSizeCap>10GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>{"timestamp": "%d{ISO8601}", "level": "%level", "logger": "%logger", "message": "%msg}%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="FILE"/>
</root>
</configuration>
6.2 Sidecar 日志收集模式
对于需要特殊日志处理的应用,可以使用 Sidecar 模式:
apiVersion: apps/v1
kind: Deployment
metadata:
name: app-with-sidecar
spec:
template:
spec:
containers:
- name: app
image: my-app:latest
volumeMounts:
- name: log-volume
mountPath: /var/log/myapp
- name: log-collector
image: fluent/fluent-bit:3.0.0
volumeMounts:
- name: log-volume
mountPath: /var/log/myapp
- name: fluent-bit-config
mountPath: /fluent-bit/etc
volumes:
- name: log-volume
emptyDir: {}
- name: fluent-bit-config
configMap:
name: fluent-bit-config
七、日志相关故障排查
7.1 kubectl logs 无响应
# 检查 API Server 是否正常
kubectl get componentstatuses
# 检查 API Server 日志
kubectl logs -n kube-system kube-apiserver-<node-name> --tail=100
# 检查 kubelet 是否正常
ssh <node-name> "systemctl status kubelet"
# 绕过 API Server 直接查看日志文件
ssh <node-name> "cat /var/log/pods/<namespace>_<pod-name>_<uid>/<container-name>/0.log | tail -100"
7.2 日志丢失问题
7.2.1 容器重启导致日志丢失
默认情况下,容器重启后旧日志会被删除。解决方案:
配置日志持久化存储
使用远程日志收集系统
启用日志轮转但增加保留文件数量
# 修改 kubelet 日志配置,增加保留文件数
cat /var/lib/kubelet/config.yaml
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
containerLogMaxFiles: 10
containerLogMaxSize: 50Mi
7.2.2 Fluent Bit/Fluentd 无法收集日志
# 检查 Fluent Bit Pod 状态
kubectl get pod -n kube-system -l k8s-app=fluent-bit
# 查看 Fluent Bit 日志
kubectl logs -n kube-system -l k8s-app=fluent-bit
# 检查 ConfigMap 配置是否正确
kubectl describe configmap fluent-bit-config -n kube-system
# 测试 Fluent Bit 配置
kubectl exec -it -n kube-system fluent-bit-xxxx -- fluent-bit --test --parser=parsers.conf < /var/log/containers/*.log
7.3 日志文件过大的处理
# 查看大日志文件
find /var/log/pods -name "*.log" -size +100M -exec ls -lh {} \;
# 在节点上手动压缩日志
sudo gzip /var/log/pods/<path>/0.log
# 清理旧的日志文件
sudo find /var/log/pods -name "*.log.*" -mtime +7 -delete
# 监控日志目录大小
du -sh /var/log/pods/*
7.4 Pod 日志与容器日志不一致
某些情况下,kubectl logs 输出的日志与实际容器日志文件可能存在差异:
# 比较两者的差异
kubectl logs <pod-name> > /tmp/kubectl.log
ssh <node-name> "cat /var/log/pods/<pod-id>/<container>/0.log" > /tmp/file.log
diff /tmp/kubectl.log /tmp/file.log
# 可能的原因:
# 1. 日志轮转导致文件变化
# 2. 容器重启,--previous 指向不同的日志文件
# 3. 日志编码问题
八、日志监控与告警
8.1 错误日志监控
配置 Prometheus 规则监控错误日志数量:
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: log-error-monitoring
namespace: monitoring
spec:
groups:
- name: application-logs
rules:
- alert: HighErrorRate
expr: |
sum(rate(container_log_messages_total{level="error"}[5m])) by (namespace, pod)
> 0.1
for: 5m
labels:
severity: warning
annotations:
summary: "High error rate in {{ $labels.namespace }}/{{ $labels.pod }}"
description: "Error rate exceeds 10% over 5 minutes"
8.2 日志存储容量监控
- alert: LogStorageUsageHigh
expr: |
(node_filesystem_avail_bytes{mountpoint="/var/log"} / node_filesystem_size_bytes{mountpoint="/var/log"}) < 0.2
for: 10m
labels:
severity: warning
annotations:
summary: "Log storage usage is above 80%"
九、实用命令参考
9.1 快速查看多个 Pod 日志
# 查看标签为 app=nginx 的所有 Pod 日志
kubectl logs -l app=nginx --tail=50
# 查看最近 1 小时内的错误日志
kubectl logs -l app=nginx --since=1h | grep -E "ERROR|FATAL"
# 统计错误数量
kubectl logs -l app=nginx --since=24h | grep -c "ERROR"
9.2 实时查看多个 Pod 日志
# 使用 stern 同时查看多个 Pod 的日志
stern -n production app=nginx --since=10m
# 只显示包含 ERROR 的行
stern -n production app=nginx --filter=ERROR
# 显示带有时间戳
stern -n production app=nginx --timestamp
9.3 日志分析常用命令
# 查看日志分布
kubectl logs <pod-name> | awk '{print $5}' | sort | uniq -c | sort -rn
# 查看最常见的错误
kubectl logs <pod-name> --since=24h | jq -r '.error // "no-error"' | sort | uniq -c | sort -rn | head -10
# 分析请求延迟
kubectl logs <pod-name> | jq -r 'select(.type=="request") | .duration' | awk '{sum+=$1; count++} END {print "Average:", sum/count, "ms"}'
# 查看特定时间段内的日志
kubectl logs <pod-name> | awk -F'[] []' '$2 >= "2026-01-15T10:00:00" && $2 <= "2026-01-15T










暂无评论内容