Logging Operator - 优雅的云原生日志管理方案 (一)

2021-04-26 15:40:37 浏览数 (1)

最近一直在研究Logging Operator,淌了不少坑,但也是真的香。现在总结分享给大家,关注公众号持续更新。

Logging Operator是BanzaiCloud下开源的一个云原生场景下的日志采集方案。之前小白转载过崔大佬介绍的一篇文章,不过由于之前一直认为在单个k8s集群下同时管理Fluent bit和Fluentd两个服务在架构上比较臃肿,便留下了一个不适用的初步印象。后来小白在一个在多租户场景下对k8s集群的日志管理做方案时,发现将日志配置统一管理的传统方式灵活性非常的弱。通常操作者会站在一个全局的角度,尽量的让日志的配置做成模版来适配业务,久而久之模版就变得非常庞大且臃肿,对后续维护和接任者都带来了不小挑战。

直到这段时间研究了Logging Operator之后,发现原来用Kubernetes的方式管理日志是非常惬意的一件事情。在开启之前我们先来看看它的架构。

可以看到Logging Operator利用CRD的方式介入了日志从采集、路由、输出这三个阶段的配置。它本质上来说还是利用DaemonSet和StatefulSet在集群内分别部署了FluentBit和Fluentd两个组件,FluentBit将容器日志采集并初步处理后转发给Fluentd做进一步的解析和路由,最终由Fluentd将日志结果转发给不同的服务。

所以服务容器化后,日志的输出标准到底是该打印到标准输出还是落盘到文件,我们可以讨论下。

除了管理日志工作流外,Logging Operator还可以让管理者开启TLS来加密日志在集群内部的网络传输,以及默认集成了ServiceMonitor来暴露日志采集端的状态。当然最重要的还是由于配置CRD化,我们的日志策略终于可以实现在集群内的多租户管理了。

1.Logging Operator CRD

整个Logging Operator的核心CRD就只有5个,它们分别是

  • logging:用于定义一个日志采集端(FleuntBit)和传输端(Fleuntd)服务的基础配置;
  • flow:用于定义一个namespaces级别的日志过滤、解析和路由等规则。
  • clusterflow:用于定义一个集群级别的日志过滤、解析和路由等规则。
  • output:用于定义namespace级别的日志的输出和参数;
  • clusteroutput:用于定义集群级别的日志输出和参数,它能把被其他命名空间内的flow关联;

通过这5个CRD,我们就可以自定义出一个Kubernetes集群内每个命名空间中的容器日志流向

2.Logging Operator 安装

Logging Operator 依赖Kuberentes1.14之后的版本,可以分别用helm和mainfest两种方式安装。

  • Helm(v3.21.0 )安装
代码语言:javascript复制
$ helm repo add banzaicloud-stable https://kubernetes-charts.banzaicloud.com

$ helm repo update

$ helm upgrade --install --wait --create-namespace --namespace logging logging-operator banzaicloud-stable/logging-operator 
  --set createCustomResource=false"
  • Mainfest安装
代码语言:javascript复制
$ kubectl create ns logging

# RBAC
$ kubectl -n logging create -f https://raw.githubusercontent.com/banzaicloud/logging-operator-docs/master/docs/install/manifests/rbac.yaml

# CRD
$ kubectl -n logging create -f https://raw.githubusercontent.com/banzaicloud/logging-operator/master/config/crd/bases/logging.banzaicloud.io_clusterflows.yaml
$ kubectl -n logging create -f https://raw.githubusercontent.com/banzaicloud/logging-operator/master/config/crd/bases/logging.banzaicloud.io_clusteroutputs.yaml
$ kubectl -n logging create -f https://raw.githubusercontent.com/banzaicloud/logging-operator/master/config/crd/bases/logging.banzaicloud.io_flows.yaml
$ kubectl -n logging create -f https://raw.githubusercontent.com/banzaicloud/logging-operator/master/config/crd/bases/logging.banzaicloud.io_loggings.yaml
$ kubectl -n logging create -f https://raw.githubusercontent.com/banzaicloud/logging-operator/master/config/crd/bases/logging.banzaicloud.io_outputs.yaml

