页面加载中,请稍候
来源:开源Linux发布时间:2023-05-09974浏览
询问 AI

动态迁移:在 Kubernetes 集群中经常存在 Pod 主动或者被动的迁移,频繁的销毁、创建,我们无法和传统的方式一样人为的给每个服务下发日志采集配置。
日志存储方式多样性:容器的日志存储方式有很多不同的类型,例如 stdout、hostPath、emptyDir、pv 等。
Kubernetes 元信息:由于日志数据采集后会被集中存储,所以查询日志时,需要根据namespace、pod、container、node,甚至包括容器的环境变量、label 等维度来检索、过滤,此时要求Agent感知并默认在日志里注入这些元信息。
以上都是有别于传统日志采集配置方式的需求和痛点,究其原因,还是因为传统的方式脱离了Kubernetes,无法感知Kubernetes,无法和Kubernetes集成。
为了采集容器日志,我们先来看一下市面上一般都有哪些解决方案。
采集容器日志,Agent有两种部署方式:
DaemonSet:每个节点部署一个Agent
Sidecar:每个Pod增加一个Sidecar容器,运行日志Agent
两种部署方式的优劣都显而易见:
Tip:正常情况下,优先使用 DaemonSet 的方式采集日志,如果单个Pod日志量特别大,超过一般 Agent 发送吞吐量,可以单独对该 Pod 使用 Sidecar 的方式采集日志。
DaemonSet + Stdout
如果使用容器运行时的是docker,正常情况下我们可以在节点的docker路径中找到容器的stdout的日志,默认为/var/lib/docker/containers/{containerId}/{containerId}-json.log。在Kubernetes 1.14版本之前,kubelet会在/var/log/pods///.log建立一个软链接到stdout文件中。类似如下所示:root@master0:/var/log/pods# tree .|-- 6687e53201c01e3fad31e7d72fbb92a6| `-- kube-apiserver| |-- 865.log -> /var/lib/docker/containers/3a35ae0a1d0b26455fbd9b267cd9d6ac3fbd3f0b12ee03b4b22b80dc5a1cde03/3a35ae0a1d0b26455fbd9b267cd9d6ac3fbd3f0b12ee03b4b22b80dc5a1cde03-json.log| `-- 866.log -> /var/lib/docker/containers/15a6924f14fcbf15dd37d1c185c5b95154fa2c5f3de9513204b1066bbe474662/15a6924f14fcbf15dd37d1c185c5b95154fa2c5f3de9513204b1066bbe474662-json.log|-- a1083c6d-3b12-11ea-9af1-fa163e28f309| `-- kube-proxy| |-- 3.log -> /var/lib/docker/containers/4b63b5a90a8f9ca6b6f20b49b5ab2564f92df21a5590f46de2a46b031e55c80e/4b63b5a90a8f9ca6b6f20b49b5ab2564f92df21a5590f46de2a46b031e55c80e-json.log| `-- 4.log -> /var/lib/docker/containers/fc7c315d33935887ca3479a38cfca4cca66fad782b8a120c548ad0b9f0ff7207/fc7c315d33935887ca3479a38cfca4cca66fad782b8a120c548ad0b9f0ff7207-json.log在Kubernetes 1.14版本之后,改成了/var/log/pods/<namespace>_<pod_name>_<pod_id>/<container_name>/<num>.log的形式。
root@master-0:/var/log/pods# tree .|-- kube-system_kube-apiserver-kind-control-plane_bd1c21fe1f0ef615e0b5e41299f1be61| `-- kube-apiserver| `-- 0.log|-- kube-system_kube-proxy-gcrfq_f07260b8-6055-4c19-9491-4a825579528f| `-- kube-proxy| `-- 0.log`-- loggie_loggie-csd4g_f1cc32e9-1002-4e64-bd58-fc6094394e06 `-- loggie `-- 0.log所以,对于 Agent 采集标准输出日志来说,也就是采集节点上的这些日志文件。一种简单粗暴的采集方式是,使用DaemonSet部署日志Agent,挂载/var/log/pods目录,Agent的配置文件使用类似/var/log/pod.log去通配日志文件,采集节点上所有的容器标准输出。
Tip:这也是我最初的解决方案,想到这就脸红!

(1) emtpyDir
emtpyDir 的生命周期跟随Pod,Pod销毁后其中存储的日志也会消失。
优点:使用简单,不同Pod都使用自己的emtpyDir,有一定的隔离性。
缺点:日志如果采集不及时,在Pod消耗后,存在丢失的可能性。
使用 emptyDir 挂载的日志文件,一般在节点的路径如下:/var/lib/kubelet/pods/${pod.UID}/volumes/kubernetes.io~empty-dir/${volumeName}
(2) hostPath
生命周期和Pod无关,Pod迁移或者销毁,日志文件还保留在现有磁盘上。
为了解决隔离性,避免多个Pod打印日志到相同的路径和文件中,我们需要使用 subPathExpr 字段从 Downward API 环境变量构造 subPath 目录名。该 VolumeSubpathEnvExpansion 功能从 Kubernetes1.15 开始默认开启,在1.17 GA。
(3) Pv
Pv的访问模式包括:
ReadWriteOnce(RWO):读写权限,并且只能被单个Node挂载。
ReadOnlyMany(ROX):只读权限,允许被多个Node挂载。
ReadWriteMany(RWX):读写权限,允许被多个Node挂载。
对于大部分的业务来说,都是Deployment无状态部署,需要挂载同一个Pv共享;对于一些中间件等有状态服务,一般会使用StatefulSet部署,每个Pod会使用独立的Pv。

另外,鉴于一些Agent对采集docker stdout有一定的支持,所以还存在一些使用上变种,比如利用webhook注入一个sidecar,读取Pod里的日志文件,转换成sidecar的stdout,然后采集sidecar的stdout日志,这里不再详述。
10T 技术资源大放送!包括但不限于:Linux、虚拟化、容器、云计算、网络、Python、Go 等。在开源Linux公众号内回复10T,即可免费获取!
新闻来源:开源Linux,文中所述为作者独立观点,不代表icspec立场。更多精彩资讯请下载icspec App。如对本稿件有异议,请联系微信客服specltkj。
暂无评论哦,快来评论一下吧!