Logging Operator - 優(yōu)雅的云原生日志管理方案 (二)

其實(shí)我們可以看出來,Logging Operator核心的邏輯主要就兩個(gè)Flow和Output。簡(jiǎn)單來說,F(xiàn)low的作用是用來處理日志流的,Output用來定義日志的輸出方式。掌握了這個(gè),至于ClusterFlow和ClusterOutput無外乎就是一個(gè)全局的聲明罷了。
3.2 Flow && ClusterFlow
Flow定義了日志的filters和outputs,它是一個(gè)namespaces級(jí)別的CRD資源。因此,我們可以在應(yīng)用所在的命名空間內(nèi)根據(jù)Kubernetes標(biāo)簽來決定日志是否被采集,同時(shí)也能定義多個(gè)filter來對(duì)日志進(jìn)行處理。舉個(gè)簡(jiǎn)單的例子:
apiVersion: logging.banzaicloud.io/v1beta1
kind: Flow
metadata:
name: flow-sample
namespace: default
spec:
filters:
- parser:
remove_key_name_field: true
parse:
type: nginx
- tag_normaliser:
format: ${namespace_name}.${pod_name}.${container_name}
localOutputRefs:
- loki-output
match:
- select:
labels:
app: nginx
這條Flow的意思是,讓日志采集端只處理來自default命名空間下,標(biāo)簽app=nginx的容器日志。同時(shí)并對(duì)采集的日志按照nginx的格式進(jìn)行解析,并把這條日志流的tag在fluentd內(nèi)部重定向?yàn)?code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(245, 70, 0);">${namespace_name}.${pod_name}.${container_name}格式。
這個(gè)例子里面,我們著重注意三個(gè)地方match,filters和localOutputRefs
match
match是處理日志的第一步,我們需要利用Kubernetes標(biāo)簽來定義哪些日志需要被采集。當(dāng)前可用的字段如下:
namespaces, 匹配命名空間 labels,匹配labels hosts,匹配host機(jī)器 container_names,匹配容器名字
我們通過select和exclude來選擇或排除我們要匹配的資源類型。比如下面例子:
apiVersion: logging.banzaicloud.io/v1beta1
kind: Flow
metadata:
name: flow-sample
namespace: default
spec:
match:
- exclude:
labels:
componnet: reloader
- select:
labels:
app: nginx
componnet: nginx
這條Flow就聲明讓客戶端只處理default命名空間下標(biāo)簽為app=nginx, componnet: nginx,排除componnet: reloader的容器日志。
對(duì)于ClusterFlow,我們可以通過更負(fù)責(zé)的select來控制多個(gè)namespaces下的日志采集。比如
apiVersion: logging.banzaicloud.io/v1beta1
kind: ClusterFlow
metadata:
name: clusterflow-sample
spec:
match:
- exclude:
namespaces:
- dev
- test
- select:
labels:
app: nginx
這條聲明就告訴了客戶端只處理命名空間是dev和test下,標(biāo)簽為app=nginx的容器日志。
ClusterFlow的聲明默認(rèn)只在
controlNamespace定義的namespace下生效,如果要定義到其他命名空間,你需要在定義logging CRD時(shí)打開allowClusterResourcesFromAllNamespaces
如果我們需要簡(jiǎn)單粗暴的采集指定namespaces下所有容器的日志,那么只需要定義一個(gè)如下內(nèi)容的ClusterFlow即可
apiVersion: logging.banzaicloud.io/v1beta1
kind: ClusterFlow
metadata:
name: clusterflow-sample
spec:
match:
- select:
namespaces:
- prod
- dev
- test
filters
Logging Operator的filter支持一些常見的日志處理插件??梢詤⒖枷旅孢@個(gè)表格
| 名稱 | 類型 | 描述 | 狀態(tài) | 版本 |
|---|---|---|---|---|
| Concat | filters | 用于fluentd處理日志多行的插件 | GA | 2.4.0 |
| Dedot | filters | 處理帶.的字段替換插件,通常用于輸出到elaticsearch前的字段轉(zhuǎn)化 | GA | 1.0.0 |
| Exception Detector | filters | Exception日志捕獲器,支持java, js, csharp, python, go, ruby, php | GA | 0.0.13 |
| Enhance K8s Metadata | filters | banzaicloud開發(fā)的k8s擴(kuò)展元數(shù)據(jù) | GA | 0.0.0 |
| Geo IP | filters | fluentd的GeoIP地址庫(kù) | GA | 1.3.2 |
| Grep | filters | fluentd的grep過濾器 | GA | more info |
| Parser | filters | fluentd的Parser解析器 | GA | more info |
| Prometheus | filters | Prometheus插件,可用于對(duì)日志做計(jì)數(shù) | GA | 1.8.5 |
| Record Modifier | filters | fluentd 字段修改插件 | GA | 2.1.0 |
| Record Transformer | filters | Mutates/transforms incoming event streams. | GA | more info |
| Stdout | filters | 標(biāo)準(zhǔn)輸出插件 | GA | more info |
| SumoLogic | filters | Sumo Logic公司的日志處理插件 | GA | 2.3.1 |
| Tag Normaliser | filters | fluentd中的tag修改器 | GA | 0.1.1 |
filter插件文檔:https://banzaicloud.com/docs/one-eye/logging-operator/configuration/plugins/filters/
Parser插件
Parser插件比較常見,通常我們用它來解析采集的日志內(nèi)容,比如我們要解析的docker日志是json格式就可以按照如下方式配置:
apiVersion: logging.banzaicloud.io/v1beta1
kind: Flow
metadata:
name: flow-sample
filters:
- parser:
remove_key_name_field: true
reserve_data: true
key_name: "log"
parse:
type: json
time_key: time
time_format: "%Y-%m-%dT%H:%M:%S.%NZ"
甚至,我們也可以在日志里定義多種類型的格式,如下:
apiVersion: logging.banzaicloud.io/v1beta1
kind: Flow
metadata:
name: flow-sample
spec:
filters:
- parser:
remove_key_name_field: true
reserve_data: true
parse:
type: multi_format
patterns:
- format: nginx
- format: regexp
expression: /foo/
- format: none
這會(huì)生成fluentd的如下的fluentd配置
<filter **>
@type parser
@id test_parser
key_name message
remove_key_name_field true
reserve_data true
<parse>
@type multi_format
<pattern>
format nginx
</pattern>
<pattern>
expression /foo/
format regexp
</pattern>
<pattern>
format none
</pattern>
</parse>
</filter>
parser插件文檔:https://banzaicloud.com/docs/one-eye/logging-operator/configuration/plugins/filters/parser/
record_modifier插件
record_modifier允許我們從已解析的日志字段里面提取和修改字段。比如我們?cè)诓杉痥ubernetes的容器日志時(shí),希望修改部分元數(shù)據(jù)時(shí),就可以使用這個(gè)插件。
apiVersion: logging.banzaicloud.io/v1beta1
kind: Flow
metadata:
name: flow-sample
spec:
filters:
- record_modifier:
records:
- host: ${record.dig('kubernetes', 'host')}
這條filter規(guī)則就定義了讓fluentd在處理日志元數(shù)據(jù)時(shí),新加一個(gè)字段host,它的值來自于.kubernetes.host。它最終在fluentd中操作的配置是這樣的。
<filter **>
@type record_modifier
@id test_record_modifier
<record>
host ${record.dig('kubernetes', 'host')}
</record>
</filter>
prometheus插件
prometheus是用來統(tǒng)計(jì)進(jìn)入fluentd日志流并處理的日志基數(shù),比如我們想統(tǒng)計(jì)標(biāo)簽app=nginx這個(gè)打印了多少日志時(shí),就可以用該插件處理,
apiVersion: logging.banzaicloud.io/v1beta1
kind: Flow
metadata:
name: flow-sample
spec:
filters:
- parser:
remove_key_name_field: true
reserve_data: true
parse:
type: nginx
- prometheus:
metrics:
- name: total_counter
desc: The total number of nginx in message.
type: counter
labels:
app: nginx
labels:
host: ${hostname}
tag: ${tag}
namespace: $.kubernetes.namespace
這個(gè)就表示了nginx日志在fluentd共計(jì)處理了多少行消息,這對(duì)我們統(tǒng)計(jì)業(yè)務(wù)日志資源使用來說比較方便的。
prometheus插件文檔:https://banzaicloud.com/docs/one-eye/logging-operator/configuration/plugins/filters/prometheus/
OutputRefs
OutputRefs定義了日志的輸出路徑。它分為locallOutputRefs和globallOutputRefs。故名思義,locallOutputRefs是跟flow一樣作用在namespace級(jí)別,其他ns下的Flow看不到當(dāng)前ns下的output定義。globallOutputRefs為集群級(jí)別的日志輸出聲明,它能被所有ns下的Flow和ClusterFlow引用。
3.3 Output && ClusterOutput
Output定義了日志的輸出方式,目前Logging Operator支持的日志輸出插件非常多,包含如下內(nèi)容:
- Alibaba Cloud
- Amazon CloudWatch
- Amazon Elasticsearch
- Amazon Kinesis
- Amazon S3
- Azure Storage
- Buffer
- Datadog
- Elasticsearch
- File
- Format
- Format rfc5424
- Forward
- GELF
- Google Cloud Storage
- Grafana Loki
- Http
- Kafka
- LogDNA
- LogZ
- NewRelic
- Splunk
- SumoLogic
- Syslog
這里面我們?nèi)粘9ぷ髦杏玫降娜罩敬鎯?chǔ)或架構(gòu)大概就包含Loki,ElasticSearch,Kafka或S3。
Grafana Loki
Grafana Loki插件用來定義fluentd將日志輸出到Loki當(dāng)中,我們可以定義一些特定的參數(shù)來控制和優(yōu)化日志輸出,比如下面這個(gè)樣例:
apiVersion: logging.banzaicloud.io/v1beta1
kind: Output
metadata:
name: loki-output
spec:
loki:
buffer:
chunk_limit_size: 8M
flush_at_shutdown: true
flush_interval: 10s
flush_mode: interval
flush_thread_count: 4
overflow_action: throw_exception
queued_chunks_limit_size: 64
retry_max_interval: 60s
retry_timeout: 1h
retry_type: exponential_backoff
retry_wait: 10s
total_limit_size: 10G
type: file
configure_kubernetes_labels: false
drop_single_key: true
extra_labels:
cluster: cluster-xxx
extract_kubernetes_labels: false
labels:
namespace: ""
pod: ""
images: ""
host: ""
container: ""
tream: ""
remove_keys:
- time
- kubernetes
- logtag
- docker
- metadata
url: http://loki:3100
在多租戶的場(chǎng)景下,我們甚至也可以將Loki的多租戶功能打開,這樣我們可以在定義output的時(shí)候指定租戶信息,比如:
apiVersion: logging.banzaicloud.io/v1beta1
kind: Output
metadata:
name: loki-output
spec:
loki:
url: http://loki:3100
username: test
password: test
tenant: test
這樣我們就可以靈活的在kubernets集群中定義多租戶的日志輸出問題。
loki插件文檔:https://banzaicloud.com/docs/one-eye/logging-operator/configuration/plugins/outputs/loki/
Kafka
Fluentd的kafka輸出插件
apiVersion: logging.banzaicloud.io/v1beta1
kind: Output
metadata:
name: kafka-output
spec:
kafka:
brokers: kafka-headless.kafka.svc.cluster.local:29092
topic_key: topic
default_topic: topic
required_acks:1
format:
type: json
buffer:
tags: topic
timekey: 1m
timekey_wait: 30s
timekey_use_utc: true
kafka插件文檔:https://banzaicloud.com/docs/one-eye/logging-operator/configuration/plugins/outputs/kafka/
ElasticSearch
Fluentd的ES輸出插件
apiVersion: logging.banzaicloud.io/v1beta1
kind: Output
metadata:
name: es-output
spec:
elasticsearch:
host: elasticsearch.logging.svc.cluster.local
port: 9200
scheme: https
ssl_verify: false
ssl_version: TLSv1_2
user: elastic
logstash_format: true
password:
valueFrom:
secretKeyRef:
name: quickstart-es-elastic-user
key: elastic
buffer:
timekey: 1m
timekey_wait: 30s
timekey_use_utc: true
elasticsearch插件文檔:https://banzaicloud.com/docs/one-eye/logging-operator/configuration/plugins/outputs/elasticsearch/
另外值得提醒的是,Output和ClusterOutput都可以被OutputRefs引用,比如我們需要將日志同時(shí)發(fā)送給kafka和elastichsearch時(shí),我們就可以如下定義:
apiVersion: logging.banzaicloud.io/v1beta1
kind: Flow
metadata:
name: nginx-flow
namespace: default
spec:
filters:
- parser:
remove_key_name_field: true
reserve_data: true
parse:
type: nginx
match:
- select:
labels:
app: nginx
localOutputRefs:
- kafka-output
- es-output
階段性總結(jié)
本文簡(jiǎn)單總結(jié)了Logging Operator的Flow、ClusterFlow、Output和ClusterOutput資源使用??梢粤私獾轿覀兛梢酝ㄟ^Flow&ClusterFlow來快速聲明和解析需要采集的日志的容器。通過Output&ClusterOutput來定義多樣的日志輸出渠道。在實(shí)際的工作中,我們往往需要對(duì)運(yùn)行在kubernetes中的容器日志流向做定向管理,用Logging Operator可以輕松實(shí)現(xiàn)這類工作。
特別是我們需要在K8S中設(shè)計(jì)多租戶架構(gòu)時(shí),對(duì)于不同租戶的日志采集方式、filter規(guī)則和輸出方式都是租戶的私有配置,這部分通過CRD的定義到租戶命名空間管理算是一個(gè)非常優(yōu)雅的解決方案了。