# Operator
$ kubectl -n logging create -f https://raw.githubusercontent.com/banzaicloud/logging-operator-docs/master/docs/install/manifests/deployment.yaml

当安装完成后,我们需要验证下服务的状态

代码语言:javascript复制
# Operator状态
$ kubectl -n logging get pods
NAME                                        READY   STATUS    RESTARTS   AGE
logging-logging-operator-599c9cf846-5nw2n   1/1     Running   0          52s

# CRD状态
$ kubectl get crd |grep banzaicloud.io
NAME                                                  CREATED AT
clusterflows.logging.banzaicloud.io                   2021-03-25T08:49:30Z
clusteroutputs.logging.banzaicloud.io                 2021-03-25T08:49:30Z
flows.logging.banzaicloud.io                          2021-03-25T08:49:30Z
loggings.logging.banzaicloud.io                       2021-03-25T08:49:30Z
outputs.logging.banzaicloud.io                        2021-03-25T08:49:30Z

3.Logging Operator 配置

3.1 logging

LoggingSpec

LoggingSpec定义了收集和传输日志消息的日志基础架构服务,其中包含Fluentd和Fluent-bit的配置。它们都部署在controlNamespace指定的命名空间内。一个简单的样例如下:

代码语言:javascript复制
apiVersion: logging.banzaicloud.io/v1beta1
kind: Logging
metadata:
  name: default-logging-simple
  namespace: logging
spec:
  fluentd: {}
  fluentbit: {}
  controlNamespace: logging

这份样例告诉了Operator在logging命名空间内创建一个默认配置的日志服务,其中包含FluentBit和Fluentd两个服务

当然实际上我们在生产环境上部署FluentBit和Fluentd不会只用默认的配置,通常我们要考虑很多方面,比如:

  • 自定义镜像
  • 日志采集位点文件的数据持久化
  • Buffer数据持久化
  • CPU/内存资源限制
  • 状态监控
  • Fluentd副本数以及负载均衡
  • 网络参数优化
  • 容器运行安全

好在Loggingspec里对上述支持得都比较全面,我们可以参考文档来个性化定制自己的服务

小白挑几个重要的字段说明下用途:

  • watchNamespaces

制定让Operator监听Flow和OutPut资源的命名空间,如果你是多租户场景,且每个租户都用logging定义了日志架构化,可以用watchNamespaces来关联租户的命名空间来缩小资源过滤范围

  • allowClusterResourcesFromAllNamespaces

ClusterOutput和ClusterFlow这样的全局资源默认只在controlNamespace关联的命名空间中生效,如果在其他命名空间中定义都会被忽略,除非将allowClusterResourcesFromAllNamespaces设置为true

LoggingSpec描述文档:https://banzaicloud.com/docs/one-eye/logging-operator/configuration/crds/v1beta1/logging_types/

FluentbitSpec
  • filterKubernetes

用来获取日志的Kubernetes元数据的插件,使用样例如下:

代码语言:javascript复制
apiVersion: logging.banzaicloud.io/v1beta1
kind: Logging
metadata:
  name: default-logging-simple
spec:
  fluentd: {}
  fluentbit:
    filterKubernetes:
       Kube_URL: "https://kubernetes.default.svc:443"
       Match: "kube.*"
  controlNamespace: logging

也可以用disableKubernetesFilter将该功能禁止,样例如下:

代码语言:javascript复制
apiVersion: logging.banzaicloud.io/v1beta1
kind: Logging
metadata:
  name: default-logging-simple
spec:
  fluentd: {}
  fluentbit:
    disableKubernetesFilter: true
  controlNamespace: logging

filterKubernetes描述文档: https://banzaicloud.com/docs/one-eye/logging-operator/configuration/crds/v1beta1/fluentbit_types/#filterkubernetes

  • inputTail

定义FluentBit的日志tail采集配置,这里面有很多细节的参数来控制,小白直接贴现在在用的配置样例:

代码语言:javascript复制
apiVersion: logging.banzaicloud.io/v1beta1
kind: Logging
metadata:
  name: default-logging-simple
spec:
  fluentbit:
    inputTail:
      Skip_Long_Lines: "true"
      #Parser: docker
      Parser: cri
      Refresh_Interval: "60"
      Rotate_Wait: "5"
      Mem_Buf_Limit: "128M"
      #Docker_Mode: "true"
      Docker_Mode: "false

