搭建 EFK 日志系統
大家介紹了 Kubernetes 集群中的幾種日志收集方案,Kubernetes 中比較流行的日志收集解決方案是 Elasticsearch、Fluentd 和 Kibana(EFK)技術棧,也是官方現在比較推薦的一種方案。
Elasticsearch
是一個實時的、分布式的可擴展的搜索引擎,允許進行全文、結構化搜索,它通常用於索引和搜索大量日志數據,也可用於搜索許多不同類型的文檔。
Elasticsearch 通常與 Kibana
一起部署,Kibana 是 Elasticsearch 的一個功能強大的數據可視化 Dashboard,Kibana 允許你通過 web 界面來瀏覽 Elasticsearch 日志數據。
Fluentd
是一個流行的開源數據收集器,我們將在 Kubernetes 集群節點上安裝 Fluentd,通過獲取容器日志文件、過濾和轉換日志數據,然后將數據傳遞到 Elasticsearch 集群,在該集群中對其進行索引和存儲。
我們先來配置啟動一個可擴展的 Elasticsearch 集群,然后在 Kubernetes 集群中創建一個 Kibana 應用,最后通過 DaemonSet 來運行 Fluentd,以便它在每個 Kubernetes 工作節點上都可以運行一個 Pod。
創建 Elasticsearch 集群
在創建 Elasticsearch 集群之前,我們先創建一個命名空間,我們將在其中安裝所有日志相關的資源對象。
新建一個 kube-logging.yaml 文件:
apiVersion: v1 kind: Namespace metadata: name: logging
然后通過 kubectl 創建該資源清單,創建一個名為 logging 的 namespace:
$ kubectl create -f kube-logging.yaml
namespace/logging created
$ kubectl get ns
NAME STATUS AGE
default Active 244d
istio-system Active 100d
kube-ops Active 179d
kube-public Active 244d
kube-system Active 244d
logging Active 4h
monitoring Active 35d
現在創建了一個命名空間來存放我們的日志相關資源,接下來可以部署 EFK 相關組件,首先開始部署一個3節點的 Elasticsearch 集群。
這里我們使用3個 Elasticsearch Pod 來避免高可用下多節點集群中出現的“腦裂”問題,當一個或多個節點無法與其他節點通信時會產生“腦裂”,可能會出現幾個主節點。
了解更多 Elasticsearch 集群腦裂問題,可以查看文檔https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-node.html#split-brain
一個關鍵點是您應該設置參數discover.zen.minimum_master_nodes=N/2+1
,其中N
是 Elasticsearch 集群中符合主節點的節點數,比如我們這里3個節點,意味着N
應該設置為2。這樣,如果一個節點暫時與集群斷開連接,則另外兩個節點可以選擇一個新的主節點,並且集群可以在最后一個節點嘗試重新加入時繼續運行,在擴展 Elasticsearch 集群時,一定要記住這個參數。
首先創建一個名為 elasticsearch 的無頭服務,新建文件 elasticsearch-svc.yaml,文件內容如下:
kind: Service apiVersion: v1 metadata: name: elasticsearch namespace: logging labels: app: elasticsearch spec: selector: app: elasticsearch clusterIP: None ports: - port: 9200 name: rest - port: 9300 name: inter-node
定義了一個名為 elasticsearch 的 Service,指定標簽app=elasticsearch
,當我們將 Elasticsearch StatefulSet 與此服務關聯時,服務將返回帶有標簽app=elasticsearch
的 Elasticsearch Pods 的 DNS A 記錄,然后設置clusterIP=None
,將該服務設置成無頭服務。最后,我們分別定義端口9200、9300,分別用於與 REST API 交互,以及用於節點間通信。
使用 kubectl 直接創建上面的服務資源對象:
$ kubectl create -f elasticsearch-svc.yaml
service/elasticsearch created
$ kubectl get services --namespace=logging Output NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE elasticsearch ClusterIP None <none> 9200/TCP,9300/TCP 26s
現在我們已經為 Pod 設置了無頭服務和一個穩定的域名.elasticsearch.logging.svc.cluster.local
,接下來我們通過 StatefulSet 來創建具體的 Elasticsearch 的 Pod 應用。
Kubernetes StatefulSet 允許我們為 Pod 分配一個穩定的標識和持久化存儲,Elasticsearch 需要穩定的存儲來保證 Pod 在重新調度或者重啟后的數據依然不變,所以需要使用 StatefulSet 來管理 Pod。
要了解更多關於 StaefulSet 的信息,可以查看官網關於 StatefulSet 的相關文檔:https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/。
新建名為 elasticsearch-statefulset.yaml 的資源清單文件,首先粘貼下面內容:
apiVersion: apps/v1 kind: StatefulSet metadata: name: es-cluster namespace: logging spec: serviceName: elasticsearch replicas: 3 selector: matchLabels: app: elasticsearch template: metadata: labels: app: elasticsearch
該內容中,我們定義了一個名為 es-cluster 的 StatefulSet 對象,然后定義serviceName=elasticsearch
和前面創建的 Service 相關聯,這可以確保使用以下 DNS 地址訪問 StatefulSet 中的每一個 Pod:es-cluster-[0,1,2].elasticsearch.logging.svc.cluster.local
,其中[0,1,2]對應於已分配的 Pod 序號。
然后指定3個副本,將 matchLabels 設置為app=elasticsearch
,所以 Pod 的模板部分.spec.template.metadata.lables
也必須包含app=elasticsearch
標簽。
然后定義 Pod 模板部分內容:
... spec: containers: - name: elasticsearch image: docker.elastic.co/elasticsearch/elasticsearch-oss:6.4.3 resources: limits: cpu: 1000m requests: cpu: 100m ports: - containerPort: 9200 name: rest protocol: TCP - containerPort: 9300 name: inter-node protocol: TCP volumeMounts: - name: data mountPath: /usr/share/elasticsearch/data env: - name: cluster.name value: k8s-logs - name: node.name valueFrom: fieldRef: fieldPath: metadata.name - name: discovery.zen.ping.unicast.hosts value: "es-cluster-0.elasticsearch,es-cluster-1.elasticsearch,es-cluster-2.elasticsearch" - name: discovery.zen.minimum_master_nodes value: "2" - name: ES_JAVA_OPTS value: "-Xms512m -Xmx512m"
該部分是定義 StatefulSet 中的 Pod,我們這里使用一個-oss
后綴的鏡像,該鏡像是 Elasticsearch 的開源版本,如果你想使用包含X-Pack
之類的版本,可以去掉該后綴。然后暴露了9200和9300兩個端口,注意名稱要和上面定義的 Service 保持一致。然后通過 volumeMount 聲明了數據持久化目錄,下面我們再來定義 VolumeClaims。最后就是我們在容器中設置的一些環境變量了:
- cluster.name:Elasticsearch 集群的名稱,我們這里命名成 k8s-logs。
- node.name:節點的名稱,通過
metadata.name
來獲取。這將解析為 es-cluster-[0,1,2],取決於節點的指定順序。 - discovery.zen.ping.unicast.hosts:此字段用於設置在 Elasticsearch 集群中節點相互連接的發現方法。我們使用 unicastdiscovery 方式,它為我們的集群指定了一個靜態主機列表。由於我們之前配置的無頭服務,我們的 Pod 具有唯一的 DNS 域
es-cluster-[0,1,2].elasticsearch.logging.svc.cluster.local
,因此我們相應地設置此變量。由於都在同一個 namespace 下面,所以我們可以將其縮短為es-cluster-[0,1,2].elasticsearch
。要了解有關 Elasticsearch 發現的更多信息,請參閱 Elasticsearch 官方文檔:https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-discovery.html。 - discovery.zen.minimum_master_nodes:我們將其設置為
(N/2) + 1
,N
是我們的群集中符合主節點的節點的數量。我們有3個 Elasticsearch 節點,因此我們將此值設置為2(向下舍入到最接近的整數)。要了解有關此參數的更多信息,請參閱官方 Elasticsearch 文檔:https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-node.html#split-brain。 - ES_JAVA_OPTS:這里我們設置為
-Xms512m -Xmx512m
,告訴JVM
使用512 MB
的最小和最大堆。您應該根據群集的資源可用性和需求調整這些參數。要了解更多信息,請參閱設置堆大小的相關文檔:https://www.elastic.co/guide/en/elasticsearch/reference/current/heap-size.html。
接下來添加關於 initContainer 的內容:
... initContainers: - name: fix-permissions image: busybox command: ["sh", "-c", "chown -R 1000:1000 /usr/share/elasticsearch/data"] securityContext: privileged: true volumeMounts: - name: data mountPath: /usr/share/elasticsearch/data - name: increase-vm-max-map image: busybox command: ["sysctl", "-w", "vm.max_map_count=262144"] securityContext: privileged: true - name: increase-fd-ulimit image: busybox command: ["sh", "-c", "ulimit -n 65536"] securityContext: privileged: true
這里我們定義了幾個在主應用程序之前運行的 Init 容器,這些初始容器按照定義的順序依次執行,執行完成后才會啟動主應用容器。
第一個名為 fix-permissions 的容器用來運行 chown 命令,將 Elasticsearch 數據目錄的用戶和組更改為1000:1000
(Elasticsearch 用戶的 UID)。因為默認情況下,Kubernetes 用 root 用戶掛載數據目錄,這會使得 Elasticsearch 無法方法該數據目錄,可以參考 Elasticsearch 生產中的一些默認注意事項相關文檔說明:https://www.elastic.co/guide/en/elasticsearch/reference/current/docker.html#_notes_for_production_use_and_defaults。
第二個名為 increase-vm-max-map 的容器用來增加操作系統對mmap
計數的限制,默認情況下該值可能太低,導致內存不足的錯誤,要了解更多關於該設置的信息,可以查看 Elasticsearch 官方文檔說明:https://www.elastic.co/guide/en/elasticsearch/reference/current/vm-max-map-count.html。
最后一個初始化容器是用來執行ulimit
命令增加打開文件描述符的最大數量的。
此外 Elastisearch Notes for Production Use 文檔還提到了由於性能原因最好禁用 swap,當然對於 Kubernetes 集群而言,最好也是禁用 swap 分區的。
現在我們已經定義了主應用容器和它之前運行的 Init Containers 來調整一些必要的系統參數,接下來我們可以添加數據目錄的持久化相關的配置,在 StatefulSet 中,使用 volumeClaimTemplates 來定義 volume 模板即可:
... volumeClaimTemplates: - metadata: name: data labels: app: elasticsearch spec: accessModes: [ "ReadWriteOnce" ] storageClassName: es-data-db resources: requests: storage: 50Gi
我們這里使用 volumeClaimTemplates 來定義持久化模板,Kubernetes 會使用它為 Pod 創建 PersistentVolume,設置訪問模式為ReadWriteOnce
,這意味着它只能被 mount 到單個節點上進行讀寫,然后最重要的是使用了一個名為 es-data-db 的 StorageClass 對象,所以我們需要提前創建該對象,我們這里使用的 NFS 作為存儲后端,所以需要安裝一個對應的 provisioner 驅動,前面關於 StorageClass 的課程中已經和大家介紹過方法,新建一個 elasticsearch-storageclass.yaml 的文件,文件內容如下:
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: es-data-db provisioner: fuseim.pri/ifs # 該值需要和 provisioner 配置的保持一致
最后,我們指定了每個 PersistentVolume 的大小為 50GB,我們可以根據自己的實際需要進行調整該值。最后,完整的 Elasticsearch StatefulSet 資源清單文件內容如下:
apiVersion: apps/v1 kind: StatefulSet metadata: name: es-cluster namespace: logging spec: serviceName: elasticsearch replicas: 3 selector: matchLabels: app: elasticsearch template: metadata: labels: app: elasticsearch spec: containers: - name: elasticsearch image: docker.elastic.co/elasticsearch/elasticsearch-oss:6.4.3 resources: limits: cpu: 1000m requests: cpu: 100m ports: - containerPort: 9200 name: rest protocol: TCP - containerPort: 9300 name: inter-node protocol: TCP volumeMounts: - name: data mountPath: /usr/share/elasticsearch/data env: - name: cluster.name value: k8s-logs - name: node.name valueFrom: fieldRef: fieldPath: metadata.name - name: discovery.zen.ping.unicast.hosts value: "es-cluster-0.elasticsearch,es-cluster-1.elasticsearch,es-cluster-2.elasticsearch" - name: discovery.zen.minimum_master_nodes value: "2" - name: ES_JAVA_OPTS value: "-Xms512m -Xmx512m" initContainers: - name: fix-permissions image: busybox command: ["sh", "-c", "chown -R 1000:1000 /usr/share/elasticsearch/data"] securityContext: privileged: true volumeMounts: - name: data mountPath: /usr/share/elasticsearch/data - name: increase-vm-max-map image: busybox command: ["sysctl", "-w", "vm.max_map_count=262144"] securityContext: privileged: true - name: increase-fd-ulimit image: busybox command: ["sh", "-c", "ulimit -n 65536"] securityContext: privileged: true volumeClaimTemplates: - metadata: name: data labels: app: elasticsearch spec: accessModes: [ "ReadWriteOnce" ] storageClassName: es-data-db resources: requests: storage: 100Gi
現在直接使用 kubectl 工具部署即可:
$ kubectl create -f elasticsearch-storageclass.yaml
storageclass.storage.k8s.io "es-data-db" created $ kubectl create -f elasticsearch-statefulset.yaml statefulset.apps/es-cluster created
添加成功后,可以看到 logging 命名空間下面的所有的資源對象:
$ kubectl get sts -n logging
NAME DESIRED CURRENT AGE
es-cluster 3 3 20h
$ kubectl get pods -n logging
NAME READY STATUS RESTARTS AGE
es-cluster-0 1/1 Running 0 20h
es-cluster-1 1/1 Running 0 20h
es-cluster-2 1/1 Running 0 20h
$ kubectl get svc -n logging
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE elasticsearch ClusterIP None <none> 9200/TCP,9300/TCP 20h
Pods 部署完成后,我們可以通過請求一個 REST API 來檢查 Elasticsearch 集群是否正常運行。使用下面的命令將本地端口9200轉發到 Elasticsearch 節點(如es-cluster-0)對應的端口:
$ kubectl port-forward es-cluster-0 9200:9200 --namespace=logging Forwarding from 127.0.0.1:9200 -> 9200 Forwarding from [::1]:9200 -> 9200
然后,在另外的終端窗口中,執行如下請求:
$ curl http://localhost:9200/_cluster/state?pretty
正常來說,應該會看到類似於如下的信息:
{ "cluster_name" : "k8s-logs", "compressed_size_in_bytes" : 348, "cluster_uuid" : "QD06dK7CQgids-GQZooNVw", "version" : 3, "state_uuid" : "mjNIWXAzQVuxNNOQ7xR-qg", "master_node" : "IdM5B7cUQWqFgIHXBp0JDg", "blocks" : { }, "nodes" : { "u7DoTpMmSCixOoictzHItA" : { "name" : "es-cluster-1", "ephemeral_id" : "ZlBflnXKRMC4RvEACHIVdg", "transport_address" : "10.244.4.191:9300", "attributes" : { } }, "IdM5B7cUQWqFgIHXBp0JDg" : { "name" : "es-cluster-0", "ephemeral_id" : "JTk1FDdFQuWbSFAtBxdxAQ", "transport_address" : "10.244.2.215:9300", "attributes" : { } }, "R8E7xcSUSbGbgrhAdyAKmQ" : { "name" : "es-cluster-2", "ephemeral_id" : "9wv6ke71Qqy9vk2LgJTqaA", "transport_address" : "10.244.40.4:9300", "attributes" : { } } }, ...
看到上面的信息就表明我們名為 k8s-logs 的 Elasticsearch 集群成功創建了3個節點:es-cluster-0,es-cluster-1,和es-cluster-2,當前主節點是 es-cluster-0。
創建 Kibana 服務
Elasticsearch 集群啟動成功了,接下來我們可以來部署 Kibana 服務,新建一個名為 kibana.yaml 的文件,對應的文件內容如下:
apiVersion: v1 kind: Service metadata: name: kibana namespace: logging labels: app: kibana spec: ports: - port: 5601 type: NodePort selector: app: kibana --- apiVersion: apps/v1 kind: Deployment metadata: name: kibana namespace: logging labels: app: kibana spec: selector: matchLabels: app: kibana template: metadata: labels: app: kibana spec: containers: - name: kibana image: docker.elastic.co/kibana/kibana-oss:6.4.3 resources: limits: cpu: 1000m requests: cpu: 100m env: - name: ELASTICSEARCH_URL value: http://elasticsearch:9200 ports: - containerPort: 5601
上面我們定義了兩個資源對象,一個 Service 和 Deployment,為了測試方便,我們將 Service 設置為了 NodePort 類型,Kibana Pod 中配置都比較簡單,唯一需要注意的是我們使用 ELASTICSEARCH_URL 這個環境變量來設置Elasticsearch 集群的端點和端口,直接使用 Kubernetes DNS 即可,此端點對應服務名稱為 elasticsearch,由於是一個 headless service,所以該域將解析為3個 Elasticsearch Pod 的 IP 地址列表。
配置完成后,直接使用 kubectl 工具創建:
$ kubectl create -f kibana.yaml
service/kibana created
deployment.apps/kibana created
創建完成后,可以查看 Kibana Pod 的運行狀態:
$ kubectl get pods --namespace=logging NAME READY STATUS RESTARTS AGE es-cluster-0 1/1 Running 0 20h es-cluster-1 1/1 Running 0 20h es-cluster-2 1/1 Running 0 20h kibana-7558d4dc4d-5mqdz 1/1 Running 0 20h $ kubectl get svc --namespace=logging NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE elasticsearch ClusterIP None <none> 9200/TCP,9300/TCP 20h kibana NodePort 10.105.208.253 <none> 5601:31816/TCP 20h
如果 Pod 已經是 Running 狀態了,證明應用已經部署成功了,然后可以通過 NodePort 來訪問 Kibana 這個服務,在瀏覽器中打開http://<任意節點IP>:31816
即可,如果看到如下歡迎界面證明 Kibana 已經成功部署到了 Kubernetes集群之中。
kibana welcome
部署 Fluentd
Fluentd
是一個高效的日志聚合器,是用 Ruby 編寫的,並且可以很好地擴展。對於大部分企業來說,Fluentd 足夠高效並且消耗的資源相對較少,另外一個工具Fluent-bit
更輕量級,占用資源更少,但是插件相對 Fluentd 來說不夠豐富,所以整體來說,Fluentd 更加成熟,使用更加廣泛,所以我們這里也同樣使用 Fluentd 來作為日志收集工具。
工作原理
Fluentd 通過一組給定的數據源抓取日志數據,處理后(轉換成結構化的數據格式)將它們轉發給其他服務,比如 Elasticsearch、對象存儲等等。Fluentd 支持超過300個日志存儲和分析服務,所以在這方面是非常靈活的。主要運行步驟如下:
- 首先 Fluentd 從多個日志源獲取數據
- 結構化並且標記這些數據
- 然后根據匹配的標簽將數據發送到多個目標服務去
fluentd 架構
配置
一般來說我們是通過一個配置文件來告訴 Fluentd 如何采集、處理數據的,下面簡單和大家介紹下 Fluentd 的配置方法。
日志源配置
比如我們這里為了收集 Kubernetes 節點上的所有容器日志,就需要做如下的日志源配置:
<source> @id fluentd-containers.log @type tail path /var/log/containers/*.log pos_file /var/log/fluentd-containers.log.pos time_format %Y-%m-%dT%H:%M:%S.%NZ tag raw.kubernetes.* format json read_from_head true </source>
上面配置部分參數說明如下:
- id:表示引用該日志源的唯一標識符,該標識可用於進一步過濾和路由結構化日志數據
- type:Fluentd 內置的指令,
tail
表示 Fluentd 從上次讀取的位置通過 tail 不斷獲取數據,另外一個是http
表示通過一個 GET 請求來收集數據。 - path:
tail
類型下的特定參數,告訴 Fluentd 采集/var/log/containers
目錄下的所有日志,這是 docker 在 Kubernetes 節點上用來存儲運行容器 stdout 輸出日志數據的目錄。 - pos_file:檢查點,如果 Fluentd 程序重新啟動了,它將使用此文件中的位置來恢復日志數據收集。
- tag:用來將日志源與目標或者過濾器匹配的自定義字符串,Fluentd 匹配源/目標標簽來路由日志數據。
路由配置
上面是日志源的配置,接下來看看如何將日志數據發送到 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:標識一個目標標簽,后面是一個匹配日志源的正則表達式,我們這里想要捕獲所有的日志並將它們發送給 Elasticsearch,所以需要配置成
**
。 - id:目標的一個唯一標識符。
- type:支持的輸出插件標識符,我們這里要輸出到 Elasticsearch,所以配置成 elasticsearch,這是 Fluentd 的一個內置插件。
- log_level:指定要捕獲的日志級別,我們這里配置成
info
,表示任何該級別或者該級別以上(INFO、WARNING、ERROR)的日志都將被路由到 Elsasticsearch。 - host/port:定義 Elasticsearch 的地址,也可以配置認證信息,我們的 Elasticsearch 不需要認證,所以這里直接指定 host 和 port 即可。
- logstash_format:Elasticsearch 服務對日志數據構建反向索引進行搜索,將 logstash_format 設置為
true
,Fluentd 將會以 logstash 格式來轉發結構化的日志數據。 - Buffer: Fluentd 允許在目標不可用時進行緩存,比如,如果網絡出現故障或者 Elasticsearch 不可用的時候。緩沖區配置也有助於降低磁盤的 IO。
安裝
要收集 Kubernetes 集群的日志,直接用 DasemonSet 控制器來部署 Fluentd 應用,這樣,它就可以從 Kubernetes 節點上采集日志,確保在集群中的每個節點上始終運行一個 Fluentd 容器。當然可以直接使用 Helm 來進行一鍵安裝,為了能夠了解更多實現細節,我們這里還是采用手動方法來進行安裝。
首先,我們通過 ConfigMap 對象來指定 Fluentd 配置文件,新建 fluentd-configmap.yaml 文件,文件內容如下:
kind: ConfigMap apiVersion: v1 metadata: name: fluentd-config namespace: logging labels: addonmanager.kubernetes.io/mode: Reconcile data: system.conf: |- <system> root_dir /tmp/fluentd-buffers/ </system> containers.input.conf: |- <source> @id fluentd-containers.log @type tail path /var/log/containers/*.log pos_file /var/log/es-containers.log.pos time_format %Y-%m-%dT%H:%M:%S.%NZ localtime tag raw.kubernetes.* format json read_from_head true </source> # Detect exceptions in the log output and forward them as one log entry. <match raw.kubernetes.**> @id raw.kubernetes @type detect_exceptions remove_tag_prefix raw message log stream stream multiline_flush_interval 5 max_bytes 500000 max_lines 1000 </match> system.input.conf: |- # Logs from systemd-journal for interesting services. <source> @id journald-docker @type systemd filters [{ "_SYSTEMD_UNIT": "docker.service" }] <storage> @type local persistent true </storage> read_from_head true tag docker </source> <source> @id journald-kubelet @type systemd filters [{ "_SYSTEMD_UNIT": "kubelet.service" }] <storage> @type local persistent true </storage> read_from_head true tag kubelet </source> forward.input.conf: |- # Takes the messages sent over TCP <source> @type forward </source> output.conf: |- # Enriches records with Kubernetes metadata <filter kubernetes.**> @type kubernetes_metadata </filter> <match **> @id elasticsearch @type elasticsearch @log_level info include_tag_key true host elasticsearch port 9200 logstash_format true 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 容器日志目錄以及 docker、kubelet 應用的日志的收集,收集到數據經過處理后發送到 elasticsearch:9200 服務。
然后新建一個 fluentd-daemonset.yaml 的文件,文件內容如下:
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-es namespace: logging labels: k8s-app: fluentd-es version: v2.0.4 kubernetes.io/cluster-service: "true" addonmanager.kubernetes.io/mode: Reconcile spec: selector: matchLabels: k8s-app: fluentd-es version: v2.0.4 template: metadata: labels: k8s-app: fluentd-es kubernetes.io/cluster-service: "true" version: v2.0.4 # This annotation ensures that fluentd does not get evicted if the node # supports critical pod annotation based priority scheme. # Note that this does not guarantee admission on the nodes (#40573). annotations: scheduler.alpha.kubernetes.io/critical-pod: '' spec: serviceAccountName: fluentd-es containers: - name: fluentd-es image: cnych/fluentd-elasticsearch:v2.0.4 env: - name: FLUENTD_ARGS value: --no-supervisor -q resources: limits: memory: 500Mi requests: cpu: 100m memory: 200Mi volumeMounts: - name: varlog mountPath: /var/log - name: varlibdockercontainers mountPath: /data/docker/containers readOnly: true - name: config-volume mountPath: /etc/fluent/config.d nodeSelector: beta.kubernetes.io/fluentd-ds-ready: "true" tolerations: - key: node-role.kubernetes.io/master operator: Exists effect: NoSchedule terminationGracePeriodSeconds: 30 volumes: - name: varlog hostPath: path