前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >k8s 日志采集最佳实践

k8s 日志采集最佳实践

原创
作者头像
iginkgo18
修改2021-11-09 15:50:58
2.3K0
修改2021-11-09 15:50:58
举报
文章被收录于专栏:devops_k8s

1 . 为何需要日志系统

通常一个线上问题的定位流程是: 通过 Metric 发现问题, 根据 Trace 定位到问题模块,根据模块具体的日志定位问题原因。在日志中包括了错误、关键变量、代码运行路径等信息,这些是问题排查的核心,因此日志永远是线上问题排查的必经路径;

大致分为 3 个主要阶段:

1 . 在单机时代,几乎所有的应用都是单机部署,当服务压力增大时,只能切换更高规格的 IBM 小型机。日志作为应用系统的一部分,主要用作程序 Debug,通常结合 grep 等 Linux 常见的文本命令进行分析;

2 . 随着单机系统成为制约业务发展的瓶颈,为了真正的 Scale out,飞天项目启动:2013 年飞天 5K 项目正式上线。在这个阶段各个业务开始了分布式改造,服务之间的调用也从本地变为分布式,为了更好的管理、调试、分析分布式应用,我们开发了 Trace(分布式链路追踪)系统、各式各样的监控系统,这些系统的统一特点是将所有的日志(包括 Metric 等)进行集中化的存储;

3 . 为了支持更快的开发、迭代效率,近年来我们开始了容器化改造,并开始了拥抱 Kubernetes 生态、业务全量上云、Serverless 等工作。在这阶段,日志无论从规模、种类都呈现爆炸式的增长,对日志进行数字化、智能化分析的需求也越来越高,因此统一的日志平台应运而生。

2 . 可观察性的终极解读

在 CNCF 中,可观察性的主要作用是问题的诊断,上升到公司整体层面,可观察性(Observability)不仅仅包括 DevOps 领域,还包括业务、运营、BI、审计、安全等领域,可观察性的最终的目标是实现公司各个方面的数字化、智能化。

几乎所有的业务角色都会涉及到各式各样的日志数据,为了支撑各类应用场景,我们开发了非常多的工具和功能:日志实时分析、链路追踪、监控、数据加工、流计算、离线计算、BI 系统、审计系统等等。日志系统主要专注于数据的实时采集、清洗、智能分析与监控以及对接各类各样的流计算、离线系统。

3 . 日志系统建设难点

单纯日志系统的解决方案非常多,相对也比较成熟,这里就不再去赘述,我们此次只针对 Kubernetes 上的日志系统建设而论。Kubernetes 上的日志方案相比我们之前基于物理机、虚拟机场景的日志方案有很大不同,例如:

1 . 日志的形式变得更加复杂,不仅有物理机/虚拟机上的日志,还有容器的标准输出、容器内的文件、容器事件、Kubernetes 事件等等信息需要采集;

2 . 环境的动态性变强,在 Kubernetes 中,机器的宕机、下线、上线、Pod销毁、扩容/缩容等都是常态,这种情况下日志的存在是瞬时的(例如如果 Pod 销毁后该 Pod 日志就不可见了),所以日志数据必须实时采集到服务端。同时还需要保证日志的采集能够适应这种动态性极强的场景;

3 . 日志的种类变多,上图是一个典型的 Kubernetes 架构,一个请求从客户端需要经过 CDN、Ingress、Service Mesh、Pod 等多个组件,涉及多种基础设施,其中的日志种类增加了很多,例如 K8s 各种系统组件日志、审计日志、ServiceMesh 日志、Ingress 等;

4 . 业务架构变化,现在越来越多的公司开始在 Kubernetes 上落地微服务架构,在微服务体系中,服务的开发更加复杂,服务之间的依赖以及服务底层产品的依赖越来越多,这时的问题排查将更加复杂,如果关联各个维度的日志将是一个困难的问题;

