做者 | 元乙 阿里云存储服务技术专家html
导读:近年来,愈来愈多的同窗咨询如何为 Kubernetes 构建一个日志系统,或者是来求助在此过程当中遇到一系列问题如何解决,授人以鱼不如授人以渔,因而做者想把这些年积累的经验以文章的形式发出来,让看到文章的同窗少走弯路。K8s 日志系列文章内容偏向落地实操以及经验分享,且内容会随着技术的迭代而不按期更新,本文为该系列文章的第 3 篇。python
第一篇:《6 个 K8s 日志系统建设中的典型问题,你遇到过几个?》nginx
第二篇:《一文看懂 K8s 日志系统设计和实践》git
在上一篇文章《一文看懂 K8s 日志系统设计和实践》中,主要和你们介绍从全局维度考虑如何去构建 K8s 中的日志系统,本文咱们将从实践角度出发来一步步构建 K8s 中的日志监控体系。程序员
构建日志系统的第一步是如何去产生这些日志,而这也每每是最繁杂最困难的一步。github
2009 年阿里云春节上班第一天,在北京一间连暖气都没有的办公室里,一帮工程师一边口呼白气,一边敲出了“飞天”的第一行代码。“飞天”做为阿里云的核心技术平台,其英文名 Apsara——来自吴哥王朝的阿仆萨罗飞天仙女的名字。docker
阿里云飞天系统的第一行代码就是为了编写一个日志系统,而如今 apsara logging 的日志库应用在飞天全部的系统中,包括盘古、女娲、伏羲、洛神...后端
一般日志最基础的做用是记录程序的运行轨迹,在此之上会衍生出很是多的功能,例如线上监控、告警、运营分析、安全分析等等(详情能够参见第一篇文章《6 个 K8s 日志系统建设中的典型问题,你遇到过几个?》,这些功能反过来也对日志具有必定的要求,咱们须要尽量的将日志规范化,以减小收集、解析、分析的代价。缓存
在 Kubernetes 中,环境的动态性很强,日志基本上都是易失的,所以须要实时将日志采集到中心的存储中,为了配合日志采集,对于日志的输出、采集会有更多的要求。安全
下述咱们列举了 Kubernetes 中,日志输出的常见注意事项(其中标记 (*)的是 Kubernetes 中特有的项目):
日志等级是用来区分日志对应事件严重程度的说明,这是全部日志中必须具有的一个选项。一般日志会分为 6 个不一样的等级:
做为程序员,必定要合理设置日志等级,我的在开发过程当中总结了如下几点经验:
一般在没有约束的状况下,程序员的发挥天马行空,各类日志内容都会出现,这些只有开发本身才能看懂的日志很难进行分析和告警。所以咱们须要一个日志顶向下的规范来约束项目中的开发人员,让全部的日志看起来是一我的打印的并且是易于分析的。
日志中一般必备的字段有:Time、Level、Location。对于特定模块/流程/业务,还须要有一些 Common 的字段,例如:
日志的字段规约最好由运维平台/中间件平台自顶向下推进,约束每一个模块/流程的程序员按照规定打印日志。
一般咱们建议使用 KeyValue 对形式的日志格式,好比咱们阿里的飞天日志库采用的就是这种形式:
[2019-12-30 21:45:30.611992] [WARNING] [958] [block_writer.cpp:671] path:pangu://localcluster/index/3/prom/7/1577711464522767696_0_1577711517 min_time:1577712000000000 max_time:1577715600000000 normal_count:27595 config:prom start_line:57315569 end_line:57343195 latency(ms):42 type:AddBlock
KeyValue 对的日志能够彻底自解析且易于理解,同时便于日志采集时自动解析。
另外推荐的是 JSON 日志格式,支持以 JSON 格式输出的日志库不少,并且大部分的日志采集 Agent 都支持 JSON 格式的日志收集。
{"addr":"tcp://0.0.0.0:10010","caller":"main.go:98","err":"listen tcp: address tcp://0.0.0.0:10010: too many colons in address","level":"error","msg":"Failed to listen","ts":"2019-03-08T10:02:47.469421Z"}
注意:绝大部分场景不建议使用非可读的日志格式(例如 ProtoBuf、Binlog 等)。
非必要状况下,尽可能不要一条日志输出成多行,这种对于采集、解析和索引的代价都比较高。
日志的输出量直接影响到磁盘使用以及对于应用的性能消耗,日志太多不利于查看、采集、分析;日志太少不利于监控,同时在出现问题的时候没办法调查。
通常线上应用需合理控制日志的数据量:
建议一个应用不一样类型的日志输出到不一样的目标(文件),这样便于分类采集、查看和监控。例如:
日志做为业务系统的辅助模块,必定不能影响到业务正常的工做,所以日志模块的性能消耗须要单独额外注意,通常在选择/开发日志库时,须要对日志库进行性能测试,确保正常状况下日志的性能消耗不超过总体 CPU 占用的 5%。
注意:必定要确保日志打印是异步的,不能阻塞业务系统运行。
开源的日志库很是多,基本每一个语言都有数十种,选择一个符合公司/业务需求的日志库须要精挑细选,有一个简单的指导原则是尽量使用比较流行的日志库的稳定版本,入坑的概率要小一点。例如:
在虚拟机/物理机的场景中,绝大部分应用都以文件的形式输出日志(只有一些系统应用输出到 syslog/journal);而在容器场景中,多了一个标准输出的方式,应用把日志打到 stdout 或 stderr 上,日志会自动进入到 docker 的日志模块,能够经过 docker logs 或 kubectl logs 直接查看。
容器的标准输出只适应于比较单一的应用,例如 K8s 中的一些系统组件,线上的服务类应用一般都会涉及到多个层级(中间件)、和各类服务交互,通常日志都会分为好几类,若是所有打印到容器的标准输出,很难区分处理。<br />同时容器标准输出对于 DockerEngine 的性能消耗特别大,实测 10W/s 的日志量会额外占用 DockerEngine 1 个核心的 CPU(单核 100%)。
在 Kubernetes 中,还能够将日志库直接对接日志系统,日志打印的时候不落盘而直接传输到日志系统后端。这种使用方式免去了日志落盘、Agent 采集的过程,总体性能会高不少。
这种方式咱们通常只建议日志量极大的场景使用,普通状况下仍是直接落盘,相比直接发送到后端的方式,落盘增长了一层文件缓存,在网络失败的状况下还能缓存必定的数据,在日志系统不可用的状况下咱们的研发运维同窗能够直接查看文件的日志,提升总体的可靠性。
Kubernetes 提供了多种存储方式,通常在云上,都会提供本地存储、远程文件存储、对象存储等方式。因为日志写入的 QPS 很高,和应用也直接相关,若是使用远程类型的存储,会额外多 2-3 次网络通讯开销。咱们通常建议使用本地存储的方式,可使用 HostVolume 或者 EmptyDir 的方式,这样对于写入和采集的性能影响会尽量的小。
相比传统虚拟机/物理机的场景,Kubernetes 对于节点、应用层提供了强大的调度、容错、缩/扩容能力,咱们经过 Kubernetes 很容易就能让应用得到高可靠运行、极致弹性。这些优点带来的一个现象是:节点动态建立/删除、容器动态建立/删除,这样日志也会随时销毁,没办法保证日志的存储周期可以知足 DevOps、审计等相关的需求。
在动态的环境下实现日志的长期存储只能经过中心化的日志存储来实现,经过实时的日志采集方式,将各个节点、各个容器的日志在秒级内采集到日志中心系统上,即便节点/容器挂掉也可以经过日志还原当时的现场。
日志输出是日志系统建设中很是重要的环节,公司/产品线必定要遵循一个统一的日志规范,这样才能保证后续日志采集、分析、监控、可视化可以顺利进行。
后面的章节会介绍如何为 Kubernetes 规划日志采集和存储的最佳实践,敬请期待。
“阿里巴巴云原生关注微服务、Serverless、容器、Service Mesh 等技术领域、聚焦云原生流行技术趋势、云原生大规模的落地实践,作最懂云原生开发者的技术圈。”