「KUBERNETES-ADDONS」- 日志

问题描述

多种多样的日志:
1)应用程序具有日志,用于排查问题;
2)集群具有日志,用于排查问题;
3)容器环境具有日志机制,容器化应用应将日志写入标准输出与标准错误;

但这些日志机制存在问题:
1)容器引擎提供的日志功能远远不够:容器崩溃,驱逐 POD 实例,节点崩溃,在这些情况下我们依旧希望访问日志。所以日志需要独立存储,并且生命周期与节点、容器等等无关;

该概念被称为“集群日志”。“集群日志”需要单独存储,但是 Kubernetes 并没有提供日志后端存储,需要我们自己集成;

该笔记将记录:与 Kubernetes Cluster 日志有关内容,包括日志种类、收集方法等等,及相关问题的解决办法。该笔记结合官方 Logging Architecture 文档,整理与日志有关内容;

解决方案

在 Kubernetes Cluster 中,需要处理的日志分为以下几种:
1)容器外日志:kubelet、Docker
2)容器内日志:(已写标准输入、标准错误)容器应用程序,包括集群组件(比如 kube-porxy,etcd 等等)
3)容器内日志:(未写标准输入、标准错误)容器应用应用,写入容器本地

使用 DaemonSet 运行 POD 实例,在节点中收集日志;

写入标准输出的日志

使用 kubectl logs 查看日志,添加–previous 选项查看已崩溃容器的日志;

如果在 POD 实例中具有容器,可以指定容器名查看特定容器日志;

节点级日志类型

应用程序日志

由容器应用写入标准输出与标准错误的日志,会被容器引擎重定向。例如在 Docker 中,由日志驱动处理(在 Kubernetes 中,被配置写入 JSON 格式的文件中);

注意,使用 Docker 日志驱动无法处理多行日志,需要在日志收集工具中进行处理;

如果容器重启,则 kubelet 会保存单个容器及它的日志。若驱逐 POD 实例,所有对应的容器将被驱逐,包括日志;

另外节点日志还要考虑轮转问题,防止日志消耗过多磁盘。但是 Kubernetes 当前不负责日志轮转,这个问题应该由容器应用处理。另外可以可以配置容器环境处理日志轮转,例如使用 Docker 的--log-opt选项;

当执行 kubectl logs 时,由对应节点的 kubelet 响应,直接读取日志文件。注意,如果外部系统执行轮转,日志截断为多个文件时,则 kubectl logs 只能读取组后一个文件;

系统组件日志

系统组件也有日志,但是分为两类:(1)运行在容器内的组件;(2)运行在容器外的组件;

运行在容器外的组件,例如 kubelet 及 Docker 等等:如果使用 systemd 管理,则日志写入 journald 中;如果未使用 systemd 管理,则日志写入 /var/log 中;
运行在容器内的组件,例如 kube-proxy 或 scheduler 等等:使用默认日志机制,将日志写入 /var/log 中;

同样,写入 /var/log 中的日志也需要轮转;

集群级日志的解决方案

由于 Kubernetes 没有提供集群日志解决方案,有以下集中途径解决:

使用节点级日志代理,运行在每个节点中

使用专用容器(Sidecar),收集应用程序日志

从应用程序中直接将日志写入后端日志存储

下面我们将简述各种解决方法

使用节点日志代理

以 DeamonSet 在每个节点运行 POD 实例,用于直接读取日志文件。但是这只适用于将日志写入标准错误与标准输出的容器;

常用解决方案有 Elasticsaerch+Fluentd 服务;

使用专用容器(Sidecar)

使用 Sidecar 容器(与应用容器处于相同 POD 实例的容器),有两种方式:(1)Sidecar 容器将应用日志“流入”自己的标准输出;(2)Sidecar 容器运行日志代理,收集应用程序日志;

# 流式 Sidecar 容器:
当 Sidecar 容器使用自身的标准错误与标准输出时,可以利用 kubelet 与每个节点的日志代理。Sidecar 容器可以读取文件、套接字、journald,然后将日志写入自己的标准错误、标准输出中;

这种方法可以从应用程序不同部分中分离出不同的日志流,即使有些应用程序可能不支持写入标准输入、与标准输出。日志重定向每次只需要处理很小日志,因此不会出现过渡的开销。另外由于 Sidecar 的标准输出与标准错误与 kubelet 处理,因此可以通过 kubectl logs 查看日志;