5 . 日志方案集成困难,通常我们都会在 Kubernetes 上搭建一套 CICD 系统,这套 CICD 系统需要尽可能的自动化的完成业务的集成和部署,其中日志的采集、存储、清洗等也需要集成到这套系统中,并和 K8s 的声明式部署方式尽可能一致。而现有的日志系统通常都是较独立的系统,集成到 CICD 中代价极大;

6 . 日志规模问题,通常在系统初期的时候我们会选择自建开源的日志系统,这种方式在测试验证阶段或公司发展初期是没有什么问题的,但当业务逐渐增长,日志量增长到一定规模时,自建的开源系统很多时候都会遇到各种各样的问题,例如租户隔离、查询延迟、数据可靠性、系统可用性等。日志系统虽不是 IT 中最核心的路径,但一旦关键时刻出现这些问题都将是非常可怕的影响,例如大促的时候出现紧急问题,排查时多个工程师并发查询把日志系统打爆,导致故障恢复时间变长,大促收到影响。

4 k8s 日志收集注意

4.1 收集方式

在 Kubernetes 中,日志采集相比传统虚拟机、物理机方式要复杂很多,最根本的原因是 Kubernetes 把底层异常屏蔽,提供更加细粒度的资源调度,向上提供稳定、动态的环境。因此日志采集面对的是更加丰富、动态的环境,需要考虑的点也更加的多;##

例如:

Aport的 Job 类应用,从启动到停止只有几秒的时间,如何保证日志采集的实时性能够跟上而且数据不丢?

K8s 一般推荐使用大规格节点,每个节点可以运行 10-100+ 的容器,如何在资源消耗尽可能低的情况下采集 100+ 的容器?

在 K8s 中,应用都以 yaml 的方式部署,而日志采集还是以手工的配置文件形式为主,如何能够让日志采集以 K8s 的方式进行部署?

Kubernetes

传统方式

日志种类

文件、stdout、宿主机文件、journal

文件,journalfD

日志源

业务容器,系统组件,宿主机

业务,宿主机

采集方式

Agent(Sidecar、DaemonSet)、直写(DockerEngine、业务)

Agent、直写

单机应用数

10-100

1-10

应用动态性

节点动态性

采集部署方式

手动、Yaml

手动、自定义

4.2 收集日志规范

1 . 日志等级要规范

等级说明debug调试信息info用来收集关注的信息warn警告信息error错误信息;

好多开发工程师记录日志总是喜欢用info级别来记录日志,一般的组件默认级别都是info,所有info默认都是会被记录的,而debug信息发布后,是不会被记录的。这是一种偷懒的做法,但这也是很普遍的做法。正确的方式应该根据日志本身的特性去设置日志的级别,其实规范的日志级别是非常重要的:

  • 正确的级别便于运维。便于统一调整系统日志级别,如特殊情况可以只记录error错误
  • 没有正确的级别,对后期日志分析和处理是留下很大的隐患。error是需要去关注,并且处理掉的问题。info是普通日志的记录,大部分时候是无需关注的。

2 . error日志内容一定要详实,info日志要简洁易懂

运营过大型系统的人都知道,除了数据库存储外,日志、图片、附件是存储的三大债主,他们是会占用非常非常大的空间,所有记录info的日志,要简洁易懂,避免空间浪费。 而对于error级别的错误,记录一定要详实,因为error的所有问题,是后期都要去解决的。

  • 请求的地址
  • 请求的参数
  • 请求的ip
  • 请求的用户
  • error具体信息
  • 输出的内容
  • ......

为了能很好的反馈当时error产生场景,以上的这些内容都应该被记录,而且越详细越好。

3 . error日志一定是全局统一收集的

前文说过,error的日志,不仅是我们需要关注的,还是我需要解决掉的问题,所有error日志非常重要。错误日志的收集,必须是全局统一收集的,AOP是你最好的伙伴,如果你发现你的errorr日志收集是在每个类中,到处是

代码语言:javascript
复制
try
{
......
}
catch()
{
    log.error("......")
}

