3. Kubernetes基础与Pod日志:K8s核心组件、kubectl logs命令详解、Pod日志的生命周期、Sidecar模式收集日志、实战:使用kubectl排查Pod日志
3.1 K8s核心组件:日志的“交通枢纽”
聊Pod日志之前,得先搞清楚K8s的架构。说白了,K8s就是一个“管家”,帮你管理一堆容器。
核心组件就这几个:
- API Server:整个集群的“门面”。你敲的
kubectl命令,最终都打到它这里。日志请求也不例外。 - kubelet:每个节点上的“代理人”。它负责拉取容器日志,并暴露给API Server。我排查问题时,经常直接SSH到节点上,用
journalctl -u kubelet看kubelet自己的日志,往往能找到线索。 - Scheduler & Controller Manager:这俩负责调度和维持期望状态。它们不直接处理Pod日志,但Pod跑在哪个节点上,是它们决定的。
- etcd:集群的“数据库”。Pod的元数据存在这里,但日志内容不存。
你想想看,日志从容器里产生,到被你用kubectl logs看到,中间经过了kubelet和API Server。理解这个链路,对后面排查问题很有帮助。
3.2 kubectl logs命令详解:不只是“看日志”
kubectl logs是我日常使用频率最高的命令之一。但很多人只用了它的皮毛。
基础用法:
# 查看单个容器的日志
kubectl logs <pod-name>
# 实时跟踪,类似 tail -f
kubectl logs -f <pod-name>
# 查看前N行
kubectl logs --tail=100 <pod-name>
# 查看特定时间范围的日志
kubectl logs --since=1h <pod-name>
kubectl logs --since-time="2024-01-01T00:00:00Z" <pod-name>
多容器Pod的情况:
# 指定容器名
kubectl logs <pod-name> -c <container-name>
# 查看所有容器的日志(K8s 1.14+)
kubectl logs <pod-name> --all-containers=true
kubectl logs --tail=50 -f 来调试。既能看到最近的上下文,又能实时跟踪。比直接 -f 从头刷屏舒服多了。
3.3 Pod日志的生命周期:日志去哪儿了?
Pod日志的生命周期,其实挺脆弱的。我遇到过不少新手,以为日志会永久保存。
实际情况是这样的:
- 日志文件位置:kubelet把容器日志写到宿主机的
/var/log/pods/目录下。每个Pod一个子目录,里面按容器名分文件。 - 日志轮转:kubelet默认会做日志轮转。默认配置是每个日志文件最大10MB,最多保留5个文件。超过就删旧的。
- Pod删除后:Pod一旦被删除,对应的日志目录也会被清理。默认情况下,日志保留时间取决于kubelet的配置,通常是几天。
- 容器重启:容器重启后,之前的日志还在。但如果你用
kubectl logs --previous,可以看到上一次容器的日志。这个参数我经常用来排查“容器CrashLoopBackOff”的问题。
3.4 Sidecar模式收集日志:优雅的解决方案
Sidecar模式,说白了就是在同一个Pod里,多跑一个容器专门干日志收集的活。主容器只管写日志到标准输出或文件,Sidecar容器负责读取、处理、发送。
为什么用Sidecar?
- 解耦:业务容器不需要关心日志怎么发、发到哪。
- 灵活性:可以给不同的Pod配不同的日志处理逻辑。
- 资源隔离:日志收集的CPU、内存消耗,不会影响业务容器。
一个典型的Sidecar配置示例:
apiVersion: v1
kind: Pod
metadata:
name: my-app
spec:
containers:
- name: app
image: my-app:latest
volumeMounts:
- name: log-volume
mountPath: /var/log/app
- name: log-collector
image: fluentd:latest
volumeMounts:
- name: log-volume
mountPath: /var/log/app
readOnly: true
volumes:
- name: log-volume
emptyDir: {}
这里的关键是 emptyDir 卷。两个容器共享这个目录,主容器写日志,Sidecar容器读日志。Pod删除时,emptyDir也会被清理,不会留下垃圾。
initContainers 先初始化日志目录。
3.5 实战:使用kubectl排查Pod日志
光说不练假把式。咱们来一个真实的排查场景。
场景: 一个Web服务Pod,用户反馈接口返回500错误。我们需要通过日志定位问题。
步骤1:查看Pod状态
kubectl get pods -n production
# 输出:my-web-app-7d4f8b9c6-x2k3l Running 0/1 CrashLoopBackOff
嗯,Pod在CrashLoopBackOff状态。说明容器一直在重启。
步骤2:查看当前日志
kubectl logs -n production my-web-app-7d4f8b9c6-x2k3l
# 输出:Error: failed to connect to database: connection refused
数据库连接失败。但这是当前容器的日志,可能不完整。
步骤3:查看上一次容器的日志
kubectl logs -n production my-web-app-7d4f8b9c6-x2k3l --previous
# 输出:Starting server on port 8080...
# 2024-01-15 10:30:45 [INFO] Received request GET /api/users
# 2024-01-15 10:30:46 [ERROR] Database timeout after 30s
看到了!上一次容器是正常启动的,但处理请求时数据库超时了。结合当前容器的“连接被拒绝”,基本可以判断数据库服务挂了。
步骤4:查看事件
kubectl describe pod -n production my-web-app-7d4f8b9c6-x2k3l
# 在Events部分看到:
# Warning BackOff 2m kubelet Back-off restarting failed container
事件也确认了容器在反复重启。
步骤5:查看节点日志(如果需要)
如果问题更复杂,比如Pod一直Pending,我会去节点上看kubelet日志:
# SSH到节点
journalctl -u kubelet -n 100 --no-pager
describe),再看当前日志(logs),最后看上一次日志(logs --previous)。这个顺序能覆盖90%的问题。如果还不行,才去看节点日志。
总结一下,kubectl logs 是排查Pod问题的第一把钥匙。配合 describe 和 get events,基本能搞定日常大部分问题。但记住,这只是临时手段。生产环境一定要上集中的日志收集系统,不然节点一挂,啥都查不到。