如果Kubernetes集群的容器运行时是Containerd或者其他CRI,就需要把Parser改成cri,同时禁用Docker_Mode

inputTail描述文档: https://banzaicloud.com/docs/one-eye/logging-operator/configuration/crds/v1beta1/fluentbit_types/#inputtail

  • buffers

定义了FluentBit的缓冲区设置,这个比较重要。由于FluentBit是以DaemonSet的方式部署在Kubernetes集群中,所以我们可以直接采用hostPath的卷挂载方式来给它提供数据持久化的配置,样例如下:

代码语言:javascript复制
apiVersion: logging.banzaicloud.io/v1beta1
kind: Logging
metadata:
  name: default-logging-simple
spec:
  fluentbit:
    bufferStorage:
      storage.backlog.mem_limit: 10M
      storage.path: /var/log/log-buffer
    bufferStorageVolume:
      hostPath:
        path: "/var/log/log-buffer"

bufferStorage描述文档: https://banzaicloud.com/docs/one-eye/logging-operator/configuration/crds/v1beta1/fluentbit_types/#bufferstorage

  • positiondb

定义了FluentBit采集日志的文件位点信息,同理我们可以用hostPath方式支持,样例如下:

代码语言:javascript复制
apiVersion: logging.banzaicloud.io/v1beta1
kind: Logging
metadata:
  name: default-logging-simple
spec:
  fluentbit:
    positiondb:
      hostPath:
        path: "/var/log/positiondb"
  • image

提供自定义的FluentBit的镜像信息,这里我强烈推荐使用FluentBit-1.7.3之后的镜像,它修复了采集端众多网络连接超时的问题,它的样例如下:

代码语言:javascript复制
apiVersion: logging.banzaicloud.io/v1beta1
kind: Logging
metadata:
  name: default-logging-simple
spec:
  fluentbit:
    image:
      repository: fluent/fluent-bit
      tag: 1.7.3
      pullPolicy: IfNotPresent
  • metrics

定义了FluentBit的监控暴露端口,以及集成的ServiceMonitor采集定义,它的样例如下:

代码语言:javascript复制
apiVersion: logging.banzaicloud.io/v1beta1
kind: Logging
metadata:
  name: default-logging-simple
spec:
  fluentbit:
    metrics:
      interval: 60s
      path: /api/v1/metrics/prometheus
      port: 2020
      serviceMonitor: true
  • resources

定义了FluentBit的资源分配和限制信息,样例如下:

代码语言:javascript复制
apiVersion: logging.banzaicloud.io/v1beta1
kind: Logging
metadata:
  name: default-logging-simple
spec:
  fluentbit:
    resources:
      limits:
        cpu: "1"
        memory: 512Mi
      requests:
        cpu: 200m
        memory: 128Mi
  • security

定义了FluentBit运行期间的安全设置,其中包含了PSP、RBAC、securityContext和podSecurityContext。他们共同组成控制了FluentBit容器内的权限,它们的样例如下:

代码语言:javascript复制
apiVersion: logging.banzaicloud.io/v1beta1
kind: Logging
metadata:
  name: default-logging-simple
spec:
  fluentbit:
    security:
      podSecurityPolicyCreate: true
      roleBasedAccessControlCreate: true
      securityContext:
        allowPrivilegeEscalation: false
        readOnlyRootFilesystem: true
      podSecurityContext:
        fsGroup: 101
  • 性能参数

这里面定义了FluentBit的一些运行性能方面的参数,其中包含:

1.开启forward转发上游应答响应

代码语言:javascript复制
apiVersion: logging.banzaicloud.io/v1beta1
kind: Logging
metadata:
  name: default-logging-simple
spec:
  fluentbit:
    forwardOptions:
      Require_ack_response: true

2.TCP连接参数

代码语言:javascript复制
apiVersion: logging.banzaicloud.io/v1beta1
kind: Logging
metadata:
  name: default-logging-simple
spec:
  fluentbit:
    network:
      connectTimeout: 30
      keepaliveIdleTimeout: 60

3.开启负载均衡模式