这个一定要避免,不管你用那种语言,错误的处理,都是可以通过全局进行统一的处理,错误日志也要通过全局统一收集。

4.3 管理日志

每个开发人员对日志的收集,都是非常熟悉的,基本都是将日志按照日期的方式进行保存,日常使用日志的时候,也是有一些要求:

1 . 单个文件大小要控制

因为大家都是通过日期方式保存的,但是因为有的人不重视日志,经常会看到有的系统单个日志文件上百M,有的甚至是几G,而实际大家处理问题关注的都是最近的日志,所以控制单个日志文件的大小,对日志的性能以及后期的运维都是非常便利的。

2 . 日志要便于浏览

日志文件小才便于浏览,日志最好能通过网址直接访问到,而不需要一波三折登录服务器,花10分钟下载下来,再来分析;

3 . 日志要定期清理

日志是非常占用存储的空间,日志太大对存储的性能也有一定的影响,所有日志要定期进行清理。

  • 空间充足可以保留半年
  • 空间不足最少也要保留3个月

当然,这个也不是一定的,根据每个系统的情况去制定清理计划就可以了。

如果大家是小型网站,一个系统一台服务器,日志管理就简单了。如果系统是做了高可用,后端用了均衡负载,那么,日志存在当前服务器是不太明智的做法,日志一定要统一存储,因为均衡负载随时都可能会切换服务器,当出现故障,你需要去找日志究竟存在哪个服务器,也是件很浪费时间的事情。日志文件也可以通过:

  • 共享虚拟目录来存储
  • 定时进行文件同步来存储

日志存储也是对性能有一定影响的,文件同步虽然看起来麻烦一定,但是比共享虚拟目录的方式来说,性能会好,推荐使用这种方式。

说到日志的同步,就不得不提Logstash这个日志组件。Logstash是现在应用最广的日志收集组件,基于java平台。其实很多java平台的组件,是不用去了解java开发的,只要简单的配置就能使用。

Logstash支持文件同步,也可以结合rsyslog进行文件同步,当然,也支持通过tcp协议,与第三方对接,好伙伴当然是Elasticsearch。Elasticsearch下文也会做简单的介绍。

5 采集方式: 主动 or 被动

日志的采集方式分为被动采集和主动推送两种,在 K8s 中,被动采集一般分为 Sidecar 和 DaemonSet 两种方式,主动推送有 DockerEngine 推送和业务直写两种方式:

  • DockerEngine 本身具有 LogDriver 功能,可通过配置不同的 LogDriver 将容器的 stdout 通过 DockerEngine 写入到远端存储,以此达到日志采集的目的。这种方式的可定制化、灵活性、资源隔离性都很低,一般不建议在生产环境中使用;
  • 业务直写是在应用中集成日志采集的 SDK,通过 SDK 直接将日志发送到服务端。这种方式省去了落盘采集的逻辑,也不需要额外部署 Agent,对于系统的资源消耗最低,但由于业务和日志 SDK 强绑定,整体灵活性很低,一般只有日志量极大的场景中使用;
  • DaemonSet 方式在每个 node 节点上只运行一个日志 agent,采集这个节点上所有的日志。DaemonSet 相对资源占用要小很多,但扩展性、租户隔离性受限,比较适用于功能单一或业务不是很多的集群;
  • Sidecar 方式为每个 POD 单独部署日志 agent,这个 agent 只负责一个业务应用的日志采集。Sidecar 相对资源占用较多,但灵活性以及多租户隔离性较强,建议大型的 K8s 集群或作为 PaaS 平台为多个业务方服务的集群使用该方式;

总结下来:

1 . DockerEngine直写不推荐;

2 . 业务直写推荐在日志量极大场景中使用;

3 . DaemonSet一般在中小型集群中使用;

4 . Sidecar推荐在超大型的集群中使用;

详细各种采集方式对比如下:

DockerEngine

业务直写

DaemonSet方式

Sidecar方式