虽然 Sidecar 是额外的容器,但是它可以简单到只运行 tail 命令。Sidecar 是一种涉及模式;

另外节点级日志代理会自动处理日志,无需进一步配置。还可以配置收集代理来根据“源容器”日志类型进行解析;

尽管 CPU 使用降低,但是会增加磁盘使用量。如果你的应用程序需要将日志写入文件,那尽量写入到标准输出中,而不是使用 Sidecar 容器处理;

# 带有日志代理的 Sidecar 容器:
如果节点级日志代理无法满足需求,可以运行在 Sidecar 容器中运行日志收集代理。该代理可以经过配置,适用于特定应用程序。但是该类型的 Sidecar 会消耗更多资源,并且不能使用 kubectl logs 查看日志;

直接暴露日志

最后一种方法是将日志直接写入后端存储,这是一种日志存储方案,但是与 Kubernetes 集群的关系并不大,这里不再讨论;

Using Elasticsearch/Fluentd/Kibana (EFK) on Minikube

如何以集中的方式査看集群中所有应用的日志?

可以使用 Elasticsearch + Fluentd + Kibana,具体内容如下;

首先,为了做好准备,请确保为 Minitube 分配了足够的资源。例如,使用–cpus=4 –memory=4000,并确保 ingress 插件已被激活;

# minitube start

# minitube addons list | grep ingress

# minikube addons enable ingress

接下来,创建名为 efk-logging.yaml 的清单文件,跳过……

现在可以启动 EFK 了: kubectl create -f efk-logging.yaml

所有应用都启动以后,所有应用都启动以后,可以利用下面的用户名和密码登录 Kiana,用户名: kiana;密码: changer

打开“https://$IP/app/kiana#/discover?_g=()”,并单击 Discover 页签,就可以看到日志了;

可以使用下列命令清理或重启 EFK 栈

kubectl delete deploy/es &&

kubectl delete deploy/kiana && \

kubectl delete svc/elasticsearch && \

kubectl delete svc/kiana &&\

kubectl delete Ingress/Kibana-public && \

kubectl delete daemonset/fluent

通过 Logstash 也可以査看日志。我们在解決方案中选择使用 Fluent,是因为它是云原生计算基金会( Cloud Native Computing Foundation,CNCF)的项日且备受关注;

请注意启动 Kiana 需要花费一定的花时间,而且可能需要反复加载几次该网络应用才能完成配置;

Manoj Bhagwat 的博文“在 Kubernetes 上利用 Fluent 和 Elasticsearch 集中管理 Docker 日志
hrps://ediun.com%E2%91%A1nano/.bhaga60ocentralize-your-docker-logs-with-fluenid-and-elasticsearch-on-kubernetes42d2acOe8b6c

Kubernetes 基于 AWS 的 EFK 機
https://github.com/skillshare/kubernetes-elk

Elk-kubernetes https://github.com/kayrus/elk-kubernetes

容器日志采集

连续性 Pod 日志采集(Grafana Loki)

问题描述:随着 Pod 的重启、驱逐、调度,Pod 的名称可能会发生变化。但是这些 Pod 都属于用一个应用,我们希望能够连续显示这些 Pod 的日志(放在一起),而不是选择不同的 Pod 来查看各自的日志。

最开始,我们期望通过 app.kubernetes.io/instance 标签来归类 Pod 实例:这就需要应用程序的支持,在部署应用时添加特定标签。但是在 Pod 多实例的场景中,这些 Pod 具有相同的标签。如果仅通过 Pod Label 来标注,这将导致 Pod 的日志混合在一起。如果要进行区分,则由要引入 Pod 名称进行区分。

想到这里,我们就发现,无法将 Pod Log 连接在一起(主要原因还是 Pod 能够同时以多实例运行)。所以在查看日志时,必须选择不同的 Pod 实例。

或者,能够得到 Pod 的创建时间也可以:连续性并非我们的最终目的,我们是期望了解到 Deployment 的 Pod 随着时间的变化。

若不可行,则只能结合 Controller Name 来对 Kubernetes Event 进行分析,以此找到 Pod 的变化过程:
1)通过 Controler Name 来抓取与之相关的 Kubernetes Event 信息;
2)针对 Kubernetes Event 分析,提取 Pod Name的变换、相关时间、所在节点等等信息;
3)根据 Kubernetes Event 时间,对 Pod Name 以列表的方式在 Dashboard 中进行展示;

参考文献

1.17/Logging Architecture