系统日志
系统组件日志记录集群中发生的事件,这对于调试非常有用。你可以配置日志的详细程度来查看更多或更少的细节。日志可以粗粒度到只显示组件内的错误,也可以细粒度到显示事件的逐步跟踪(如 HTTP 访问日志、Pod 状态变化、控制器动作或调度器决策)。
警告
与此处描述的命令行参数相反,日志输出本身不属于 Kubernetes API 的稳定性保证范围:单个日志条目及其格式可能会在不同发布版本之间发生变化!Klog
klog 是 Kubernetes 的日志库。klog 为 Kubernetes 系统组件生成日志消息。
Kubernetes 正在简化其组件中的日志记录。从 Kubernetes v1.23 开始,以下 klog 命令行参数已被废弃,并在 Kubernetes v1.26 中移除
--add-dir-header
--alsologtostderr
--log-backtrace-at
--log-dir
--log-file
--log-file-max-size
--logtostderr
--one-output
--skip-headers
--skip-log-headers
--stderrthreshold
输出将始终写入标准错误 (stderr),无论输出格式如何。输出重定向应由调用 Kubernetes 组件的组件处理。这可以是 POSIX Shell 或 systemd 之类的工具。
在某些情况下,例如 distroless 容器或 Windows 系统服务,这些选项不可用。此时可以使用 kube-log-runner
二进制文件作为 Kubernetes 组件的包装器来重定向输出。在一些 Kubernetes 基础镜像中包含了一个预构建的二进制文件,其传统名称是 /go-runner
,在服务器和节点发布存档中则称为 kube-log-runner
。
下表显示了 kube-log-runner
调用与 Shell 重定向的对应关系
用法 | POSIX Shell(如 bash) | kube-log-runner <选项> <命令> |
---|---|---|
合并标准错误和标准输出,写入标准输出 | 2>&1 | kube-log-runner (默认行为) |
将两者都重定向到日志文件 |
|
|
复制到日志文件并输出到标准输出 |
|
|
仅将标准输出重定向到日志文件 |
|
|
Klog 输出
传统 klog 原生格式的示例
I1025 00:15:15.525108 1 httplog.go:79] GET /api/v1/namespaces/kube-system/pods/metrics-server-v0.3.1-57c75779f-9p8wg: (1.512ms) 200 [pod_nanny/v0.0.0 (linux/amd64) kubernetes/$Format 10.56.1.19:51756]
消息字符串可能包含换行符
I1025 00:15:15.525108 1 example.go:79] This is a message
which has a line break.
结构化日志记录
Kubernetes v1.23 [beta]
警告
迁移到结构化日志消息是一个持续进行的过程。此版本并非所有日志消息都是结构化的。解析日志文件时,你还必须处理非结构化日志消息。
日志格式和值序列化可能会发生变化。
结构化日志记录在日志消息中引入了统一的结构,从而允许以程序方式提取信息。你可以用更少的精力、更低的成本存储和处理结构化日志。生成日志消息的代码决定了它是使用传统的非结构化 klog 输出还是结构化日志记录。
结构化日志消息的默认格式是文本,其格式与传统 klog 向后兼容
<klog header> "<message>" <key1>="<value1>" <key2>="<value2>" ...
示例
I1025 00:15:15.525108 1 controller_utils.go:116] "Pod status updated" pod="kube-system/kubedns" status="ready"
字符串会被引用。其他值则使用 %+v
格式化,这可能导致日志消息 根据数据 在下一行继续。
I1025 00:15:15.525108 1 example.go:116] "Example" data="This is text with a line break\nand \"quotation marks\"." someInt=1 someFloat=0.1 someStruct={StringField: First line,
second line.}
上下文日志记录
Kubernetes v1.30 [beta]
上下文日志记录构建在结构化日志记录之上。它主要关乎开发人员如何使用日志记录调用:基于该概念的代码更灵活,并支持 上下文日志记录 KEP 中描述的其他用例。
如果开发人员在其组件中使用 WithValues
或 WithName
等附加函数,那么日志条目将包含调用者传递给函数的附加信息。
对于 Kubernetes 1.33,此功能由 ContextualLogging
特性门控 控制,并默认启用。此基础结构在 1.24 版本中添加,但未修改组件。 component-base/logs/example
命令演示了如何使用新的日志记录调用以及支持上下文日志记录的组件的行为。
$ cd $GOPATH/src/k8s.io/kubernetes/staging/src/k8s.io/component-base/logs/example/cmd/
$ go run . --help
...
--feature-gates mapStringBool A set of key=value pairs that describe feature gates for alpha/experimental features. Options are:
AllAlpha=true|false (ALPHA - default=false)
AllBeta=true|false (BETA - default=false)
ContextualLogging=true|false (BETA - default=true)
$ go run . --feature-gates ContextualLogging=true
...
I0222 15:13:31.645988 197901 example.go:54] "runtime" logger="example.myname" foo="bar" duration="1m0s"
I0222 15:13:31.646007 197901 example.go:55] "another runtime" logger="example" foo="bar" duration="1h0m0s" duration="1m0s"
logger
键和 foo="bar"
由记录 runtime
消息和 duration="1m0s"
值的函数的调用者添加,而无需修改该函数。
禁用上下文日志记录后,WithValues
和 WithName
不起作用,日志调用通过全局 klog 日志记录器。因此,此附加信息不再出现在日志输出中。
$ go run . --feature-gates ContextualLogging=false
...
I0222 15:14:40.497333 198174 example.go:54] "runtime" duration="1m0s"
I0222 15:14:40.497346 198174 example.go:55] "another runtime" duration="1h0m0s" duration="1m0s"
JSON 日志格式
Kubernetes v1.19 [alpha]
警告
JSON 输出不支持许多标准的 klog 参数。有关不受支持的 klog 参数列表,请参见命令行工具参考。
并非所有日志都保证以 JSON 格式写入(例如,在进程启动期间)。如果你打算解析日志,请确保你也能处理非 JSON 格式的日志行。
字段名称和 JSON 序列化可能会发生变化。
--logging-format=json
参数将日志格式从 klog 原生格式更改为 JSON 格式。JSON 日志格式示例(漂亮打印)
{
"ts": 1580306777.04728,
"v": 4,
"msg": "Pod status updated",
"pod":{
"name": "nginx-1",
"namespace": "default"
},
"status": "ready"
}
具有特殊含义的键
ts
- 以 Unix 时间表示的时间戳(必需,浮点数)v
- 详细程度(仅用于信息类日志,不用于错误消息,整数)err
- 错误字符串(可选,字符串)msg
- 消息(必需,字符串)
当前支持 JSON 格式的组件列表
日志详细级别
-v
参数控制日志详细程度。增加值会增加日志记录的事件数量。减少值会减少日志记录的事件数量。增加详细程度设置会记录越来越不严重的事件。详细程度设置为 0 只记录关键事件。
日志位置
系统组件有两种类型:在容器中运行的组件和不在容器中运行的组件。例如
- Kubernetes 调度器和 kube-proxy 在容器中运行。
- kubelet 和 容器运行时 不在容器中运行。
在使用 systemd 的机器上,kubelet 和容器运行时写入 journald。否则,它们写入 /var/log
目录下的 .log
文件。容器内的系统组件总是写入 /var/log
目录下的 .log
文件,绕过默认的日志记录机制。与容器日志类似,你应该轮换 /var/log
目录下的系统组件日志。在使用 kube-up.sh
脚本创建的 Kubernetes 集群中,日志轮换由 logrotate
工具配置。logrotate
工具每天轮换日志,或者当日志大小大于 100MB 时进行轮换。
日志查询
Kubernetes v1.30 [beta]
(默认禁用)为了帮助调试节点上的问题,Kubernetes v1.27 引入了一个功能,允许查看在节点上运行的服务日志。要使用此功能,请确保为该节点启用了 NodeLogQuery
特性门控,并且 kubelet 配置选项 enableSystemLogHandler
和 enableSystemLogQuery
都设置为 true。在 Linux 上,假设服务日志通过 journald 提供。在 Windows 上,假设服务日志在应用程序日志提供程序中提供。在两种操作系统上,日志也可以通过读取 /var/log/
中的文件获取。
如果你被授权与节点对象交互,你可以在所有节点或部分节点上试用此功能。以下是从节点检索 kubelet 服务日志的示例:
# Fetch kubelet logs from a node named node-1.example
kubectl get --raw "/api/v1/nodes/node-1.example/proxy/logs/?query=kubelet"
你还可以获取文件,前提是这些文件位于 kubelet 允许日志抓取的目录中。例如,你可以在 Linux 节点上从 /var/log
中抓取日志:
kubectl get --raw "/api/v1/nodes/<insert-node-name-here>/proxy/logs/?query=/<insert-log-file-name-here>"
kubelet 使用启发式方法来检索日志。如果你不确定某个系统服务是将日志写入操作系统原生日志记录器(如 journald)还是写入 /var/log/
中的日志文件,这会有所帮助。启发式方法首先检查原生日志记录器,如果不可用,则尝试从 /var/log/<servicename>
或 /var/log/<servicename>.log
或 /var/log/<servicename>/<servicename>.log
中检索最先出现的日志。
可以使用的完整选项列表如下:
选项 | 描述 |
---|---|
boot | boot 显示特定系统启动时的消息 |
pattern | pattern 通过提供的 PERL 兼容正则表达式过滤日志条目 |
query | query 指定要返回日志的服务或文件(必需) |
sinceTime | 一个 RFC3339 时间戳,从此时间开始显示日志(包括此时间) |
untilTime | 一个 RFC3339 时间戳,到此时间结束显示日志(包括此时间) |
tailLines | 指定从日志末尾检索的行数;默认为抓取整个日志 |
更复杂查询的示例
# Fetch kubelet logs from a node named node-1.example that have the word "error"
kubectl get --raw "/api/v1/nodes/node-1.example/proxy/logs/?query=kubelet&pattern=error"