采集日志类型

标准输出

业务日志

标准输出+部分文件

文件

部署运维

低,原生支持

低,只需维护好配置文件即可

一般,需维护DaemonSet

较高,每个需要采集日志的POD都需要部署sidecar容器

日志分类存储

无法实现

业务独立配置

一般,可通过容器/路径等映射

每个POD可单独配置,灵活性高

多租户隔离

弱,日志直写会和业务逻辑竞争资源

一般,只能通过配置间隔离

强,通过容器进行隔离,可单独分配资源

支持集群规模

本地存储无限制,若使用syslog、fluentd会有单点限制

无限制

取决于配置数

无限制

资源占用

低,docker

engine提供

整体最低,省去采集开销

较低,每个节点运行一个容器

较高,每个POD运行一个容器

查询便捷性

低,只能grep原始日志

高,可根据业务特点进行定制

较高,可进行自定义的查询、统计

高,可根据业务特点进行定制

可定制性

高,可自由扩展

高,每个POD单独配置

耦合度

高,与DockerEngine强绑定,修改需要重启DockerEngine

高,采集模块修改/升级需要重新发布业务

低,Agent可独立升级

一般,默认采集Agent升级对应Sidecar业务也会重启(有一些扩展包可以支持Sidecar热升级)

适用场景

测试、POC等非生产场景

对性能要求极高的场景

日志分类明确、功能较单一的集群

大型、混合型、PAAS型集群

6 日志输出: Stdout or 文件

和虚拟机/物理机不同,K8s 的容器提供标准输出和文件两种方式。在容器中,标准输出将日志直接输出到 stdout 或 stderr,而 DockerEngine 接管 stdout 和 stderr 文件描述符,将日志接收后按照 DockerEngine 配置的 LogDriver 规则进行处理;日志打印到文件的方式和虚拟机/物理机基本类似,只是日志可以使用不同的存储方式,例如默认存储、EmptyDir、HostVolume、NFS 等。

虽然使用 Stdout 打印日志是 Docker 官方推荐的方式,但大家需要注意:这个推荐是基于容器只作为简单应用的场景,实际的业务场景中我们还是建议大家尽可能使用文件的方式,主要的原因有以下几点:

  • Stdout 性能问题,从应用输出 stdout 到服务端,中间会经过好几个流程(例如普遍使用的 JSON LogDriver):应用 stdout -> DockerEngine -> LogDriver -> 序列化成 JSON -> 保存到文件 -> Agent 采集文件 -> 解析 JSON -> 上传服务端。整个流程相比文件的额外开销要多很多,在压测时,每秒 10 万行日志输出就会额外占用 DockerEngine 1 个 CPU 核;
  • Stdout 不支持分类,即所有的输出都混在一个流中,无法像文件一样分类输出,通常一个应用中有 AccessLog、ErrorLog、InterfaceLog(调用外部接口的日志)、TraceLog 等,而这些日志的格式、用途不一,如果混在同一个流中将很难采集和分析;
  • Stdout 只支持容器的主程序输出,如果是 daemon/fork 方式运行的程序将无法使用 stdout;
  • 文件的 Dump 方式支持各种策略,例如同步/异步写入、缓存大小、文件轮转策略、压缩策略、清除策略等,相对更加灵活。

因此我们建议线上应用使用文件的方式输出日志,Stdout 只在功能单一的应用或一些 K8s 系统/运维组件中使用。

Kubernetes 提供了标准化的业务部署方式,可以通过 yaml(K8s API)来声明路由规则、暴露服务、挂载存储、运行业务、定义缩扩容规则等,所以 Kubernetes 很容易和 CICD 系统集成。而日志采集也是运维监控过程中的重要部分,业务上线后的所有日志都要进行实时的收集。

原始的方式是在发布之后手动去部署日志采集的逻辑,这种方式需要手工干预,违背 CICD 自动化的宗旨;为了实现自动化,有人开始基于日志采集的 API/SDK 包装一个自动部署的服务,在发布后通过 CICD 的 webhook 触发调用,但这种方式的开发代价很高。

