搭建 EFK 日志系統(tǒng)
前面大家介紹了 Kubernetes 集群中的幾種日志收集方案,Kubernetes 中比較流行的日志收集解決方案是 Elasticsearch、Fluentd 和 Kibana(EFK)技術(shù)棧,也是官方現(xiàn)在比較推薦的一種方案。
Elasticsearch
?是一個(gè)實(shí)時(shí)的、分布式的可擴(kuò)展的搜索引擎,允許進(jìn)行全文、結(jié)構(gòu)化搜索,它通常用于索引和搜索大量日志數(shù)據(jù),也可用于搜索許多不同類型的文檔。
Elasticsearch 通常與?Kibana
?一起部署,Kibana 是 Elasticsearch 的一個(gè)功能強(qiáng)大的數(shù)據(jù)可視化 Dashboard,Kibana 允許你通過 web 界面來瀏覽 Elasticsearch 日志數(shù)據(jù)。
Fluentd
是一個(gè)流行的開源數(shù)據(jù)收集器,我們將在 Kubernetes 集群節(jié)點(diǎn)上安裝 Fluentd,通過獲取容器日志文件、過濾和轉(zhuǎn)換日志數(shù)據(jù),然后將數(shù)據(jù)傳遞到 Elasticsearch 集群,在該集群中對其進(jìn)行索引和存儲(chǔ)。
我們先來配置啟動(dòng)一個(gè)可擴(kuò)展的 Elasticsearch 集群,然后在 Kubernetes 集群中創(chuàng)建一個(gè) Kibana 應(yīng)用,最后通過 DaemonSet 來運(yùn)行 Fluentd,以便它在每個(gè) Kubernetes 工作節(jié)點(diǎn)上都可以運(yùn)行一個(gè) Pod。
安裝 Elasticsearch 集群?
在創(chuàng)建 Elasticsearch 集群之前,我們先創(chuàng)建一個(gè)命名空間,我們將在其中安裝所有日志相關(guān)的資源對象。
$ kubectl create ns logging
環(huán)境準(zhǔn)備?
ElasticSearch 安裝有最低安裝要求,如果安裝后 Pod 無法正常啟動(dòng),請檢查是否符合最低要求的配置,要求如下:
這里我們要安裝的 ES 集群環(huán)境信息如下所示:
這里我們使用一個(gè) NFS 類型的 StorageClass 來做持久化存儲(chǔ),當(dāng)然如果你是線上環(huán)境建議使用 Local PV 或者 Ceph RBD 之類的存儲(chǔ)來持久化 Elasticsearch 的數(shù)據(jù)。
此外由于 ElasticSearch 7.x 版本默認(rèn)安裝了?X-Pack
?插件,并且部分功能免費(fèi),需要我們配置一些安全證書文件。
1、生成證書文件
# 運(yùn)行容器生成證書,containerd下面用nerdctl
$ mkdir -p elastic-certs
$ nerdctl run --name elastic-certs -v elastic-certs:/app -it -w /app elasticsearch:7.17.3 /bin/sh -c \
"elasticsearch-certutil ca --out /app/elastic-stack-ca.p12 --pass '' && \
elasticsearch-certutil cert --name security-master --dns \
security-master --ca /app/elastic-stack-ca.p12 --pass '' --ca-pass '' --out /app/elastic-certificates.p12"
# 刪除容器
$ nerdctl rm -f elastic-certs
# 將 pcks12 中的信息分離出來,寫入文件
$ cd elastic-certs && openssl pkcs12 -nodes -passin pass:'' -in elastic-certificates.p12 -out elastic-certificate.pem
需要注意 nerdctl 如果是 v0.20.0 版本,需要更新 CNI 插件版本,否則會(huì)出現(xiàn)錯(cuò)誤?
FATA[0000] failed to create shim: OCI runtime create failed: container_linux.go:380: starting container process caused: process_linux.go:545: container init caused: Running hook #0:: error running hook: exit status 1, stdout: , stderr: time="2022-06-06T16:37:03+08:00" level=fatal msg="failed to call cni.Setup: plugin type=\"bridge\" failed (add): incompatible CNI versions; config is \"1.0.0\", plugin supports [\"0.1.0\" \"0.2.0\" \"0.3.0\" \"0.3.1\" \"0.4.0\"]"
,將 CNI 插件從?https://github.com/containernetworking/plugins/releases/download/v1.1.1/cni-plugins-linux-amd64-v1.1.1.tgz?下載下來覆蓋?/opt/cni/bin
?目錄即可。
2、添加證書到 Kubernetes
# 添加證書
$ kubectl create secret -n logging generic elastic-certs --from-file=elastic-certificates.p12
# 設(shè)置集群用戶名密碼
$ kubectl create secret -n logging generic elastic-auth --from-literal=username=elastic --from-literal=password=ydzsio321
安裝 ES 集群?
首先添加 ELastic 的 Helm 倉庫:
$ helm repo add elastic https://helm.elastic.co
$ helm repo update
ElaticSearch 安裝需要安裝三次,分別安裝 Master、Data、Client 節(jié)點(diǎn),Master 節(jié)點(diǎn)負(fù)責(zé)集群間的管理工作;Data 節(jié)點(diǎn)負(fù)責(zé)存儲(chǔ)數(shù)據(jù);Client 節(jié)點(diǎn)負(fù)責(zé)代理 ElasticSearch Cluster 集群,負(fù)載均衡。
首先使用?helm pull
?拉取 Chart 并解壓:
$ helm pull elastic/elasticsearch --untar --version 7.17.3
$ cd elasticsearch
在 Chart 目錄下面創(chuàng)建用于 Master 節(jié)點(diǎn)安裝配置的 values 文件:
# values-master.yaml
## 設(shè)置集群名稱
clusterName: 'elasticsearch'
## 設(shè)置節(jié)點(diǎn)名稱
nodeGroup: 'master'
## 設(shè)置角色
roles:
master: 'true'
ingest: 'false'
data: 'false'
# ============鏡像配置============
## 指定鏡像與鏡像版本
image: 'elasticsearch'
imageTag: '7.17.3'
imagePullPolicy: 'IfNotPresent'
## 副本數(shù)
replicas: 3
# ============資源配置============
## JVM 配置參數(shù)
esJavaOpts: '-Xmx1g -Xms1g'
## 部署資源配置(生成環(huán)境要設(shè)置大些)
resources:
requests:
cpu: '2000m'
memory: '2Gi'
limits:
cpu: '2000m'
memory: '2Gi'
## 數(shù)據(jù)持久卷配置
persistence:
enabled: true
## 存儲(chǔ)數(shù)據(jù)大小配置
volumeClaimTemplate:
storageClassName: local-path
accessModes: ['ReadWriteOnce']
resources:
requests:
storage: 5Gi
# ============安全配置============
## 設(shè)置協(xié)議,可配置為 http、https
protocol: http
## 證書掛載配置,這里我們掛入上面創(chuàng)建的證書
secretMounts:
- name: elastic-certs
secretName: elastic-certs
path: /usr/share/elasticsearch/config/certs
defaultMode: 0755
## 允許您在/usr/share/elasticsearch/config/中添加任何自定義配置文件,例如 elasticsearch.yml、log4j2.properties
## ElasticSearch 7.x 默認(rèn)安裝了 x-pack 插件,部分功能免費(fèi),這里我們配置下
## 下面注掉的部分為配置 https 證書,配置此部分還需要配置 helm 參數(shù) protocol 值改為 https
esConfig:
elasticsearch.yml: |
xpack.security.enabled: true
xpack.security.transport.ssl.enabled: true
xpack.security.transport.ssl.verification_mode: certificate
xpack.security.transport.ssl.keystore.path: /usr/share/elasticsearch/config/certs/elastic-certificates.p12
xpack.security.transport.ssl.truststore.path: /usr/share/elasticsearch/config/certs/elastic-certificates.p12
# xpack.security.http.ssl.enabled: true
# xpack.security.http.ssl.truststore.path: /usr/share/elasticsearch/config/certs/elastic-certificates.p12
# xpack.security.http.ssl.keystore.path: /usr/share/elasticsearch/config/certs/elastic-certificates.p12
## 環(huán)境變量配置,這里引入上面設(shè)置的用戶名、密碼 secret 文件
extraEnvs:
- name: ELASTIC_USERNAME
valueFrom:
secretKeyRef:
name: elastic-auth
key: username
- name: ELASTIC_PASSWORD
valueFrom:
secretKeyRef:
name: elastic-auth
key: password
# ============調(diào)度配置============
## 設(shè)置調(diào)度策略
## - hard:只有當(dāng)有足夠的節(jié)點(diǎn)時(shí) Pod 才會(huì)被調(diào)度,并且它們永遠(yuǎn)不會(huì)出現(xiàn)在同一個(gè)節(jié)點(diǎn)上
## - soft:盡最大努力調(diào)度
antiAffinity: 'soft'
# tolerations:
# - operator: "Exists" ##容忍全部污點(diǎn)
然后創(chuàng)建用于 Data 節(jié)點(diǎn)安裝的 values 文件:
# values-data.yaml
# ============設(shè)置集群名稱============
## 設(shè)置集群名稱
clusterName: 'elasticsearch'
## 設(shè)置節(jié)點(diǎn)名稱
nodeGroup: 'data'
## 設(shè)置角色
roles:
master: 'false'
ingest: 'true'
data: 'true'
# ============鏡像配置============
## 指定鏡像與鏡像版本
image: 'elasticsearch'
imageTag: '7.17.3'
## 副本數(shù)(建議設(shè)置為3,我這里資源不足只用了1個(gè)副本)
replicas: 3
# ============資源配置============
## JVM 配置參數(shù)
esJavaOpts: '-Xmx1g -Xms1g'
## 部署資源配置(生成環(huán)境一定要設(shè)置大些)
resources:
requests:
cpu: '1000m'
memory: '2Gi'
limits:
cpu: '1000m'
memory: '2Gi'
## 數(shù)據(jù)持久卷配置
persistence:
enabled: true
## 存儲(chǔ)數(shù)據(jù)大小配置
volumeClaimTemplate:
storageClassName: local-path
accessModes: ['ReadWriteOnce']
resources:
requests:
storage: 10Gi
# ============安全配置============
## 設(shè)置協(xié)議,可配置為 http、https
protocol: http
## 證書掛載配置,這里我們掛入上面創(chuàng)建的證書
secretMounts:
- name: elastic-certs
secretName: elastic-certs
path: /usr/share/elasticsearch/config/certs
## 允許您在/usr/share/elasticsearch/config/中添加任何自定義配置文件,例如 elasticsearch.yml
## ElasticSearch 7.x 默認(rèn)安裝了 x-pack 插件,部分功能免費(fèi),這里我們配置下
## 下面注掉的部分為配置 https 證書,配置此部分還需要配置 helm 參數(shù) protocol 值改為 https
esConfig:
elasticsearch.yml: |
xpack.security.enabled: true
xpack.security.transport.ssl.enabled: true
xpack.security.transport.ssl.verification_mode: certificate
xpack.security.transport.ssl.keystore.path: /usr/share/elasticsearch/config/certs/elastic-certificates.p12
xpack.security.transport.ssl.truststore.path: /usr/share/elasticsearch/config/certs/elastic-certificates.p12
# xpack.security.http.ssl.enabled: true
# xpack.security.http.ssl.truststore.path: /usr/share/elasticsearch/config/certs/elastic-certificates.p12
# xpack.security.http.ssl.keystore.path: /usr/share/elasticsearch/config/certs/elastic-certificates.p12
## 環(huán)境變量配置,這里引入上面設(shè)置的用戶名、密碼 secret 文件
extraEnvs:
- name: ELASTIC_USERNAME
valueFrom:
secretKeyRef:
name: elastic-auth
key: username
- name: ELASTIC_PASSWORD
valueFrom:
secretKeyRef:
name: elastic-auth
key: password
# ============調(diào)度配置============
## 設(shè)置調(diào)度策略
## - hard:只有當(dāng)有足夠的節(jié)點(diǎn)時(shí) Pod 才會(huì)被調(diào)度,并且它們永遠(yuǎn)不會(huì)出現(xiàn)在同一個(gè)節(jié)點(diǎn)上
## - soft:盡最大努力調(diào)度
antiAffinity: 'soft'
## 容忍配置
# tolerations:
# - operator: "Exists" ##容忍全部污點(diǎn)
最后一個(gè)是用于創(chuàng)建 Client 節(jié)點(diǎn)的 values 文件:
# values-client.yaml
# ============設(shè)置集群名稱============
## 設(shè)置集群名稱
clusterName: 'elasticsearch'
## 設(shè)置節(jié)點(diǎn)名稱
nodeGroup: 'client'
## 設(shè)置角色
roles:
master: 'false'
ingest: 'false'
data: 'false'
# ============鏡像配置============
## 指定鏡像與鏡像版本
image: 'elasticsearch'
imageTag: '7.17.3'
## 副本數(shù)
replicas: 1
# ============資源配置============
## JVM 配置參數(shù)
esJavaOpts: '-Xmx1g -Xms1g'
## 部署資源配置(生成環(huán)境一定要設(shè)置大些)
resources:
requests:
cpu: '1000m'
memory: '2Gi'
limits:
cpu: '1000m'
memory: '2Gi'
## 數(shù)據(jù)持久卷配置
persistence:
enabled: false
# ============安全配置============
## 設(shè)置協(xié)議,可配置為 http、https
protocol: http
## 證書掛載配置,這里我們掛入上面創(chuàng)建的證書
secretMounts:
- name: elastic-certs
secretName: elastic-certs
path: /usr/share/elasticsearch/config/certs
## 允許您在/usr/share/elasticsearch/config/中添加任何自定義配置文件,例如 elasticsearch.yml
## ElasticSearch 7.x 默認(rèn)安裝了 x-pack 插件,部分功能免費(fèi),這里我們配置下
## 下面注掉的部分為配置 https 證書,配置此部分還需要配置 helm 參數(shù) protocol 值改為 https
esConfig:
elasticsearch.yml: |
xpack.security.enabled: true
xpack.security.transport.ssl.enabled: true
xpack.security.transport.ssl.verification_mode: certificate
xpack.security.transport.ssl.keystore.path: /usr/share/elasticsearch/config/certs/elastic-certificates.p12
xpack.security.transport.ssl.truststore.path: /usr/share/elasticsearch/config/certs/elastic-certificates.p12
# xpack.security.http.ssl.enabled: true
# xpack.security.http.ssl.truststore.path: /usr/share/elasticsearch/config/certs/elastic-certificates.p12
# xpack.security.http.ssl.keystore.path: /usr/share/elasticsearch/config/certs/elastic-certificates.p12
## 環(huán)境變量配置,這里引入上面設(shè)置的用戶名、密碼 secret 文件
extraEnvs:
- name: ELASTIC_USERNAME
valueFrom:
secretKeyRef:
name: elastic-auth
key: username
- name: ELASTIC_PASSWORD
valueFrom:
secretKeyRef:
name: elastic-auth
key: password
# ============Service 配置============
service:
type: NodePort
nodePort: '30200'
現(xiàn)在用上面的 values 文件來安裝:
# 安裝 master 節(jié)點(diǎn)
$ helm upgrade --install es-master -f values-master.yaml --namespace logging .
# 安裝 data 節(jié)點(diǎn)
$ helm upgrade --install es-data -f values-data.yaml --namespace logging .
# 安裝 client 節(jié)點(diǎn)
$ helm upgrade --install es-client -f values-client.yaml --namespace logging .
在安裝 Master 節(jié)點(diǎn)后 Pod 啟動(dòng)時(shí)候會(huì)拋出異常,就緒探針探活失敗,這是個(gè)正?,F(xiàn)象。在執(zhí)行安裝 Data 節(jié)點(diǎn)后 Master 節(jié)點(diǎn) Pod 就會(huì)恢復(fù)正常。
安裝 Kibana?
Elasticsearch 集群安裝完成后接下來配置安裝 Kibana
使用?helm pull
?命令拉取 Kibana Chart 包并解壓:
$ helm pull elastic/kibana --untar --version 7.17.3
$ cd kibana
創(chuàng)建用于安裝 Kibana 的 values 文件:
# values-prod.yaml
## 指定鏡像與鏡像版本
image: 'kibana'
imageTag: '7.17.3'
## 配置 ElasticSearch 地址
elasticsearchHosts: 'http://elasticsearch-client:9200'
# ============環(huán)境變量配置============
## 環(huán)境變量配置,這里引入上面設(shè)置的用戶名、密碼 secret 文件
extraEnvs:
- name: 'ELASTICSEARCH_USERNAME'
valueFrom:
secretKeyRef:
name: elastic-auth
key: username
- name: 'ELASTICSEARCH_PASSWORD'
valueFrom:
secretKeyRef:
name: elastic-auth
key: password
# ============資源配置============
resources:
requests:
cpu: '500m'
memory: '1Gi'
limits:
cpu: '500m'
memory: '1Gi'
# ============配置 Kibana 參數(shù)============
## kibana 配置中添加語言配置,設(shè)置 kibana 為中文
kibanaConfig:
kibana.yml: |
i18n.locale: "zh-CN"
# ============Service 配置============
service:
type: NodePort
nodePort: '30601'
使用上面的配置直接安裝即可:
$ helm install kibana -f values-prod.yaml --namespace logging .
下面是安裝完成后的 ES 集群和 Kibana 資源:
$ kubectl get pods -n logging
NAME READY STATUS RESTARTS AGE
elasticsearch-client-0 1/1 Running 0 9m25s
elasticsearch-data-0 1/1 Running 0 9m33s
elasticsearch-master-0 1/1 Running 0 8m29s
kibana-kibana-79b9878cd7-7l75v 1/1 Running 0 6m12s
$ kubectl get svc -n logging
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
elasticsearch-client NodePort 10.108.226.197 <none> 9200:30200/TCP,9300:32746/TCP 3m25s
elasticsearch-client-headless ClusterIP None <none> 9200/TCP,9300/TCP 3m25s
elasticsearch-data ClusterIP 10.104.121.49 <none> 9200/TCP,9300/TCP 3m33s
elasticsearch-data-headless ClusterIP None <none> 9200/TCP,9300/TCP 3m33s
elasticsearch-master ClusterIP 10.102.72.71 <none> 9200/TCP,9300/TCP 6m8s
elasticsearch-master-headless ClusterIP None <none> 9200/TCP,9300/TCP 6m8s
kibana-kibana NodePort 10.109.35.219 <none> 5601:30601/TCP 12s
上面我們安裝 Kibana 的時(shí)候指定了 30601 的 NodePort 端口,所以我們可以從任意節(jié)點(diǎn)?http://IP:30601
?來訪問 Kibana。
我們可以看到會(huì)跳轉(zhuǎn)到登錄頁面,讓我們輸出用戶名、密碼,這里我們輸入上面配置的用戶名?elastic
、密碼?ydzsio321
?進(jìn)行登錄。登錄成功后進(jìn)入如下所示的 Kibana 主頁:
部署 Fluentd?
Fluentd
?是一個(gè)高效的日志聚合器,是用 Ruby 編寫的,并且可以很好地?cái)U(kuò)展。對于大部分企業(yè)來說,F(xiàn)luentd 足夠高效并且消耗的資源相對較少,另外一個(gè)工具?Fluent-bit
?更輕量級,占用資源更少,但是插件相對 Fluentd 來說不夠豐富,所以整體來說,F(xiàn)luentd 更加成熟,使用更加廣泛,所以這里我們使用 Fluentd 來作為日志收集工具。
工作原理?
Fluentd 通過一組給定的數(shù)據(jù)源抓取日志數(shù)據(jù),處理后(轉(zhuǎn)換成結(jié)構(gòu)化的數(shù)據(jù)格式)將它們轉(zhuǎn)發(fā)給其他服務(wù),比如 Elasticsearch、對象存儲(chǔ)等等。Fluentd 支持超過 300 個(gè)日志存儲(chǔ)和分析服務(wù),所以在這方面是非常靈活的。主要運(yùn)行步驟如下:
- 首先 Fluentd 從多個(gè)日志源獲取數(shù)據(jù)
- 結(jié)構(gòu)化并且標(biāo)記這些數(shù)據(jù)
- 然后根據(jù)匹配的標(biāo)簽將數(shù)據(jù)發(fā)送到多個(gè)目標(biāo)服務(wù)去
配置?
一般來說我們是通過一個(gè)配置文件來告訴 Fluentd 如何采集、處理數(shù)據(jù)的,下面簡單和大家介紹下 Fluentd 的配置方法。
日志源配置?
比如我們這里為了收集 Kubernetes 節(jié)點(diǎn)上的所有容器日志,就需要做如下的日志源配置:
<source>
@id fluentd-containers.log
@type tail # Fluentd 內(nèi)置的輸入方式,其原理是不停地從源文件中獲取新的日志。
path /var/log/containers/*.log # 掛載的宿主機(jī)容器日志地址
pos_file /var/log/es-containers.log.pos
tag raw.kubernetes.* # 設(shè)置日志標(biāo)簽
read_from_head true
<parse> # 多行格式化成JSON
@type multi_format # 使用 multi-format-parser 解析器插件
<pattern>
format json # JSON 解析器
time_key time # 指定事件時(shí)間的時(shí)間字段
time_format %Y-%m-%dT%H:%M:%S.%NZ # 時(shí)間格式
</pattern>
<pattern>
format /^(?<time>.+) (?<stream>stdout|stderr) [^ ]* (?<log>.*)$/
time_format %Y-%m-%dT%H:%M:%S.%N%:z
</pattern>
</parse>
</source>
上面配置部分參數(shù)說明如下:
- id:表示引用該日志源的唯一標(biāo)識符,該標(biāo)識可用于進(jìn)一步過濾和路由結(jié)構(gòu)化日志數(shù)據(jù)
- type:Fluentd 內(nèi)置的指令,
tail
?表示 Fluentd 從上次讀取的位置通過 tail 不斷獲取數(shù)據(jù),另外一個(gè)是?http
?表示通過一個(gè) GET 請求來收集數(shù)據(jù)。 - path:
tail
?類型下的特定參數(shù),告訴 Fluentd 采集?/var/log/containers
?目錄下的所有日志,這是 docker 在 Kubernetes 節(jié)點(diǎn)上用來存儲(chǔ)運(yùn)行容器 stdout 輸出日志數(shù)據(jù)的目錄。 - pos_file:檢查點(diǎn),如果 Fluentd 程序重新啟動(dòng)了,它將使用此文件中的位置來恢復(fù)日志數(shù)據(jù)收集。
- tag:用來將日志源與目標(biāo)或者過濾器匹配的自定義字符串,F(xiàn)luentd 匹配源/目標(biāo)標(biāo)簽來路由日志數(shù)據(jù)。
路由配置?
上面是日志源的配置,接下來看看如何將日志數(shù)據(jù)發(fā)送到 Elasticsearch:
<match **>
@id elasticsearch
@type elasticsearch
@log_level info
include_tag_key true
type_name fluentd
host "#{ENV['OUTPUT_HOST']}"
port "#{ENV['OUTPUT_PORT']}"
logstash_format true
<buffer>
@type file
path /var/log/fluentd-buffers/kubernetes.system.buffer
flush_mode interval
retry_type exponential_backoff
flush_thread_count 2
flush_interval 5s
retry_forever
retry_max_interval 30
chunk_limit_size "#{ENV['OUTPUT_BUFFER_CHUNK_LIMIT']}"
queue_limit_length "#{ENV['OUTPUT_BUFFER_QUEUE_LIMIT']}"
overflow_action block
</buffer>
</match>
- match:標(biāo)識一個(gè)目標(biāo)標(biāo)簽,后面是一個(gè)匹配日志源的正則表達(dá)式,我們這里想要捕獲所有的日志并將它們發(fā)送給 Elasticsearch,所以需要配置成
**
。 - id:目標(biāo)的一個(gè)唯一標(biāo)識符。
- type:支持的輸出插件標(biāo)識符,我們這里要輸出到 Elasticsearch,所以配置成 elasticsearch,這是 Fluentd 的一個(gè)內(nèi)置插件。
- log_level:指定要捕獲的日志級別,我們這里配置成?
info
,表示任何該級別或者該級別以上(INFO、WARNING、ERROR)的日志都將被路由到 Elsasticsearch。 - host/port:定義 Elasticsearch 的地址,也可以配置認(rèn)證信息,我們的 Elasticsearch 不需要認(rèn)證,所以這里直接指定 host 和 port 即可。
- logstash_format:Elasticsearch 服務(wù)對日志數(shù)據(jù)構(gòu)建反向索引進(jìn)行搜索,將 logstash_format 設(shè)置為?
true
,F(xiàn)luentd 將會(huì)以 logstash 格式來轉(zhuǎn)發(fā)結(jié)構(gòu)化的日志數(shù)據(jù)。 - Buffer: Fluentd 允許在目標(biāo)不可用時(shí)進(jìn)行緩存,比如,如果網(wǎng)絡(luò)出現(xiàn)故障或者 Elasticsearch 不可用的時(shí)候。緩沖區(qū)配置也有助于降低磁盤的 IO。
過濾?
由于 Kubernetes 集群中應(yīng)用太多,也還有很多歷史數(shù)據(jù),所以我們可以只將某些應(yīng)用的日志進(jìn)行收集,比如我們只采集具有?logging=true
?這個(gè) Label 標(biāo)簽的 Pod 日志,這個(gè)時(shí)候就需要使用 filter,如下所示:
# 刪除無用的屬性
<filter kubernetes.**>
@type record_transformer
remove_keys $.docker.container_id,$.kubernetes.container_image_id,$.kubernetes.pod_id,$.kubernetes.namespace_id,$.kubernetes.master_url,$.kubernetes.labels.pod-template-hash
</filter>
# 只保留具有l(wèi)ogging=true標(biāo)簽的Pod日志
<filter kubernetes.**>
@id filter_log
@type grep
<regexp>
key $.kubernetes.labels.logging
pattern ^true$
</regexp>
</filter>
安裝?
要收集 Kubernetes 集群的日志,直接用 DasemonSet 控制器來部署 Fluentd 應(yīng)用,這樣,它就可以從 Kubernetes 節(jié)點(diǎn)上采集日志,確保在集群中的每個(gè)節(jié)點(diǎn)上始終運(yùn)行一個(gè) Fluentd 容器。當(dāng)然可以直接使用 Helm 來進(jìn)行一鍵安裝,為了能夠了解更多實(shí)現(xiàn)細(xì)節(jié),我們這里還是采用手動(dòng)方法來進(jìn)行安裝。
可以直接使用官方的對于 Kubernetes 集群的安裝文檔:?Kubernetes - Fluentd。
首先,我們通過 ConfigMap 對象來指定 Fluentd 配置文件,新建?fluentd-configmap.yaml
?文件,文件內(nèi)容如下:
# fluentd-configmap.yaml
kind: ConfigMap
apiVersion: v1
metadata:
name: fluentd-conf
namespace: logging
data:
# 容器日志
containers.input.conf: |-
<source>
@id fluentd-containers.log
@type tail # Fluentd 內(nèi)置的輸入方式,其原理是不停地從源文件中獲取新的日志
path /var/log/containers/*.log # Docker 容器日志路徑
pos_file /var/log/es-containers.log.pos # 記錄讀取的位置
tag raw.kubernetes.* # 設(shè)置日志標(biāo)簽
read_from_head true # 從頭讀取
<parse> # 多行格式化成JSON
# 可以使用我們介紹過的 multiline 插件實(shí)現(xiàn)多行日志
@type multi_format # 使用 multi-format-parser 解析器插件
<pattern>
format json # JSON解析器
time_key time # 指定事件時(shí)間的時(shí)間字段
time_format %Y-%m-%dT%H:%M:%S.%NZ # 時(shí)間格式
</pattern>
<pattern>
format /^(?<time>.+) (?<stream>stdout|stderr) [^ ]* (?<log>.*)$/
time_format %Y-%m-%dT%H:%M:%S.%N%:z
</pattern>
</parse>
</source>
# 在日志輸出中檢測異常(多行日志),并將其作為一條日志轉(zhuǎn)發(fā)
# https://github.com/GoogleCloudPlatform/fluent-plugin-detect-exceptions
<match raw.kubernetes.**> # 匹配tag為raw.kubernetes.**日志信息
@id raw.kubernetes
@type detect_exceptions # 使用detect-exceptions插件處理異常棧信息
remove_tag_prefix raw # 移除 raw 前綴
message log
multiline_flush_interval 5
</match>
<filter **> # 拼接日志
@id filter_concat
@type concat # Fluentd Filter 插件,用于連接多個(gè)日志中分隔的多行日志
key message
multiline_end_regexp /\n$/ # 以換行符“\n”拼接
separator ""
</filter>
# 添加 Kubernetes metadata 數(shù)據(jù)
<filter kubernetes.**>
@id filter_kubernetes_metadata
@type kubernetes_metadata
</filter>
# 修復(fù) ES 中的 JSON 字段
# 插件地址:https://github.com/repeatedly/fluent-plugin-multi-format-parser
<filter kubernetes.**>
@id filter_parser
@type parser # multi-format-parser多格式解析器插件
key_name log # 在要解析的日志中指定字段名稱
reserve_data true # 在解析結(jié)果中保留原始鍵值對
remove_key_name_field true # key_name 解析成功后刪除字段
<parse>
@type multi_format
<pattern>
format json
</pattern>
<pattern>
format none
</pattern>
</parse>
</filter>
# 刪除一些多余的屬性
<filter kubernetes.**>
@type record_transformer
remove_keys $.docker.container_id,$.kubernetes.container_image_id,$.kubernetes.pod_id,$.kubernetes.namespace_id,$.kubernetes.master_url,$.kubernetes.labels.pod-template-hash
</filter>
# 只保留具有l(wèi)ogging=true標(biāo)簽的Pod日志
<filter kubernetes.**>
@id filter_log
@type grep
<regexp>
key $.kubernetes.labels.logging
pattern ^true$
</regexp>
</filter>
###### 監(jiān)聽配置,一般用于日志聚合用 ######
forward.input.conf: |-
# 監(jiān)聽通過TCP發(fā)送的消息
<source>
@id forward
@type forward
</source>
output.conf: |-
<match **>
@id elasticsearch
@type elasticsearch
@log_level info
include_tag_key true
host elasticsearch-client
port 9200
user elastic # FLUENT_ELASTICSEARCH_USER | FLUENT_ELASTICSEARCH_PASSWORD
password ydzsio321
logstash_format true
logstash_prefix k8s
request_timeout 30s
<buffer>
@type file
path /var/log/fluentd-buffers/kubernetes.system.buffer
flush_mode interval
retry_type exponential_backoff
flush_thread_count 2
flush_interval 5s
retry_forever
retry_max_interval 30
chunk_limit_size 2M
queue_limit_length 8
overflow_action block
</buffer>
</match>
上面配置文件中我們只配置了 docker 容器日志目錄,收集到數(shù)據(jù)經(jīng)過處理后發(fā)送到?elasticsearch-client:9200
?服務(wù)。
然后新建一個(gè)?fluentd-daemonset.yaml
?的文件,文件內(nèi)容如下:
apiVersion: v1
kind: ServiceAccount
metadata:
name: fluentd-es
namespace: logging
labels:
k8s-app: fluentd-es
kubernetes.io/cluster-service: 'true'
addonmanager.kubernetes.io/mode: Reconcile
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: fluentd-es
labels:
k8s-app: fluentd-es
kubernetes.io/cluster-service: 'true'
addonmanager.kubernetes.io/mode: Reconcile
rules:
- apiGroups:
- ''
resources:
- 'namespaces'
- 'pods'
verbs:
- 'get'
- 'watch'
- 'list'
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: fluentd-es
labels:
k8s-app: fluentd-es
kubernetes.io/cluster-service: 'true'
addonmanager.kubernetes.io/mode: Reconcile
subjects:
- kind: ServiceAccount
name: fluentd-es
namespace: logging
apiGroup: ''
roleRef:
kind: ClusterRole
name: fluentd-es
apiGroup: ''
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: fluentd
namespace: logging
labels:
app: fluentd
kubernetes.io/cluster-service: 'true'
spec:
selector:
matchLabels:
app: fluentd
template:
metadata:
labels:
app: fluentd
kubernetes.io/cluster-service: 'true'
spec:
tolerations:
- key: node-role.kubernetes.io/master
effect: NoSchedule
serviceAccountName: fluentd-es
containers:
- name: fluentd
image: quay.io/fluentd_elasticsearch/fluentd:v3.4.0
volumeMounts:
- name: fluentconfig
mountPath: /etc/fluent/config.d
- name: varlog
mountPath: /var/log
volumes:
- name: fluentconfig
configMap:
name: fluentd-conf
- name: varlog
hostPath:
path: /var/log
我們將上面創(chuàng)建的?fluentd-config
?這個(gè) ConfigMap 對象通過 volumes 掛載到了 Fluentd 容器中,另外為了能夠靈活控制哪些節(jié)點(diǎn)的日志可以被收集,還可以添加了一個(gè)?nodSelector
?屬性:
nodeSelector:
beta.kubernetes.io/fluentd-ds-ready: 'true'
意思就是要想采集節(jié)點(diǎn)的日志,那么我們就需要給節(jié)點(diǎn)打上上面的標(biāo)簽。
!!! info "提示" 如果你需要在其他節(jié)點(diǎn)上采集日志,則需要給對應(yīng)節(jié)點(diǎn)打上標(biāo)簽,使用如下命令:kubectl label nodes node名 beta.kubernetes.io/fluentd-ds-ready=true
。
另外由于我們的集群使用的是 kubeadm 搭建的,默認(rèn)情況下 master 節(jié)點(diǎn)有污點(diǎn),所以如果要想也收集 master 節(jié)點(diǎn)的日志,則需要添加上容忍:
tolerations:
- operator: Exists
分別創(chuàng)建上面的 ConfigMap 對象和 DaemonSet:
$ kubectl create -f fluentd-configmap.yaml
configmap "fluentd-conf" created
$ kubectl create -f fluentd-daemonset.yaml
serviceaccount "fluentd-es" created
clusterrole.rbac.authorization.k8s.io "fluentd-es" created
clusterrolebinding.rbac.authorization.k8s.io "fluentd-es" created
daemonset.apps "fluentd" created
創(chuàng)建完成后,查看對應(yīng)的 Pods 列表,檢查是否部署成功:
$ kubectl get pods -n logging
NAME READY STATUS RESTARTS AGE
elasticsearch-client-0 1/1 Running 0 64m
elasticsearch-data-0 1/1 Running 0 65m
elasticsearch-master-0 1/1 Running 0 73m
fluentd-5rqbq 1/1 Running 0 60m
fluentd-l6mgf 1/1 Running 0 60m
fluentd-xmfpg 1/1 Running 0 60m
kibana-66f97964b-mdspc 1/1 Running 0 63m
Fluentd 啟動(dòng)成功后,這個(gè)時(shí)候就可以發(fā)送日志到 ES 了,但是我們這里是過濾了只采集具有?logging=true
?標(biāo)簽的 Pod 日志,所以現(xiàn)在還沒有任何數(shù)據(jù)會(huì)被采集。
下面我們部署一個(gè)簡單的測試應(yīng)用, 新建?counter.yaml
?文件,文件內(nèi)容如下:
apiVersion: v1
kind: Pod
metadata:
name: counter
labels:
logging: 'true' # 一定要具有該標(biāo)簽才會(huì)被采集
spec:
containers:
- name: count
image: busybox
args:
[
/bin/sh,
-c,
'i=0; while true; do echo "$i: $(date)"; i=$((i+1)); sleep 1; done',
]
該 Pod 只是簡單將日志信息打印到?stdout
,所以正常來說 Fluentd 會(huì)收集到這個(gè)日志數(shù)據(jù),在 Kibana 中也就可以找到對應(yīng)的日志數(shù)據(jù)了,使用 kubectl 工具創(chuàng)建該 Pod:
$ kubectl create -f counter.yaml
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
counter 1/1 Running 0 9h
Pod 創(chuàng)建并運(yùn)行后,回到 Kibana Dashboard 頁面,點(diǎn)擊左側(cè)最下面的?Management
?->?Stack Management
,進(jìn)入管理頁面,點(diǎn)擊左側(cè)?Kibana
?下面的?索引模式
,點(diǎn)擊?創(chuàng)建索引模式
?開始導(dǎo)入索引數(shù)據(jù):
在這里可以配置我們需要的 Elasticsearch 索引,前面 Fluentd 配置文件中我們采集的日志使用的是 logstash 格式,定義了一個(gè)?k8s
?的前綴,所以這里只需要在文本框中輸入?k8s-*
?即可匹配到 Elasticsearch 集群中采集的 Kubernetes 集群日志數(shù)據(jù),然后點(diǎn)擊下一步,進(jìn)入以下頁面:
在該頁面中配置使用哪個(gè)字段按時(shí)間過濾日志數(shù)據(jù),在下拉列表中,選擇@timestamp
字段,然后點(diǎn)擊?創(chuàng)建索引模式
,創(chuàng)建完成后,點(diǎn)擊左側(cè)導(dǎo)航菜單中的?Discover
,然后就可以看到一些直方圖和最近采集到的日志數(shù)據(jù)了:
現(xiàn)在的數(shù)據(jù)就是上面 Counter 應(yīng)用的日志,如果還有其他的應(yīng)用,我們也可以篩選過濾:
我們也可以通過其他元數(shù)據(jù)來過濾日志數(shù)據(jù),比如您可以單擊任何日志條目以查看其他元數(shù)據(jù),如容器名稱,Kubernetes 節(jié)點(diǎn),命名空間等。
安裝 Kafka?
對于大規(guī)模集群來說,日志數(shù)據(jù)量是非常巨大的,如果直接通過 Fluentd 將日志打入 Elasticsearch,對 ES 來說壓力是非常巨大的,我們可以在中間加一層消息中間件來緩解 ES 的壓力,一般情況下我們會(huì)使用 Kafka,然后可以直接使用?kafka-connect-elasticsearch
?這樣的工具將數(shù)據(jù)直接打入 ES,也可以在加一層 Logstash 去消費(fèi) Kafka 的數(shù)據(jù),然后通過 Logstash 把數(shù)據(jù)存入 ES,這里我們來使用 Logstash 這種模式來對日志收集進(jìn)行優(yōu)化。
首先在 Kubernetes 集群中安裝 Kafka,同樣這里使用 Helm 進(jìn)行安裝:
$ helm repo add bitnami https://charts.bitnami.com/bitnami
$ helm repo update
首先使用?helm pull
?拉取 Chart 并解壓:
$ helm pull bitnami/kafka --untar --version 17.2.3
$ cd kafka
這里面我們指定使用一個(gè)?StorageClass
?來提供持久化存儲(chǔ),在 Chart 目錄下面創(chuàng)建用于安裝的 values 文件:
# values-prod.yaml
## @section Persistence parameters
persistence:
enabled: true
storageClass: 'local-path'
accessModes:
- ReadWriteOnce
size: 8Gi
mountPath: /bitnami/kafka
# 配置zk volumes
zookeeper:
enabled: true
persistence:
enabled: true
storageClass: 'local-path'
accessModes:
- ReadWriteOnce
size: 8Gi
直接使用上面的 values 文件安裝 kafka:
$ helm upgrade --install kafka -f values-prod.yaml --namespace logging .
Release "kafka" does not exist. Installing it now.
NAME: kafka
LAST DEPLOYED: Thu Jun 9 14:02:01 2022
NAMESPACE: logging
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
CHART NAME: kafka
CHART VERSION: 17.2.3
APP VERSION: 3.2.0
** Please be patient while the chart is being deployed **
Kafka can be accessed by consumers via port 9092 on the following DNS name from within your cluster:
kafka.logging.svc.cluster.local
Each Kafka broker can be accessed by producers via port 9092 on the following DNS name(s) from within your cluster:
kafka-0.kafka-headless.logging.svc.cluster.local:9092
To create a pod that you can use as a Kafka client run the following commands:
kubectl run kafka-client --restart='Never' --image docker.io/bitnami/kafka:3.2.0-debian-10-r4 --namespace logging --command -- sleep infinity
kubectl exec --tty -i kafka-client --namespace logging -- bash
PRODUCER:
kafka-console-producer.sh \
--broker-list kafka-0.kafka-headless.logging.svc.cluster.local:9092 \
--topic test
CONSUMER:
kafka-console-consumer.sh \
--bootstrap-server kafka.logging.svc.cluster.local:9092 \
--topic test \
--from-beginning
安裝完成后我們可以使用上面的提示來檢查 Kafka 是否正常運(yùn)行:
$ kubectl get pods -n logging -l app.kubernetes.io/instance=kafka
kafka-0 1/1 Running 0 7m58s
kafka-zookeeper-0 1/1 Running 0 7m58s
用下面的命令創(chuàng)建一個(gè) Kafka 的測試客戶端 Pod:
$ kubectl run kafka-client --restart='Never' --image docker.io/bitnami/kafka:3.2.0-debian-10-r4 --namespace logging --command -- sleep infinity
pod/kafka-client created
然后啟動(dòng)一個(gè)終端進(jìn)入容器內(nèi)部生產(chǎn)消息:
# 生產(chǎn)者
$ kubectl exec --tty -i kafka-client --namespace logging -- bash
I have no name!@kafka-client:/$ kafka-console-producer.sh --broker-list kafka-0.kafka-headless.logging.svc.cluster.local:9092 --topic test
>hello kafka on k8s
>
啟動(dòng)另外一個(gè)終端進(jìn)入容器內(nèi)部消費(fèi)消息:
# 消費(fèi)者
$ kubectl exec --tty -i kafka-client --namespace logging -- bash
I have no name!@kafka-client:/$ kafka-console-consumer.sh --bootstrap-server kafka.logging.svc.cluster.local:9092 --topic test --from-beginning
hello kafka on k8s
如果在消費(fèi)端看到了生產(chǎn)的消息數(shù)據(jù)證明我們的 Kafka 已經(jīng)運(yùn)行成功了。
Fluentd 配置 Kafka?
現(xiàn)在有了 Kafka,我們就可以將 Fluentd 的日志數(shù)據(jù)輸出到 Kafka 了,只需要將 Fluentd 配置中的?<match>
?更改為使用 Kafka 插件即可,但是在 Fluentd 中輸出到 Kafka,需要使用到?fluent-plugin-kafka
?插件,所以需要我們自定義下 Docker 鏡像,最簡單的做法就是在上面 Fluentd 鏡像的基礎(chǔ)上新增 kafka 插件即可,Dockerfile 文件如下所示:
FROM quay.io/fluentd_elasticsearch/fluentd:v3.4.0
RUN echo "source 'https://mirrors.tuna.tsinghua.edu.cn/rubygems/'" > Gemfile && gem install bundler
RUN gem install fluent-plugin-kafka -v 0.17.5 --no-document
使用上面的?Dockerfile
?文件構(gòu)建一個(gè) Docker 鏡像即可,我這里構(gòu)建過后的鏡像名為?cnych/fluentd-kafka:v0.17.5
。接下來替換 Fluentd 的 Configmap 對象中的?<match>
?部分,如下所示:
# fluentd-configmap.yaml
kind: ConfigMap
apiVersion: v1
metadata:
name: fluentd-conf
namespace: logging
data:
......
output.conf: |-
<match **>
@id kafka
@type kafka2
@log_level info
# list of seed brokers
brokers kafka-0.kafka-headless.logging.svc.cluster.local:9092
use_event_time true
# topic settings
topic_key k8slog
default_topic messages # 注意,kafka中消費(fèi)使用的是這個(gè)topic
# buffer settings
<buffer k8slog>
@type file
path /var/log/td-agent/buffer/td
flush_interval 3s
</buffer>
# data type settings
<format>
@type json
</format>
# producer settings
required_acks -1
compression_codec gzip
</match>
然后替換運(yùn)行的 Fluentd 鏡像:
# fluentd-daemonset.yaml
image: cnych/fluentd-kafka:v0.17.5
直接更新 Fluentd 的 Configmap 與 DaemonSet 資源對象即可:
$ kubectl apply -f fluentd-configmap.yaml
$ kubectl apply -f fluentd-daemonset.yaml
更新成功后我們可以使用上面的測試 Kafka 客戶端來驗(yàn)證是否有日志數(shù)據(jù):
$ kubectl exec --tty -i kafka-client --namespace logging -- bash
I have no name!@kafka-client:/$ kafka-console-consumer.sh --bootstrap-server kafka.logging.svc.cluster.local:9092 --topic messages --from-beginning
{"stream":"stdout","docker":{},"kubernetes":{"container_name":"count","namespace_name":"default","pod_name":"counter","container_image":"busybox:latest","host":"node1","labels":{"logging":"true"}},"message":"43883: Tue Apr 27 12:16:30 UTC 2021\n"}
......
安裝 Logstash?
雖然數(shù)據(jù)從 Kafka 到 Elasticsearch 的方式多種多樣,比如可以使用?Kafka Connect Elasticsearch Connector?來實(shí)現(xiàn),我們這里還是采用更加流行的 `Logstash`` 方案,上面我們已經(jīng)將日志從 Fluentd 采集輸出到 Kafka 中去了,接下來我們使用 Logstash 來連接 Kafka 與 Elasticsearch 間的日志數(shù)據(jù)。
首先使用?helm pull
?拉取 Chart 并解壓:
$ helm pull elastic/logstash --untar --version 7.17.3
$ cd logstash
同樣在 Chart 根目錄下面創(chuàng)建用于安裝的 Values 文件,如下所示:
# values-prod.yaml
fullnameOverride: logstash
persistence:
enabled: true
logstashConfig:
logstash.yml: |
http.host: 0.0.0.0
# 如果啟用了xpack,需要做如下配置
xpack.monitoring.enabled: true
xpack.monitoring.elasticsearch.hosts: ["http://elasticsearch-client:9200"]
xpack.monitoring.elasticsearch.username: "elastic"
xpack.monitoring.elasticsearch.password: "ydzsio321"
# 要注意下格式
logstashPipeline:
logstash.conf: |
input { kafka { bootstrap_servers => "kafka-0.kafka-headless.logging.svc.cluster.local:9092" codec => json consumer_threads => 3 topics => ["messages"] } }
filter {} # 過濾配置(比如可以刪除key、添加geoip等等)
output { elasticsearch { hosts => [ "elasticsearch-client:9200" ] user => "elastic" password => "ydzsio321" index => "logstash-k8s-%{+YYYY.MM.dd}" } stdout { codec => rubydebug } }
volumeClaimTemplate:
accessModes: ['ReadWriteOnce']
storageClassName: nfs-storage
resources:
requests:
storage: 1Gi
其中最重要的就是通過?logstashPipeline
?配置 logstash 數(shù)據(jù)流的處理配置,通過?input
?指定日志源 kafka 的配置,通過?output
?輸出到 Elasticsearch,同樣直接使用上面的 Values 文件安裝 logstash 即可:
$ helm upgrade --install logstash -f values-prod.yaml --namespace logging .
Release "logstash" does not exist. Installing it now.
NAME: logstash
LAST DEPLOYED: Thu Jun 9 15:02:49 2022
NAMESPACE: logging
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
1. Watch all cluster members come up.
$ kubectl get pods --namespace=logging -l app=logstash -w
安裝啟動(dòng)完成后可以查看 logstash 的日志:
$ logstash kubectl get pods --namespace=logging -l app=logstash
NAME READY STATUS RESTARTS AGE
logstash-0 1/1 Running 0 2m8s
$ kubectl logs -f logstash-0 -n logging
......
{
"@version" => "1",
"stream" => "stdout",
"@timestamp" => 2022-06-09T07:09:16.889Z,
"message" => "4672: Thu Jun 9 07:09:15 UTC 2022",
"kubernetes" => {
"container_image" => "docker.io/library/busybox:latest",
"container_name" => "count",
"labels" => {
"logging" => "true"
},
"pod_name" => "counter",
"namespace_name" => "default",
"pod_ip" => "10.244.2.118",
"host" => "node2",
"namespace_labels" => {
"kubernetes_io/metadata_name" => "default"
}
},
"docker" => {}
}
由于我們啟用了 debug 日志調(diào)試,所以我們可以在 logstash 的日志中看到我們采集的日志消息,到這里證明我們的日志數(shù)據(jù)就獲取成功了。
現(xiàn)在我們可以登錄到 Kibana 可以看到有如下所示的索引數(shù)據(jù)了:
然后同樣創(chuàng)建索引模式,匹配上面的索引即可:
創(chuàng)建完成后就可以前往發(fā)現(xiàn)頁面過濾日志數(shù)據(jù)了:
到這里我們就實(shí)現(xiàn)了一個(gè)使用?Fluentd+Kafka+Logstash+Elasticsearch+Kibana
?的 Kubernetes 日志收集工具棧,這里我們完整的 Pod 信息如下所示:
$ kubectl get pods -n logging
NAME READY STATUS RESTARTS AGE
elasticsearch-client-0 1/1 Running 0 128m
elasticsearch-data-0 1/1 Running 0 128m
elasticsearch-master-0 1/1 Running 0 128m
fluentd-6k52h 1/1 Running 0 61m
fluentd-cw72c 1/1 Running 0 61m
fluentd-dn4hs 1/1 Running 0 61m
kafka-0 1/1 Running 3 134m
kafka-client 1/1 Running 0 125m
kafka-zookeeper-0 1/1 Running 0 134m
kibana-kibana-66f97964b-qqjgg 1/1 Running 0 128m
logstash-0 1/1 Running 0 13m
當(dāng)然在實(shí)際的工作項(xiàng)目中還需要我們根據(jù)實(shí)際的業(yè)務(wù)場景來進(jìn)行參數(shù)性能調(diào)優(yōu)以及高可用等設(shè)置,以達(dá)到系統(tǒng)的最優(yōu)性能。
上面我們在配置?logstash
?的時(shí)候是將日志輸出到?"logstash-k8s-%{+YYYY.MM.dd}"
?這個(gè)索引模式的,可能有的場景下只通過日期去區(qū)分索引不是很合理,那么我們可以根據(jù)自己的需求去修改索引名稱,比如可以根據(jù)我們的服務(wù)名稱來進(jìn)行區(qū)分,那么這個(gè)服務(wù)名稱可以怎么來定義呢?可以是 Pod 的名稱或者通過 label 標(biāo)簽去指定,比如我們這里去做一個(gè)規(guī)范,要求需要收集日志的 Pod 除了需要添加?logging: true
?這個(gè)標(biāo)簽之外,還需要添加一個(gè)?logIndex: <索引名>
?的標(biāo)簽。
比如重新更新我們測試的 counter 應(yīng)用:
apiVersion: v1
kind: Pod
metadata:
name: counter
labels:
logging: 'true' # 一定要具有該標(biāo)簽才會(huì)被采集
logIndex: 'test' # 指定索引名稱
spec:
containers:
- name: count
image: busybox
args:
[
/bin/sh,
-c,
'i=0; while true; do echo "$i: $(date)"; i=$((i+1)); sleep 1; done',
]
然后重新更新 logstash 的配置,修改 values 配置:
# ......
logstashPipeline:
logstash.conf: |
input { kafka { bootstrap_servers => "kafka-0.kafka-headless.logging.svc.cluster.local:9092" codec => json consumer_threads => 3 topics => ["messages"] } }
filter {} # 過濾配置(比如可以刪除key、添加geoip等等)
output { elasticsearch { hosts => [ "elasticsearch-client:9200" ] user => "elastic" password => "ydzsio321" index => "k8s-%{[kubernetes][labels][logIndex]}-%{+YYYY.MM.dd}" } stdout { codec => rubydebug } }
# ......
使用上面的 values 值更新 logstash,正常更新后上面的 counter 這個(gè) Pod 日志會(huì)輸出到一個(gè)名為?k8s-test-2022.06.09
?的索引去。
文章來源:http://www.zghlxwxcb.cn/news/detail-757186.html
這樣我們就實(shí)現(xiàn)了自定義索引名稱,當(dāng)然你也可以使用 Pod 名稱、容器名稱、命名空間名稱來作為索引的名稱,這完全取決于你自己的需求。文章來源地址http://www.zghlxwxcb.cn/news/detail-757186.html
到了這里,關(guān)于k8s搭建EFK日志系統(tǒng)的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!