loggie-io / loggie

A lightweight, cloud-native data transfer agent and aggregator
https://loggie-io.github.io/docs-en/
Apache License 2.0
1.26k stars 168 forks source link

k8s 采集 docker 控制台日志,日志会有中断的情况,并且不会恢复 #526

Closed VanLiuZhi closed 1 year ago

VanLiuZhi commented 1 year ago

环境: k8s: v1.19.6 docker: v18, v20 都有 loggie:v1.4.0

遇到一个问题求助一下:

采集日志,过一段时间后,某些pod的日志就采集中断了(从es那边看,就一直没有数据上报,相当于停止了)。我部署了监控,从grafan看,经过我多次测试,大概总结了一下原因,监控里面,只要是 采集进度超过 100% 的,日志就会停止

image

会出现这种情况,我认为是我们docker容器做了配置,限制了日志文件大小 "log-opts": {"max-size":"1024m"},这样容器日志超过1g的,json文件就被清空了,此时 loggie 的 size,就很小了,而文件的 offset 没有被重置,所以算出来的采集进度也就是如图所示的情况

此时,如果我重启节点的 loggie,采集恢复,我看到有这样的日志,源码这个位置 source/file/watch.go func (w *Watcher) eventBus(e jobEvent)

// check whether the existAckOffset is larger than the file size
        if existAckOffset > fileSize+int64(len(job.GetEncodeLineEnd())) {
            log.Warn("new job(jobUid:%s) fileName(%s) existRegistry(%+v) ackOffset is larger than file size(%d).is inode repeat?", job.Uid(), filename, existRegistry, fileSize)
            // file was truncated,start from the beginning
            if job.task.config.RereadTruncated {
                existAckOffset = 0
                existLineNumber = 0
            }
        }

这段代码应该是重启的时候,会执行,它重置了 existAckOffset ,所以又能采集了。

小结一下:

  1. 解决办法,就是要能监控到容器json文件清空的时候,触发一下 existAckOffset = 0 existLineNumber = 0,但是我不知道这个逻辑是加到源码哪个位置才是正确的,或者可以告知一下大概应该怎么做,我去验证一下。
  2. 我不知道loggie是否考虑了docker配置 "log-opts": {"max-size":"1024m"} 的情况,如果考虑了那这应该是个BUG了。我们之所以设置这个参数,也是因为好多服务很长时间不重新发布,导致节点磁盘占用太大,因为日志都采集上es了,所以容器控制台日志就限制了大小
ethfoo commented 1 year ago

感觉可能是因为采集进度offset是使用inode+deviceId作为唯一标识来记录的,如果docker的这个日志发生rotate之后,存在inode复用的情况,导致文件的offset大于rotate后文件的size,这个时候就没办法去采集了,我具体验证一下看看

VanLiuZhi commented 1 year ago

@ethfoo 明白你的意思了,我感觉docker "log-opts": {"max-size":"1024m"} 配置下,只保留一个文件,文件size到上限的时候,清空文件内容,此时再看文件大小已经没有1G了,我验证一下多文件的rotate,能否绕过这种情况 "log-opts": { "max-size": "10m", "max-file": "5" }

VanLiuZhi commented 1 year ago

"log-opts": { "max-size": "10m", "max-file": "5" }

可以,不会中断采集,那情况就比较清晰了,因为设置多文件的情况下,官方文档的说法,当日志文件 xxx-json 满了之后,把这个文件重命名为 xxx-json.1, 然后新的日志再写入到同名创建的新文件 xxx-json 中。只是线上要动这个docker配置,确实很麻烦,log-opts的配置要重建容器才生效

ethfoo commented 1 year ago

我们内部讨论一下,是否ack offset大于size这种情况下,直接重新采集;本质上这种是需要支持copytruncate的日志轮转策略。

VanLiuZhi commented 1 year ago

create 和 copytruncate 2种策略吧,发现这种日志采集要兼容各种 runtime 还是挺复杂的

VanLiuZhi commented 1 year ago

@ethfoo 有没有什么临时修补方案,我不太确定在源码的哪个时间点改比较合适

ixiaoyi93 commented 1 year ago

这个问题解决了吗?我测试过程中也发现,采集 pod 的日志也会不采集。重启 loggie 就好了,并且如果日志文件创建新文件之后,发现不了新文件。

ethfoo commented 1 year ago

这个问题解决了吗?我测试过程中也发现,采集 pod 的日志也会不采集。重启 loggie 就好了,并且如果日志文件创建新文件之后,发现不了新文件。

你这个是另外那个issues提到的使用containerd无挂载模式导致的问题吧?和copytruncate无关?copytruncate模式已经在v1.5.0-rc.0版本支持了

VanLiuZhi commented 1 year ago

我看是解决了,升级 v1.5.0-rc.0 版本后没有采集中断的情况了