在 Kubernetes 中,日志最标准的集成方式是以一个新资源注册到 Kubernetes 系统中,以 Operator(CRD)的方式来进行管理和维护。在这种方式下,CICD 系统不需要额外的开发,只需在部署到 Kubernetes 系统时附加上日志相关的配置即可实现。

7 日志采集方案

早在 Kubernetes 出现之前,我们就开始为容器环境开发日志采集方案,随着 K8s 的逐渐稳定,我们开始将很多业务迁移到 K8s 平台上,因此也基于之前的基础专门开发了一套 K8s 上的日志采集方案。主要具备的功能有:

  • 支持各类数据的实时采集,包括容器文件、容器 Stdout、宿主机文件、Journal、Event 等;
  • 支持多种采集部署方式,包括 DaemonSet、Sidecar、DockerEngine LogDriver 等;
  • 支持对日志数据进行富化,包括附加 Namespace、Pod、Container、Image、Node 等信息;
  • 稳定、高可靠,自研的 Logtail 采集 Agent 实现,目前全网已有几百万的部署实例;
  • 基于 CRD 进行扩展,可使用 Kubernetes 部署发布的方式来部署日志采集规则,与 CICD 完美集成。

8 采集规则推荐方式

实际应用场景中,一般都是使用 DaemonSet 或 DaemonSet 与 Sidecar 混用方式,DaemonSet 的优势是资源利用率高,但有一个问题是 DaemonSet 的所有 Logtail 都共享全局配置,而单一的 Logtail 有配置支撑的上限,因此无法支撑应用数比较多的集群。

上述是我们给出的推荐配置方式,核心的思想是:

一个配置尽可能多的采集同类数据,减少配置数,降低 DaemonSet 压力;

核心的应用采集要给予充分的资源,可以使用 Sidecar 方式;

配置方式尽可能使用 CRD 方式;

Sidecar 由于每个 Logtail 是单独的配置,所以没有配置数的限制,这种比较适合于超大型的集群使用;

9 实践对比

9.1 中小型集群

绝大部分 Kubernetes 集群都属于中小型的,对于中小型没有明确的定义,一般应用数在 500 以内,节点规模 1000 以内,没有职能明确的 Kubernetes 平台运维。这种场景应用数不会特别多,DaemonSet 可以支撑所有的采集配置;

  • 绝大部分业务应用的数据使用 DaemonSet 采集方式;
  • 核心应用(对于采集可靠性要求比较高,例如订单/交易系统)使用 Sidecar 方式单独采集;

9.2 大型集群

对于一些用作 PaaS 平台的大型/超大型集群,一般业务在 1000 以上,节点规模也在 1000 以上,有专门的 Kubernetes 平台运维人员。这种场景下应用数没有限制,DaemonSet 无法支持,因此必须使用 Sidecar 方式,整体规划如下:

  • Kubernetes 平台本身的系统组件日志、内核日志相对种类固定,这部分日志使用 DaemonSet 采集,主要为平台的运维人员提供服务;
  • 各个业务的日志使用 Sidecar 方式采集,每个业务可以独立设置 Sidecar 的采集目的地址,为业务的 DevOps 人员提供足够的灵活性;

作者 | 元乙 存储服务技术专家

https://www.kubernetes.org.cn/6935.html

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1 . 为何需要日志系统
    • 2 . 可观察性的终极解读
      • 3 . 日志系统建设难点
        • 4 k8s 日志收集注意
          • 4.1 收集方式
          • 4.2 收集日志规范
          • 4.3 管理日志
        • 5 采集方式: 主动 or 被动
          • 6 日志输出: Stdout or 文件
            • 7 日志采集方案
              • 8 采集规则推荐方式
                • 9 实践对比
                  • 9.1 中小型集群
                  • 9.2 大型集群
              相关产品与服务
              容器服务
              腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档