云原生架构下的日志平台方案

2020-12-08 18:12:53 浏览数 (1)

云原生架构下的日志平台方案

作者简介

Ford, 云原生布道师,云原生实验室(CloudnativeLab.COM)创始人 专注于云计算领域数年,目前主要从事容器云平台的建设,推进各类基础设施服务的云原生化,乐于研发效能建设、产品驱动模式探索和敏捷高效的产品研发团队打造,ServiceMesh拥护者,持续交付、敏捷实践者。

一、云原生架构下的日志系统特点

伴随公司近年来持续高速增长的业务发展,以及软件架构的微服务化,在水平和垂直双向扩展后线上运行的应用成倍增长。原本基于单体应用(Monolithic)场景下,使用tail、grep、awk的日志查询和日志分析方式已捉襟见肘、无法应对云原生架构下成倍增长的应用日志量和分布式项目的复杂运行环境挑战。

在公司转型云原生架构的过程中,复杂的动态集群环境下,可观测性(Observability)对于快速定位和诊断问题,已上升到公司整体层面了。日志作为重要的三大(logs, metrics and traces)可监测要素之一尤为重要。同时日志系统提供的也不再局限于应用系统的诊断,还包括业务、运营、BI、审计、安全等领域,日志平台最终的目标是实现公司在云原生架构下各个方面的数字化、智能化。

图:三大可监测要素:logs, metrics and traces

three-pillars-of-observability-.pngthree-pillars-of-observability-.png

云原生架构下的日志方案比基于物理机、虚拟机场景的日志架构设计有较大的差异,比如:

1、动态的日志环境,在 kubernetes 集群环境下,应用的弹性伸缩、Pod的销毁和漂移、working节点的上线和下线都是常态,这种情况下日志的存在是瞬间的,伴随着Pod的销毁和漂移日志会被动销毁,因此日志数据需要被实时采集到集中式的存储设备中,同时对于日志采集器在此动态和复杂环境下的扩展性和适配性有新的要求。

2、资源消耗,在原有的传统ELK架构中,基于 JDK 的 Logstash 和 Filebeat 预期分别会消耗500M、12M左右的内存,在微服务、云原生的架构下,服务通常都会拆的很小,因此数据采集对于服务自身的资源消耗要尽可能的少。

3、日志平台的运维代价,运维一套动态环境下的日志采集和日志管理平台是复杂和繁琐的,日志平台应该SaaS话,作为底层基础设施,可一键部署和动态适配。

4、便捷的日志分析、日志系统最核心的功能是问题排查,问题排查的速度直接决定了事故响应速度、损失大小。一套可视化、高性能、智能分析的功能可以帮助用户快速定位问题。

二、云原生架构下的日志系统设计

2.1 方案选型
  • 云原生架构下的日志采集解决方案

编号

方案

优点

缺点

1

每个app的镜像中都集成日志收集组件,如logback-redis-appender

部署方便,kubernetes的yaml文件无须特别配置,可以灵活的为每个app自定义日志采集规则

强耦合,应用侵入式,不方便应用和日志收集组件升级和维护且会导致镜像过大

2

app的Pod内单独创建一个日志采集容器跟app的容器一起运行

低耦合,扩展性强,方便维护和升级

需要对 kubernetes 的yaml文件进行单独配置,略显繁琐

3

以 DaemonSet 方式在每个工作节点上启动一个日志采集的Pod, 将所有的Pod的日志都挂载到宿主机上

完全解耦,性能最高,管理起来最方便

需要统一日志收集规则,目录和输出方式

综合以上优缺点,我们选择使用方案三。

该方案在扩展性、资源消耗、部署和后期维护方面都能做到均衡,因此选择该方案。

以下整理各方案的架构图:

图:方案1,应用内置采集组件,异步采集

_u65B9_u68481_uFF0C_u5E94_u7528.png_u65B9_u68481_uFF0C_u5E94_u7528.png

图:方案2,Pod伴侣容器,Sidercar模式

_u65B9_u68482_uFF0CPod_u4F34_u4.png_u65B9_u68482_uFF0CPod_u4F34_u4.png

图:方案3,宿主机统一采集方案

_u65B9_u68483_uFF0Cfluent-bit.png_u65B9_u68483_uFF0Cfluent-bit.png
2.2 方案实施及验证
2.2.1 方案说明

在集群启动时以 DaemonSet 方式在每个机器启动一个 Fluent-bit agent,收集日志然后发送给 Elasticsearch。实现方式是每个agent挂载目录 /var/log/containers/ 使用 Fluent-bit 的tail插件扫描每个容器日志文件,直接发送给 Elasticsearch。

而 /var/log/containers/ 的日志实际映射自 kubernetes 节点上的容器日志,如下图所示:

图:节点在/var/log/containers/目录下的文件链接路径

node-container-log-storagepath.pngnode-container-log-storagepath.png
node-container-log-storagepath02.pngnode-container-log-storagepath02.png

fluent-bit 监听及Input配置

代码语言:txt复制
    @INCLUDE input-kubernetes.conf
    @INCLUDE filter-kubernetes.conf
    @INCLUDE output-elasticsearch.conf

  input-kubernetes.conf: |
    [INPUT]
        Name              tail
        Tag               kube.*
        Path              /var/log/containers/*.log
        Parser            docker
        DB                /var/log/flb_kube.db
        Mem_Buf_Limit     5MB
        Skip_Long_Lines   On
        Refresh_Interval  10

采集agent本身也是基于 kubernetes 集群部署的,当集群节点扩容时,由 kube-scheduler 执行新节点的 fluent-bit agent 的自动完成部署。

Elasticsearch 和 Kibana 目前使用的云供应商的服务,自带 X-pack 插件,支持商业版才有的权限管理功能。

2.2.2 实施

1、fluent-bit采集器配置(server, input, filters and output)

fluentd_u91C7_u96C6_u5668_u914D.pngfluentd_u91C7_u96C6_u5668_u914D.png

2、fluent-bit在kubernetes集群中的RABC权限创建

  • fluent-bit-service-account.yaml
代码语言:txt复制

apiVersion: v1

kind: ServiceAccount

metadata:

代码语言:txt复制
name: fluent-bit
代码语言:txt复制
namespace: logging
代码语言:txt复制
  • fluent-bit-role.yaml
代码语言:txt复制

apiVersion: rbac.authorization.k8s.io/v1beta1

kind: ClusterRole

metadata:

代码语言:txt复制
name: fluent-bit-read

rules:

  • apiGroups: "" resources: - namespaces - pods verbs: "get", "list", "watch"
  • fluent-bit-role-binding.yaml
代码语言:txt复制

apiVersion: rbac.authorization.k8s.io/v1beta1

kind: ClusterRoleBinding

metadata:

代码语言:txt复制
name: fluent-bit-read

roleRef:

代码语言:txt复制
apiGroup: rbac.authorization.k8s.io
代码语言:txt复制
kind: ClusterRole
代码语言:txt复制
name: fluent-bit-read

subjects:

  • kind: ServiceAccount name: fluent-bit namespace: logging

3、Fluent-bit在kubernetes集群节点以Daemonset方式部署

  • fluent-bit-ds.yaml
代码语言:txt复制

apiVersion: extensions/v1beta1

kind: DaemonSet

metadata:

代码语言:txt复制
name: fluent-bit
代码语言:txt复制
namespace: logging
代码语言:txt复制
labels:
代码语言:txt复制
  k8s-app: fluent-bit-logging
代码语言:txt复制
  version: v1
代码语言:txt复制
  kubernetes.io/cluster-service: "true"

spec:

代码语言:txt复制
template:
代码语言:txt复制
  metadata:
代码语言:txt复制
    labels:
代码语言:txt复制
      k8s-app: fluent-bit-logging
代码语言:txt复制
      version: v1
代码语言:txt复制
      kubernetes.io/cluster-service: "true"
代码语言:txt复制
    annotations:
代码语言:txt复制
      prometheus.io/scrape: "true"
代码语言:txt复制
      prometheus.io/port: "2020"
代码语言:txt复制
      prometheus.io/path: /api/v1/metrics/prometheus
代码语言:txt复制
  spec:
代码语言:txt复制
    containers:
代码语言:txt复制
    - name: fluent-bit
      image: fluent/fluent-bit:1.2.1
      imagePullPolicy: Always
      ports:
        - containerPort: 2020
      env:
      - name: FLUENT_ELASTICSEARCH_HOST
        value: "elasticsearch"
      - name: FLUENT_ELASTICSEARCH_PORT
        value: "9200"
      volumeMounts:
      - name: varlog
        mountPath: /var/log
      - name: varlibdockercontainers
        mountPath: /var/lib/docker/containers
        readOnly: true
      - name: fluent-bit-config
        mountPath: /fluent-bit/etc/
    terminationGracePeriodSeconds: 10
    volumes:
    - name: varlog
      hostPath:
        path: /var/log
    - name: varlibdockercontainers
      hostPath:
        path: /var/lib/docker/containers
    - name: fluent-bit-config
      configMap:
        name: fluent-bit-config
    serviceAccountName: fluent-bit
    tolerations:
    - key: node-role.kubernetes.io/master
      operator: Exists
      effect: NoSchedule
    - operator: "Exists"
      effect: "NoExecute"
    - operator: "Exists"
      effect: "NoSchedule"
2.3 验证日志平台
  • 简单查询
  • 分词查询
  • 精准查询
  • 复合查询 (AND OR)
  • 基于字段的查询
  • 项目过滤
  • 机器、节点过滤
  • 正则查询
  • 区间查询
  • 查询上下文
  • 日志列表显示定制
  • 时间选择

图:日志查询 - 复合查询 (AND OR)

kb-and.pngkb-and.png

图:日志查询-查询上下文

kb-surunde.pngkb-surunde.png
2.4 集群审计日志采集

方案中的,Fluent-bit支持采集kubernetes集群的事件审计日志,在kube-apiserver操作导致的状态变更的都会产生相应日志,如下 kubernetes-audit-policy.yaml 定义了收集那些审计日志,只需要在kube-api启动文件中引用此配置,通过使用 --audit-policy-file

  • kubernetes-audit-policy.yamlapiVersion: audit.k8s.io/v1 # This is required. kind: PolicyDon't generate audit events for all requests in RequestReceived stage.omitStages:
    • "RequestReceived" rules:Log pod changes at RequestResponse level
    • level: RequestResponse resources:
      • group: ""# Resource "pods" doesn't match requests to any subresource of pods, # which is consistent with the RBAC policy. resources: ["pods"]Log "pods/log", "pods/status" at Metadata level
    • level: Metadata resources:
      • group: "" resources: "pods/log", "pods/status"

Don't log requests to a configmap called "controller-leader"

  • level: None resources:
    • group: "" resources: "configmaps" resourceNames: "controller-leader"

Don't log watch requests by the "system:kube-proxy" on endpoints or services

  • level: None users: "system:kube-proxy" verbs: "watch" resources:
    • group: "" # core API group resources: "endpoints", "services"

Don't log authenticated requests to certain non-resource URL paths.

  • level: None userGroups: "system:authenticated" nonResourceURLs:
    • "/api*" # Wildcard matching.
    • "/version"

Log the request body of configmap changes in kube-system.

  • level: Request resources:
    • group: "" # core API group resources: "configmaps"This rule only applies to resources in the "kube-system" namespace.The empty string "" can be used to select non-namespaced resources.namespaces: "kube-system"

Log configmap and secret changes in all other namespaces at the Metadata level.

  • level: Metadata resources:
    • group: "" # core API group resources: "secrets", "configmaps"

Log all other resources in core and extensions at the Request level.

  • level: Request resources:
    • group: "" # core API group
    • group: "extensions" # Version of group should NOT be included.

A catch-all rule to log all other requests at the Metadata level.

  • level: MetadataLong-running requests like watches that fall under this rule will notgenerate an audit event in RequestReceived.omitStages:
    • "RequestReceived"

图:kubernetes集群审计日志

k8s-audit-log.pngk8s-audit-log.png

三、总结

随着云原生架构下日益复杂的分布式系统,日志比较分散,应用监控和排查问题都比较困难,同时效率还低下,本文中kubernetes集群下的集中式日志平台就是为了解决这个问题。将集群日志、应用日志,安全日志收集、检索、统计、分析以及对日志信息的 Web 管理等集中化管控,实现了快速问题排查、高效解决问题的重要的途径。

在生产部署时,可以根据业务系统容量来确定是否引入 Kafaka 队列,线下环境也可以不引入 Kafaka 队列,简单部署,后续需要扩展再接入 Kafaka 队列。

本文中Elasticsearch 和 Kibana 使用的云厂商的服务,线下开发环境,考虑成本节约的因素可以使用 helm 快速构建,参考如下:

  • 使用 helm 快速部署 Elasticsearch
代码语言:txt复制

helm repo add incubator https://kubernetes-charts-incubator.storage.googleapis.com/

helm install --name elasticsearch stable/elasticsearch

代码语言:txt复制
  --set master.persistence.enabled=false 
代码语言:txt复制
  --set data.persistence.enabled=false 
代码语言:txt复制
  --namespace logging
代码语言:txt复制
  • 使用 helm 快速部署 Kibana
代码语言:txt复制

helm install --name kibana stable/kibana

代码语言:txt复制
  --set env.ELASTICSEARCH_URL=http://elasticsearch-client:9200 
代码语言:txt复制
  --namespace logging
代码语言:txt复制

四、参考文档

https://github.com/fluent/fluentd

https://kubernetes.io/docs/tasks/debug-application-cluster/audit/

https://github.com/kubernetes/kubernetes/tree/master/cluster/addons/fluentd-elasticsearch

https://github.com/fluent/fluent-bit

https://github.com/anjia0532/gcr.io_mirror

0 人点赞