2022年10月26日更新
阿里云ACK上的iLogtail组件已经更新,新版组件集成了iLogtail状态持久化配置,本文所提到的手动配置方法可以在ACK上一键升级搞定。步骤如下:
- 通过ACK控制台左侧导航,找到组件管理 -> logtail-ds。看到当前版本旁边有个小红点,说明有新版本可升级。
- 点击升级,弹出的提示框会显示最新版本。v1.0.34.1及以上版本均自带持久化参数。
需要注意的是,如果以前使用本文方法已经配置了持久化参数的同学需要注意,如果被挂载点主机路径不是/etc/kube-system-logtail-ds/checkpoint则请使用提示的“手动升级”方法进行升级,否则已配置参数会被覆盖,导致升级过程中的数据重复采集。对于此类参数被覆盖的问题后续会进一步对logtail-ds组件进行升级,以组件配置的方式提供组件自定义能力,并保持版本间升级时参数得到传承。
背景
在容器场景下,使用iLogtail DaemonSet方式对采集容器内的日志是最为常见的日志采集方案。这种方式指在每一个K8S节点上部署一个iLogtail采集Agent容器实现对该节点上所属的容器进行日志采集。由于节点上的容器都依赖一个iLogtail容器进行采集,iLogtail容器的可靠性就显得尤为重要。随着业务发展或者环境变化总有一些情况需要iLogtail容器重启:
- 容器资源配置过小或节点资源不足导致iLogtail容器被杀死或驱逐
- 需要使用新功能,对iLogtail版本进行升级
- 需要调整iLogtail配置参数
在默认的参数配置下,iLogtail容器并没有对Logtail的运行状态进行很好的持久化,因此在iLogtail重启后,因采集进度丢失必然导致节点上容器日志重复采集、采集丢失的情况发生。为了保证在正常重启的情况下数据采集不丢不重,异常重启的情况下数据不丢,本文讲详细介绍在容器场景下iLogtail应该如何配置才能做到重启时数据无异常。
状态持久化原理
保存哪些状态
要做到在iLogtail重启时数据无异常,要求iLogtail在重启前后的关键状态是一致的。这里我们首先了解一下iLogtail有哪些关键状态:
- 当前iLogtail的采集配置。iLogtail需要采集哪些文件的配置,重启后依赖本地配置恢复采集文件读取进度与采集配置的关系。
- 当前容器路径与实际采集路径的映射表。DaemonSet方式容器日志采集的原理是通过挂载宿主机的根目录来采集容器内存文件在宿主机上的对应路径,因此在容器场景下采集配置加上这份映射表才是完整的配置。
- 当前所有文件的读取进度。这一点最容易理解,重启前文件读到哪了,那么重启后文件从哪开始读。
- 没有来得及发送的缓存数据。理想情况下,iLogtail在退出前现将缓存中的数据发完然后退出,但实际情况是由于网络等原因iLogtail可能无法在较短时间内将缓存的数据发完。为了至少能够在网络异常的情况下退出并做到数据不丢失,iLogtail需要将这些缓存数据持久化到磁盘上。
- 插件状态。比如容器标准输出采集插件要记录自己当前采集的标准输出对应的文件名以及偏移量。
什么时候保存
然后,我们来了解一下这些状态记录的时机:
- iLogtail的采集配置:拉取到远程的采集配置后在本地生效时。
- 容器路径与实际采集路径的映射表:发现容器新增、删除时。
- 文件的读取进度:定期,这段时间的长短由参数check_point_dump_interval决定,默认为900秒。iLogtail在退出时也会保存文件的读取进度。
- 发送缓存数据:iLogtail退出时。
- 插件状态:插件自定义定期以及退出时。
如何恢复
这部分最后,介绍一下重启后状态恢复的过程:
- 读取本地保存的iLogtail的采集配置
- 读取容器路径与实际采集路径的映射表。
- 加载发送缓存数据并启动发送线程。
- 恢复插件状态。
- 扫描配置的采集路径并通过文件的读取进度重建文件读取器,启动文件读取线程,开始文件采集。
状态持久化参数
参数 |
类型 |
说明 |
示例 |
user_config_file_path |
String |
Logtail配置文件的保存路径,默认为进程binary所在目录,文件名为user_log_config.json。 |
"user_config_file_path" : user_log_config.json |
docker_file_cache_path |
String |
该文件记录了容器文件到宿主机文件的路径映射,默认值:/usr/local/ilogtail/docker_path_config.json。 |
"docker_file_cache_path": /usr/local/ilogtail/docker_path_config.json |
check_point_filename |
String |
Logtail的checkpoint文件的保存路径, 默认值:/tmp/logtail_check_point。 |
"check_point_filename" : /tmp/logtail_check_point |
check_point_dump_interval |
int |
Logtail更新Checkpoint文件的周期,默认值:900,单位:秒。即默认情况下每15分钟更新一次Checkpoint文件。 仅支持Logtail 1.0.19及以上版本。 |
"check_point_dump_interval" : 900 |
buffer_file_path |
String |
缓存文件存放目录。 默认值为空,即缓存文件存放于logtail安装目录/usr/local/ilogtail下。 当您设置此参数后,需手动将原目录下名为logtail_buffer_file_*的文件移动到此目录,以保证Logtail可以读取到该缓存文件并在发送后进行删除。 |
"buffer_file_path" : "" |
logtail_sys_conf_dir |
String |
Logtail系统配置目录。默认值/etc/ilogtail/。存储用户标识、机器组用户自定义标识、插件Checkpoint文件等。 |
"logtail_sys_conf_dir": "/etc/ilogtail/" |
容器场景下的状态持久化方案
在主机场景下,这些采集参数的默认值已经可以很好地保证iLogtail进程重启前后的关键状态不丢失,但在容器场景下,容器的存储生命周期默认与容器相同,保存在/usr/local/ilogtail、/tmp和/etc/ilogtail目录下的数据在容器重启后将丢失,因此需要一个方案将iLogtail的状态保存到持久化数据卷上。由于/usr/local/ilogtail/目录与iLogtail镜像中iLogtail安装目录冲突、/tmp是系统临时目录,均不适合挂载持久化数据卷,因此容器场景下的需要调整保存状态的文件路径。
这里我们选择将状态文件都保存到/etc/ilogtail/checkpoint下,保证iLogtail容器正常重启前后数据不丢不重。选择这个目录是由于插件状态文件没有直接的参数可以修改其保存位置,只能继续保留在/etc/ilogtail/checkpoint中,而为了简化部署其他文件在确保不冲突的情况下直接复用该目录。同时修改checkpoint的保存频率,在异常情况下保证数据异常控制在1分钟以内。
- 通过容器编排程序将主机的上的目录挂载到容器/etc/ilogtail/checkpoint中,实现容器存储的持久化。
- 通过修改ilogtail的状态持久化参数,将状态文件写入到/etc/ilogtail/checkpoint中。
- 通过修改ilogtail的状态持久化参数,调整checkpoint频率为60秒。
K8S环境配置
K8S环境下使用hostPath实现主机磁盘挂载。这里以Aliyun ACK中已经部署的iLogtail DaemonSet为例介绍配置过程。(K8S环境下iLogtail的部署请参考:安装iLogtail组件)
- 在集群管理页面,通过“工作负载”>“守护进程集”>“命名空间:kube-system”找到“logtail-ds”。
- 点击“查看Yaml”进行编辑,containers声明中只有logtail一个容器,在原有的env后面追加以下环境变量
name user_config_file_path value'/etc/ilogtail/checkpoint/user_log_config.json'name docker_file_cache_path value'/etc/ilogtail/checkpoint/docker_path_config.json'name check_point_filename value'/etc/ilogtail/checkpoint/logtail_check_point'name check_point_dump_interval value'60'name buffer_file_path value'/etc/ilogtail/checkpoint'
- 在原有的volumeMounts后面追加挂载
mountPath /etc/ilogtail/checkpoint name state
- 在原有的volumes后追加数据卷声明
hostPath path /lib/var/kube-system-logtail-ds/checkpoint type DirectoryOrCreate name state
- 最终的yaml应该符合如下的结构。点击“更新”生效配置。
apiVersion apps/v1 kind DaemonSet metadata name logtail-ds namespace kube-system spec template spec containersenvname user_config_file_path value'/etc/ilogtail/checkpoint/user_log_config.json'name docker_file_cache_path value'/etc/ilogtail/checkpoint/docker_path_config.json'name check_point_filename value'/etc/ilogtail/checkpoint/logtail_check_point'name check_point_dump_interval value'60'name buffer_file_path value'/etc/ilogtail/checkpoint' name logtail volumeMountsmountPath /etc/ilogtail/checkpoint name state volumeshostPath path /lib/var/kube-system-logtail-ds/checkpoint type DirectoryOrCreate name state
Docker环境配置
Docker环境下直接使用bind mounts的功能实现主机磁盘挂载。(Docker环境下iLogtail的部署请参考:采集标准Docker容器日志)
- 在命令行参数中增加挂载
-v /lib/var/docker_ilogtail/checkpoint:/etc/ilogtail/checkpoint
- 在命令行参数中增加环境变量
-euser_config_file_path=/etc/ilogtail/checkpoint/user_log_config.json -edocker_file_cache_path=/etc/ilogtail/checkpoint/docker_path_config.json -echeck_point_filename=/etc/ilogtail/checkpoint/logtail_check_point -echeck_point_dump_interval=60-ebuffer_file_path=/etc/ilogtail/checkpoint
- 最终命令应该符合如下结构
docker run -d--name docker_ilogtail -v /:/logtail_host:ro -v /var/run:/var/run -v /lib/var/docker_ilogtail/checkpoint:/etc/ilogtail/checkpoint -eALIYUN_LOGTAIL_CONFIG=/etc/ilogtail/conf/${your_region_name}/ilogtail_config.json -eALIYUN_LOGTAIL_USER_ID=${your_aliyun_user_id}-eALIYUN_LOGTAIL_USER_DEFINED_ID=${your_machine_group_user_defined_id}-euser_config_file_path=/etc/ilogtail/checkpoint/user_log_config.json -edocker_file_cache_path=/etc/ilogtail/checkpoint/docker_path_config.json -echeck_point_filename=/etc/ilogtail/checkpoint/logtail_check_point -echeck_point_dump_interval=60-ebuffer_file_path=/etc/ilogtail/checkpoint registry.${your_region_name}.aliyuncs.com/log-service/logtail
配置前后效果对比
假设我们已经配置好了采集配置,采集容器中的/root/log/1.log文件。采集容器日志的配置可参考:通过DaemonSet-控制台方式采集容器文本日志。
我们在被采集的容器中上创建一个文件并输入一些测试数据
~/log # echo 1 > 1.log; echo 2 >> 1.log; echo 3 >> 1.log
在日志服务控制台观察日志已经采集
接着我们重启logtail-ds。
等待新Pod拉起后,在被采集的容器中追加一条日志触发采集。
~/log # echo 4 >> 1.log
通过控制台查询可知,由于iLogtail状态丢失,日志重复采集了。
然后我们使用上述配置更新logtail-ds的声明,Pod会自动重启。
在业务容器中再次输入以下命令,触发的logtail-ds进行日志采集。
~/log # echo 1 > 1.log; echo 2 >> 1.log; echo 3 >> 1.log
可以到控制台确认数据采集是否成功,这里不再截图。
进入logtail-ds容器,检查/var/lib/ilogtail目录,确认状态是否保存成功。
# ls /var/lib/ilogtail/docker_path_config.json logtail_check_point user_log_config.json
可以看到关键的状态文件已经保存到配置的目录下了。
接着我们再次重启logtail-ds。
等待新Pod拉起后,在被采集的容器中追加一条日志触发采集。
~/log # echo 4 >> 1.log
通过控制台查询可知,iLogtail状态持久化生效,采集到的数据完全正常。
总结
追求数据采集准确是每一个从业人员的目标,K8S和Docker容器在给予开发者便利的同时也对日志采集的稳定性提出了新的的挑战。采集容器重启是容器场景下必然会遇到的一种可能导致数据采集异常的场景,本文简要讲解了iLogtail的状态持久化原理和容器场景状态持久化方案,并详细描述了在K8S和Docker环境下如何配置iLogtail参数和容器参数来解决这种场景下的数据采集的稳定性问题。
有些读者可能会疑惑,既然这样进行配置那么好,为什么在阿里云自己的ACK上安装iLogtail日志采集组件没有默认进行这样的配置呢?这是一个很好的建议,在后续的iLogtail组件升级中,我们将会把这种设置变成默认参数,给大家更稳定的日志采集体验。(2022年10月26日更新:组件已完成升级)