系统日志

系统组件日志记录集群中发生的事件,这对调试非常有用。你可以配置日志详细程度以查看更多或更少细节。日志的粒度可以粗到显示组件中的错误,也可以细到显示事件的逐步跟踪(例如 HTTP 访问日志、Pod 状态变更、控制器操作或调度器决策)。

Klog

klog 是 Kubernetes 的日志库。klog 为 Kubernetes 系统组件生成日志消息。

Kubernetes 正在简化其组件中的日志记录。以下 klog 命令行参数在 Kubernetes v1.23 中已弃用,并将在 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 等工具。

在某些情况下,例如无发行版容器或 Windows 系统服务,这些选项不可用。此时,可以将 kube-log-runner 二进制文件用作 Kubernetes 组件的包装器,以重定向输出。预构建的二进制文件包含在几个 Kubernetes 基础镜像中,其传统名称为 /go-runner,在服务器和节点发布归档中则为 kube-log-runner

此表显示了 kube-log-runner 调用如何与 shell 重定向相对应。

用途POSIX shell (例如 bash)kube-log-runner <options> <cmd>
合并 stderr 和 stdout,写入 stdout2>&1kube-log-runner (默认行为)
重定向两者到日志文件1>>/tmp/log 2>&1kube-log-runner -log-file=/tmp/log
复制到日志文件并输出到 stdout2>&1 | tee -a /tmp/logkube-log-runner -log-file=/tmp/log -also-stdout
仅将 stdout 重定向到日志文件>/tmp/logkube-log-runner -log-file=/tmp/log -redirect-stderr=false

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 中描述的其他用例。

如果开发人员在其组件中使用了 WithValuesWithName 等附加函数,则日志条目将包含由其调用者传递到函数中的附加信息。

对于 Kubernetes 1.34,此功能由 ContextualLogging Feature Gate 控制,并默认启用。其基础设施在 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" 值的函数添加的,而无需修改该函数。

在禁用上下文日志时,WithValuesWithName 不起作用,并且日志调用通过全局 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]

--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] (默认启用:false)

为了帮助调试节点上的问题,Kubernetes v1.27 引入了一个特性,允许查看节点上运行的服务的日志。要使用此特性,请确保该节点已启用 NodeLogQuery 功能门控,并且 kubelet 配置选项 enableSystemLogHandlerenableSystemLogQuery 都设置为 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 中检索第一个日志。

可使用的完整选项列表如下:

选项描述
bootboot 显示特定系统启动的消息
patternpattern 通过提供的与 PERL 兼容的正则表达式过滤日志条目
queryquery 指定要返回日志的服务或文件(必需)
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"

下一步

上次修改时间为太平洋标准时间 2024 年 2 月 22 日下午 3:16:上下文日志:文档推广至 Beta (4f0dc7ad36)