Go应用日志收不到的根本原因是未按容器规范输出到stdout/stderr:log需显式SetOutput(os.Stdout),禁用文件路径配置,移除轮转逻辑;结构化日志库须配JSON格式;采集端需监听/var/log/pods/路径并确认containerd日志驱动为json-file。

Go 应用部署到 Kubernetes 后日志收不到,基本不是 kubectl logs 用错了,而是应用没按容器环境规范输出、或者采集链路断在了某一层。
Go 程序必须把日志写到 stdout/stderr
容器里没有文件系统持久化概念,log.Printf 或 zap.NewProduction() 默认写文件会失败或静默丢弃。必须显式重定向:
- 用
log.SetOutput(os.Stdout)替换默认的os.Stderr(如果想统一走 stdout) - 结构化日志库如
zap要用zap.AddStacktrace(zap.DPanicLevel)+zap.NewDevelopmentEncoderConfig()配置为纯文本或 JSON 格式输出 - 禁用所有日志轮转、文件切割逻辑——Docker 会自动把 stdout 流转发给日志驱动
- 避免在
init()或main()开头就 panic,否则可能连第一条日志都来不及刷出
Deployment 中要禁用日志文件路径配置
很多 Go 项目习惯从 config.yaml 读取 log.file: /var/log/app.log,这在 Kubernetes 里是无效且危险的:
- 容器内
/var/log是临时目录,重启即丢;挂载 EmptyDir 又增加复杂度 - 如果程序强行创建文件,可能因权限问题 crash,或被 seccomp 策略拦截
- 正确做法是彻底移除文件路径配置项,只保留
log.level和log.format: json这类控制输出行为的字段 - 若必须兼容旧配置,启动时加参数覆盖:
args: ["--log-format=console", "--log-level=info"]
集群级日志采集不能只靠 kubectl logs
kubectl logs -f pod/name 只能查当前存活 Pod 的最近日志,历史日志、滚动前日志、崩溃前日志全丢失:
- 确保节点上运行了日志采集器(如
fluentd、filebeat或云厂商的cloud-logging-agent) - 采集器必须监听
/var/log/pods/下的符号链接——这是 kubelet 写入容器 stdout 的实际位置 - 如果用了
containerd,确认/etc/containerd/config.toml中plugins."io.containerd.grpc.v1.cri".registry日志驱动设为json-file(默认) - 验证采集:进节点执行
ls -l /var/log/pods/*/*/logs/,看是否有stdout.log文件生成
调试日志缺失的第一检查点
当 kubectl logs 返回空或“no such file”,先不怀疑采集器,直接进容器看原始输出是否产生:
- 运行
kubectl exec -it,确认 fd 1(stdout)和 fd 2(stderr)指向-- sh -c 'ls -l /proc/1/fd/' pipe:或socket:,而不是anon_inode或死路径 - 临时改用
strace -p 1 -e write观察进程是否真在调用write(1, ...) - 检查 Go 应用是否设置了
GOMAXPROCS过高导致协程调度异常,间接卡住日志 goroutine
真正卡住日志的,往往不是采集端,而是 Go 程序自己没把 log 输出通道打通——这点比 YAML 配置错误更难定位,也更容易被忽略。











