背景
Fluentd/Fluent Bit作为云原生场景的可观测采集器,致力于打造云原生场景下的日志采集方案。Fluentd/Fluent Bit官方虽然提供了一些K8s的采集部署方案,但是总体来说自动化程度不高,操作也比较繁琐。所以也就催生出了各类Operator,比较有名的是Fluent Operator、Logging Operator,本文将重点介绍Logging Operator的原理及实战。
Logging Operator是BanzaiCloud开源的一个云原生场日志采集方案,它整合了fluent 社区的两个开源日志采集器 FluentBit、Fluentd,以 operator 的方式自动化配置 k8s 日志采集pipeline。
Logging Operator原理
Logging operator 可以自动部署和配置Kubernetes 日志采集pipeline。该operator会在每个节点上部署Fluent Bit DaemonSet,用于从节点文件系统中收集容器和应用程序日志;同时,Fluent Bit会查询 Kubernetes API 并使用有关 pod 的元数据丰富日志,并将日志和元数据都传输到 Fluentd。Fluentd接收后,经过过滤处理,最终传输给第三方存储系统。 整个日志的采集、传输过程始终在经过身份验证和加密的通道上传输。
使用者可以配置如下的CRD配置Logging operator:
- logging:定义了FleuntBit、Fleuntd的基础配置;可以指定controlNamespace。
- output:定义了namespace级别的日志输出配置。
- flow:定义了namespaces级别的日志filters、outputs流。
- clusteroutput:定义了cluster级别的日志输出配置。
- clusterflow:定义了cluster级别的日志filters、outputs流。
CRD详解
flow/clusterflow
- 作用:用来处理日志流的,决定了数据从哪里采集、如何过滤、路由分发。
- match定义了哪些容器的日志会被采集。可以通过select、exclude表示选择或排除;字段可以是namespaces、labels、container_names等。
- filters为Logging Operator的日志处理插件。常见的有:Parser(支持nginx、apache2、syslog、csv、json等)、Prometheus(可以对日志进行统计)、Tag Normaliser(tag修改器)等。
- 示例1:将default命名空间下标签为app=nginx的容器日志,采集后按照nginx日志格式解析,最终日志的 tag 在 fluentd 最终汇总时设置为
${namespace_name}.${pod_name}.${container_name}
格式。
apiVersion: logging.banzaicloud.io/v1beta1
kind: Flow
metadata:
name: default-flow
namespace: default ##定义收集日志的命名空间
spec:
filters: ##定义过滤器,一个flow可以定义一个或者多个
- parser:
remove_key_name_field: true
parse: ##parse支持apache2, apache_error, nginx, syslog, csv, tsv, ltsv, json, multiline, none, logfmt类型解析
type: nginx
- tag_normaliser:
format: ${namespace_name}.${pod_name}.${container_name} ##在fluentd里面使用${namespace_name}.${pod_name}.${container_name}的格式
localOutputRefs:
- "elasticsearch-output" ## 定义Output
match: ## Kubernetes标签来定义哪些日志需要被采集
- select:
labels: ## 使用标签匹配采集日志
app: nginx
- 示例2: Prometheus 插件
apiVersion: logging.banzaicloud.io/v1beta1
kind: Flow
metadata:
name: default-flow
namespace: default ##定义收集日志的命名空间
spec:
filters:
- parser:
remove_key_name_field: true
parse: ##parse支持apache2, apache_error, nginx, syslog, csv, tsv, ltsv, json, multiline, none, logfmt类型解析
type: nginx ##采集日志按照Nginx格式进行处理
- prometheus: ##Pormetheus插件
metrics:
- desc: The total number of nginx in log. ##指标说明
name: nginx_log_total_counter ##指标名称
type: counter ##指标Prometheus类型
labels: ## 指标标签
app: nginx
labels: ##指标标签
host: ${hostname}
tag: ${tag}
namespace: $.kubernetes.namespaces
- tag_normaliser:
format: ${namespace_name}.${pod_name}.${container_name} ##在fluentd里面使用${namespace_name}.${pod_name}.${container_name}的格式
localOutputRefs:
- "es-output" ## 定义Output
match: ## Kubernetes标签来定义哪些日志需要被采集
- select:
labels: ## 使用标签匹配采集日志
app: nginx
output/clusteroutput
- 作用:表示处理完成的日志应该输出到哪里。
- 示例:Output-Kafka配置
apiVersion: logging.banzaicloud.io/v1beta1
kind: Output
metadata:
name: kafka-output
spec:
kafka:
brokers: kafka-headless.kafka.svc.cluster.local:29092 ##kafka地址
default_topic: topic
topic_key: kafka-output ##kafka topic名称;
sasl_over_ssl: false ##是否使用ssl
format:
type: json ##类型
buffer: ##发送buff配置
tags: topic
timekey: 1m
timekey_wait: 30s
timekey_use_utc: true
Logging Operator实战:Nginx Access Logs访问日志采集到Kafka
- 安装logging-operator
$ 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
$ kubectl get deployment -n logging
NAME READY UP-TO-DATE AVAILABLE AGE
logging-operator 1/1 1 1 10h
- 安装Demo应用
$ helm upgrade --install --wait --create-namespace --namespace logging logging-demo banzaicloud-stable/logging-demo \
--set "kafka.enabled=True"
- 部署logging CRD
# 配置
$ kubectl -n logging apply -f - <<"EOF"
apiVersion: logging.banzaicloud.io/v1beta1
kind: Logging
metadata:
name: default-logging-simple
spec:
fluentd: {}
fluentbit: {}
controlNamespace: logging
EOF
# 结果查看
## 生成DaemonSet的fluentbit
$ kubectl get ds -n logging
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
default-logging-simple-fluentbit 2 2 2 2 2 <none> 9h
## 生成StatefulSet的fluentd
$ kubectl get statefulset -n logging
NAME READY AGE
default-logging-simple-fluentd 1/1 9h
## pod信息
$ kubectl get pods -n logging
NAME READY STATUS RESTARTS AGE
default-logging-simple-fluentbit-n9b25 1/1 Running 1 9h
default-logging-simple-fluentbit-rdzqk 1/1 Running 0 9h
default-logging-simple-fluentd-0 2/2 Running 0 9h
## fluentbit保密字典配置。会将采集的日志输出到default-logging-simple-fluentd中。
$ kubectl get secret default-logging-simple-fluentbit -n logging -o jsonpath='{.data.fluent-bit\.conf}'|base64 --decode
[SERVICE]
Flush 1
Grace 5
Daemon Off
Log_Level info
Parsers_File parsers.conf
Coro_Stack_Size 24576
storage.path /buffers
[INPUT]
Name tail
DB /tail-db/tail-containers-state.db
Mem_Buf_Limit 5MB
Parser docker
Path /var/log/containers/*.log
Refresh_Interval 5
Skip_Long_Lines On
Tag kubernetes.*
[FILTER]
Name kubernetes
Buffer_Size 0
Kube_CA_File /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
Kube_Tag_Prefix kubernetes.var.log.containers
Kube_Token_File /var/run/secrets/kubernetes.io/serviceaccount/token
Kube_URL https://kubernetes.default.svc:443
Match kubernetes.*
Merge_Log On
Use_Kubelet Off
[OUTPUT]
Name forward
Match *
Host default-logging-simple-fluentd.logging.svc.cluster.local
Port 24240
Retry_Limit False
- 配置output、flow CRD
$ kubectl -n logging apply -f - <<"EOF"
apiVersion: logging.banzaicloud.io/v1beta1
kind: Output
metadata:
name: kafka-output
spec:
kafka:
brokers: kafka-headless.kafka.svc.cluster.local:29092
default_topic: topic
format:
type: json
buffer:
tags: topic
timekey: 1m
timekey_wait: 30s
timekey_use_utc: true
EOF
$ kubectl -n logging apply -f - <<"EOF"
apiVersion: logging.banzaicloud.io/v1beta1
kind: Flow
metadata:
name: kafka-flow
spec:
filters:
- tag_normaliser: {}
- parser:
remove_key_name_field: true
reserve_data: true
parse:
type: nginx
match:
- select:
labels:
app.kubernetes.io/name: log-generator
localOutputRefs:
- kafka-output
EOF
// 进入fluentd容器,查看配置文件。说明已经完整转发到kafka的配置。
$ cat fluentd/app-config/fluentd.conf
<source>
@type forward
@id main_forward
bind 0.0.0.0
port 24240
</source>
<label @bd16f9a1a7328cf1691828de4bc6fc89>
<match kubernetes.**>
@type tag_normaliser
@id flow:logging:kafka-flow:0
format ${namespace_name}.${pod_name}.${container_name}
</match>
<filter **>
@type parser
@id flow:logging:kafka-flow:1
key_name log
remove_key_name_field true
reserve_data true
<parse>
@type nginx
</parse>
</filter>
<match **>
@type kafka2
@id flow:logging:kafka-flow:output:logging:kafka-output
brokers .....
default_topic logging-operator-test
sasl_over_ssl false
<buffer topic>
@type file
chunk_limit_size 8MB
path /buffers/flow:logging:kafka-flow:output:logging:kafka-output.*.buffer
retry_forever true
timekey 1m
timekey_use_utc true
timekey_wait 30s
</buffer>
<format>
@type json
</format>
</match>
</label>
...
- 部署demo
kubectl -n logging apply -f - <<"EOF"
apiVersion: apps/v1
kind: Deployment
metadata:
name: log-generator
spec:
selector:
matchLabels:
app.kubernetes.io/name: log-generator
replicas: 1
template:
metadata:
labels:
app.kubernetes.io/name: log-generator
spec:
containers:
- name: nginx
image: banzaicloud/log-generator:0.3.2
EOF
- 结果验证
参考资料
Logging Operator - 优雅的云原生日志管理方案
关于iLogtail
iLogtail作为阿里云SLS提供的可观测数据采集器,可以运行在服务器、容器、K8s、嵌入式等多种环境,支持采集数百种可观测数据(日志、监控、Trace、事件等),已经有千万级的安装量。目前,iLogtail已正式开源,欢迎使用及参与共建。
GitHub:https://github.com/alibaba/ilogtail
社区版文档:https://ilogtail.gitbook.io/ilogtail-docs/about/readme
企业版官网:https://help.aliyun.com/document_detail/65018.html
钉钉群:iLogtail社区