0%

K8s-日志

Kubernetes 日志处理

基本的日志

使用 kubectl logs 查看 pod 日志

1
kubectl logs -f ${POD_NAME}

如果容器已经崩溃停止,仍然可以使用 kubectl logs --previous 获取该容器的日志,只不过需要添加参数 --previous。 如果 Pod 中包含多个容器,而想要看其中某一个容器的日志,那么请在命令的最后增加容器名字作为参数。

常用的日志命令示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 追踪名称空间 nsA 下容器组 pod1 的日志
kubectl logs -f pod1 -n nsA

# 追踪名称空间 nsA 下容器组 pod1 中容器 container1 的日志
kubectl logs -f pod1 -c container1 -n nsA

# 查看容器组 nginx 下所有容器的日志
kubectl logs nginx --all-containers=true

# 查看带有 app=nginx 标签的所有容器组所有容器的日志
kubectl logs -lapp=nginx --all-containers=true

# 查看容器组 nginx 最近20行日志
kubectl logs --tail=20 nginx

# 查看容器组 nginx 过去1个小时的日志
kubectl logs --since=1h nginx

节点级别的日志

日志存储

容器化应用程序写入到 stdoutstderr 中的任何信息,都将被容器引擎重定向到某个地方。例如,Docker 容器引擎将 stdoutstderr 这两个输出流重定向到 logging driver,Kubernetes的默认配置中,最终 logging driver 最终把日志写入了一个 json 格式的文件

默认配置下,如果容器重启了,kubelet 只为该容器保留最后一份日志。如果 Pod 从节点上驱逐,当中所有的容器也将一并被驱逐,连同他们的日志也将被删除。

日志轮转

在节点级别的日志里,一个非常重要的考量是实现 log rotation(日志轮转),这样的话,日志文件就不会耗尽节点上的存储空间。

Kubernetes当前并不负责对日志进行轮转,而是期望由 kubernetes 安装工具来配置一个合适的解决方案。例如,在使用 kube-up.sh 脚本安装的 kubernetes 集群中,配置了 logrotage 工具,该工具每小时执行一次日志轮转的操作。

也可以配置容器引擎,使其自动轮转应用程序的日志,例如,使用 Docker 的 log-opt。在 kube-up.sh 脚本中,后者被用在了 GCP 的 COS 镜像中,而前者则用在了任何其他环境。两种情况下,默认的配置是,日志文件达到 10MB 时进行轮转。

如果Kubernetes的外部系统执行了文件的轮转,只有最新日志文件中的内容可以通过 kubectl logs 命令返回。例如,如果假设日志文件刚刚达到 10MB, logrotate 执行了日志轮转,将所有日志挪到一个带时间戳的日志存档文件中,并清空了当前日志文件,此时 kubectl logs 将返回空的日志信息(因为当前日志文件为空)

系统组件的日志

Kubernetes中存在两种类型的系统组件:

  • 运行在容器中的系统组件
  • 不运行在容器中的系统组件

例如:

  • kubenetes scheduler 和 kube-proxy 运行在容器中
  • kubelet 和容器引擎(例如 docker)不运行在容器中

在带有 systemd 的机器上,kubelet 和容器引擎将日志写入 Linux 系统的 journald 中。如果没有 systemd,kubelet 和容器引擎将日志写入目录 /var/log 中的 .log 文件。运行在容器中的系统组件则使用将日志写入目录 /var/log 中(绕过了默认的日志机制–即将日志写入stdoutstderr)。

与容器化应用程序的日志相似,记录在 /var/log 目录下的系统组件的日志也应该进行轮转。在使用 kube-up.sh 脚本安装的集群中,这些日志文件将由 logrotate 工具进行轮转,轮转的机制是:每天或者每当日志文件超过 100MB 时。

集群级别的日志

Kubernetes 中并不默认提供集群级别的日志,不过,有许多种途径可以和集群级别的日志整合。例如:

  • 在每个节点上配置日志代理
  • 在应用程序的 Pod 中包含一个专门用于收集日志的 sidecar 容器
  • 从应用程序中直接推送日志到日志存储端

在节点上配置日志代理

如上图所示,通过在每个节点上配置一个节点级别的 logging-agent,就可以实现集群级别的日志(cluster-level logging)。该 logging-agent 专门用来将节点上的日志文件中的日志推送到日志的后端存储。所有应用程序的标准输出都被使用 docker 的 logging driver存储到了节点的 /var/log/containers 目录下(K8S 的默认配置)。因此,节点级别的 logging-agent 应该能够将该目录下的日志文件发送到日志后端。系统组件的日志 可以考虑一下是否要推送到日志后端。

logging-agent 必须运行在每一个节点上,推荐使用 DaemonSet

对于 Kubernetes 集群来说,使用节点级别的 logging-agent 实现集群级别的日志(cluster-level logging)是使用最广泛也最为推荐的一种做法,因为这种做法只为每个节点创建了一个 logging-agent,且无需对节点上的容器化应用程序做任何修改。

当然,只有当应用程序使用 stdout 和 stderr 记录日志时,节点级别的 logging-agent 才能生效。Kubernetes 默认安装并不指定 logging-agent,但是Kubernetes默认打包了两种 logging-agent 以供选择:

在 sidecar 容器中配置 logging-agent

可以按照以下方式使用 sidecar 容器,以收集日志:

  • sidecar 容器跟踪应用程序的日志文件,并输出到 sidecar 容器自己的 stdout
  • sidecar 容器运行一个 logging-agent,追踪应用程序的日志文件,并发送到日志后端

sidecar输出到stdout

使用 sidecar 容器将应用程序的日志输出到 sidecar 容器自己的 stdoutstderr 之后,可以直接利用已经在集群上运行的 kubelet 以及节点级别的 logging-agent 进一步将日志发送到日志后端。此时 sidecar 容器可以从日志文件读取、socket读取或者 journald 读取日志内容,其输出则是 sidecar 容器自己的 stdoutstderr

使用这种方法:

  • 只需要对那些不能将日志输出到 stdoutstderr 的应用程序进行特殊配置即可,那些已经可以将日志输出到 stdoutstderr 的应用程序,则可以直接利用节点级别的 logging-agent。
  • 由于重定向日志的逻辑非常简单,这种做法所带来的系统开销也是非常小的。
  • 此外,stdoutstderr 由 kubelet 处理,还可以直接使用支持 apiserver 的 kubernetes 管理工具来查看日志,例如 kubectl logs或者Kubernetes Dashboard等

直接从应用程序容器发送日志到后端