代码语言:javascript复制
apiVersion: logging.banzaicloud.io/v1beta1
kind: Logging
metadata:
  name: default-logging-simple
spec:
  fluentbit:
    enableUpstream: true

4.调度污点容忍

代码语言:javascript复制
apiVersion: logging.banzaicloud.io/v1beta1
kind: Logging
metadata:
  name: default-logging-simple
spec:
  fluentbit:
    tolerations:
    - effect: NoSchedule
      key: node-role.kubernetes.io/master
FluentdSpec
  • buffers

这里主要定义Fluentd的buffer数据持久化配置,由于Fluentd是以StatefulSet的方式部署的,所以我们用hostPath就不太合适,这里我们应该用PersistentVolumeCliamTemplate的方式为每一个fluentd实例创建一块专门的buffer数据卷,样例如下:

代码语言:javascript复制
apiVersion: logging.banzaicloud.io/v1beta1
kind: Logging
metadata:
  name: default-logging-simple
spec:
  fluentd:
    bufferStorageVolume:
      pvc:
        spec:
          accessModes:
            - ReadWriteOnce
          resources:
            requests:
              storage: 50Gi
          storageClassName: csi-rbd
          volumeMode: Filesystem

这里如果不指定storageClassName的话,Operator将通过StorageClass为default的存储插件创建pvc

  • FluentOutLogrotate

定义了Fluentd的标准输出重定向到文件配置,这主要是为了避免在出现错误时Fluentd产生连锁反应,并且错误消息作为日志消息返回系统生成另一个错误,样例如下:

代码语言:javascript复制
apiVersion: logging.banzaicloud.io/v1beta1
kind: Logging
metadata:
  name: default-logging-simple
spec:
  fluentd:
    fluentOutLogrotate:
      enabled: true
      path: /fluentd/log/out
      age: 10
      size: 10485760

这里表达的意思就是将fluentd日志重定向到/fluentd/log/out目录,同时保留10天,文件最大不超过10M

FluentOutLogrotate描述文档:https://banzaicloud.com/docs/one-eye/logging-operator/configuration/crds/v1beta1/fluentd_types/#fluentoutlogrotate

  • Scaling

这里主要定义fluentd的副本数,如果FluentBit开启UpStraem的支持,调整Fluentd的副本数会导致FluentBit滚动更新,它的样例如下:

代码语言:javascript复制
apiVersion: logging.banzaicloud.io/v1beta1
kind: Logging
metadata:
  name: default-logging-simple
spec:
  fluentd:
    scaling:
      replicas: 4

scaling描述文档:https://banzaicloud.com/docs/one-eye/logging-operator/configuration/crds/v1beta1/fluentd_types/#fluentdscaling

  • Worker

这里定义了Fluentd内部的Worker数量,由于Fluentd受限于ruby,它还是以单进程的方式处理日志工作流,增加worker数可以显著提高Fluentd的并发,样例如下:

代码语言:javascript复制
apiVersion: logging.banzaicloud.io/v1beta1
kind: Logging
metadata:
  name: default-logging-simple
spec:
  fluentd:
    workers: 2

当Worker数大于1时,Operator-3.9.2之前的版本,对Fluentd的buffer数据持久化存储不够友好,可能会造成Fluentd容器Crash

  • image

定义了FluentD的镜像信息,这里必须要用Logging Operator定制的镜像,可以自定义镜像版本,结构和FluetBit类似。

  • security

定义了FluentD运行期间的安全设置,其中包含了PSP、RBAC、securityContext和podSecurityContext,结构和FluetBit类似。

  • metrics

定义了FluentD的监控暴露端口,以及集成的ServiceMonitor采集定义,结构和FluetBit类似。

  • resources

定义了FluentD的资源分配和限制信息,结构和FluetBit类似。

阶段性总结

本文介绍了Logging Operator的架构、部署和CRD的相关内容,同时详细描述了logging的定义和重要参数。当我们要将Operator用于生产环境采集日志时,它们会变得非常重要,请读者在使用前一定好好参考文档。

由于Logging Opeator的内容非常多,我将在后面几期更新Flow、ClusterFlow、Output、ClusterOutput以及各种Plugins的使用,请大家持续关注

0 人点赞