logging in kubernetes
background
docker
docker的日志输出可以通过指定driver输出到不同的位置,常用的是journald
和json-file
。 使用journald
日志输出可能受限于jourand的throttle作用, 因为journald
是node agent, 负责该node上全部容器的日志收集, 当一个用户写入大量日志,就会进行rate limit, 这样导致其他用户也会丢失日志, 并且无法进行单个用户rate-limit 的设置; 而使用json-file
log driver, docker是将log以json 格式保存到宿主机的目录之上, 默认是/var/lib/docker/containers/${docker-uid}
, 可以通过log-opt
参数配置log rotate文件大小和数量, 避免占用太多磁盘空间。 个人比较推荐使用json-file
log driver, 不会丢日志, 耦合性较低,日志先格式化输出到磁盘上, 然后后面怎么处理都比较方便。 所有的log driver都需要经过docker daemon, 然后分发到不同的driver里, 这样就会有单点问题,分发和处理(序列化日志等)会有性能问题, 耗费机器资源, 严重情况下会导致整个docker daemon卡死。所以对于这种log较多的应用建议直接输出到文件中,而不是STDOUT, 避免影响docker daemon。
kubernetes
如果docker使用json-file
log driver, kubelet会为所有的容器日志创建一个软链接到/var/log/pods
目录下, 包含各个pods所有的日志,文件名称由pod name, namespaces, container name, container Id等组成。kubernetes官方文档Logging Architecture介绍了三种日志收集方式, 并推荐使用daemonset部署log agent 方式收集, 这种方式部署简单, 节约资源, 但是灵活性不够, 无法针对每个pod做一些定制化的需求, 同时因为是一个node上的全局agent, 需要考虑所收集的多个pod的日志隔离, 避免相关影响。 在生产环境中, 我们可以统一由node agent来收集日志, 对于比较特殊的需求则使用sidecar的方式进行收集。
方案实现
日志收集的各种node agent的实现不尽相同, 有些agent是通过docker api获取容器日志的,例如开源的logspout
,这种agent适用这种场景比较单一,如果我们还需要收集写到磁盘上的日志, logspout
就无法胜任了。我们知道容器如果使用json-file
这种log driver, 日志最终会保存在宿主机上的特定目录中的文件里, 所以我们可以归约以上所有的情况都为文件日志收集, 使用类似tail -f
功能的程序来实现, 目前这样的开源工具很多, 例如fluentd
, filebeat
等, 除了基本的tailf
功能外, log agent还需要考虑那些功能?
功能
- label添加: 自动添加container name, containerID, node name的label,除了基本的contianer信息外,还应该支持用户自定义的label, 方便收集索引和数据处理。
- 支持多种数据来源: 容器环境下的日志主要分为: 宿主机文件, 容器文件, 容器stdout,这些类型都可以归约为文件,因为容器的stdout也可以先落磁盘,然后由agent收集。
- 自动发现容器创建、删除: 如果场景比较单一的话,比如只收集固定目录的文件,就可以统一使用文件tailf, 自动监视指定目录的变化即可。 如果需要一些高级的功能,例如目录多变,数据来源较多,就需要动态监听docker daemon事件, 并从container的label或者env中解析出动态传递的变量进行定制化。如果某些程序不支持监听docker daemon的事件的话,可以写一个对应的reloader,由reloader监听docker事件生成配置供agent使用。
- 数据处理: 过滤,路由到不同的target,例如输出到kafaka, es等
上述功能对于不同的业务场景可能有不同的需求, 很多现在开源的工具都提供一种插件的方式来扩展功能,以fluend来说,提出Unified Logging Layer,通过各个插件进行日志路由和处理,目前基本插件都能找到开源的,可谓是一个日志收集生态。
性能
除了满足基本的功能之外, 就需要考虑性能问题了:
- 多租户隔离: 容器环境下, 可能多个用户共享一台物理机, 如果一个容器写日志速率较快可能会影响其他用户正常操作, 因为一个node agent的收集速率总会有上限,并且在公有云环境下, 日志收集作为资源提供出去,是需要计费的, 此时就需要考虑限速, 容量调度, 优先级抢占等问题。该部分可以参见:Logtail技术分享(二) : 多租户隔离技术+双十一实战效果
- 性能: 日志速率的速率越快, 单台node收集的日志越多, 可以满足更加丰富的业务场景。
- 资源消耗: node agent往往是需要部署集群中所有的node上面, 所以影响面较广, 如果我们能显著降低资源消耗, 相当于省钱。
- 稳定可靠: 自动降级,就算是异常情况, 程序Bug也不能影响用户, 此时就需要通过cgroup等技术进行容量的限制。 还有就是不能多收集日志或者丢失日志。
日志收集agent原理
这部分可以阅读下面链接的阿里云团队分享的文章, 这里highlight一下:
- 使用polling + inotify发现日志文件
- 使用dev+inode+signatrue标识一个文件
- 通过点位文件保证可靠性, 通过fsync+rename保证点位文件的可靠性
- 通过保持文件打开状态来保证文件采集完整
日志采集中的关键技术分析
Logtail技术分享(一) : Polling + Inotify 组合下的日志保序采集方案
Logtail技术分享(二) : 多租户隔离技术+双十一实战效果
More topic
Logging Architecture
Cluster-level Logging in Kubernetes with Fluentd
阿里PB级Kubernetes日志平台建设实践