搭建EFK日誌系統
Elasticsearch
是一個實時的、分散式的可擴充套件的搜尋引擎,允許進行全文、結構化搜尋,它通常用於索引和搜尋大量日誌資料,也可用於搜尋許多不同型別的文件。
Elasticsearch 通常與 Kibana
一起部署,Kibana 是 Elasticsearch 的一個功能強大的資料視覺化 Dashboard,Kibana 允許你通過 web 介面來瀏覽 Elasticsearch 日誌資料。
Fluentd
是一個流行的開源資料收集器,我們將在 Kubernetes 叢集節點上安裝 Fluentd,通過獲取容器日誌檔案、過濾和轉換日誌資料,然後將資料傳遞到 Elasticsearch 叢集,在該叢集中對其進行索引和儲存。
一、建立Elasticsearch叢集
kube-logging.yaml
apiVersion: v1
kind: Namespace
metadata:
name: logging
然後通過kubectl建立該namespace,建立名為logging的名稱空間
# kubectl create -f kube-logging.yaml namespace/logging created # kubectl get ns NAME STATUS AGE default Active 31d kube-node-lease Active 31d kube-public Active 31d kube-system Active 31d kubernetes-dashboard Active 28d logging Active 7s
使用3個Elasticsearch Pod來避免 高可用下多節點叢集中出現的“腦裂”問題,一個關鍵的是您應該設定引數discover.zen.minimum_master_nodes=N/2+1
,其中N
是 Elasticsearch 叢集中符合主節點的節點數,比如我們這裡3個節點,意味著N
首先建立一個名為elasticsearch的headless服務,新建檔案elasticearch-svc.yaml:
apiVersion: v1 kind: Service 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 svc -n logging NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE elasticsearch ClusterIP None <none> 9200/TCP,9300/TCP 7s
現在我們已經為 Pod 設定了無頭服務和一個穩定的域名.elasticsearch.logging.svc.cluster.local
,接下來我們通過 StatefulSet 來建立具體的 Elasticsearch 的 Pod 應用。
定義elasticsearch的配置檔案,elasticsearch-conf.yaml
apiVersion: v1 kind: ConfigMap metadata: name: elasticsearch namespace: logging data: elasticsearch.yml: | cluster.name: k8s-log node.name: "${POD_NAME}" network.host: 0.0.0.0 cluster.initial_master_nodes: ["es-cluster-0","es-cluster-1","es-cluster-2"] discovery.zen.ping.unicast.hosts: ["es-cluster-0.elasticsearch","es-cluster-1.elasticsearch","es-cluster-2.elasticsearch"] xpack.security.enabled: "false" bootstrap.system_call_filter: "false" discovery.zen.minimum_master_nodes: "2"
建立該configmap
# kubectl create -f elasticsearch-conf.yaml # kubectl get configmap elasticsearch -n logging -o yaml apiVersion: v1 data: elasticsearch.yml: | cluster.name: k8s-log node.name: "${POD_NAME}" network.host: 0.0.0.0 cluster.initial_master_nodes: ["es-cluster-0","es-cluster-1","es-cluster-2"] discovery.zen.ping.unicast.hosts: ["es-cluster-0.elasticsearch","es-cluster-1.elasticsearch","es-cluster-2.elasticsearch"] xpack.security.enabled: "false" bootstrap.system_call_filter: "false" discovery.zen.minimum_master_nodes: "2" kind: ConfigMap metadata: creationTimestamp: "2020-07-07T01:05:33Z" managedFields: - apiVersion: v1 fieldsType: FieldsV1 fieldsV1: f:data: .: {} f:elasticsearch.yml: {} manager: kubectl operation: Update time: "2020-07-07T01:05:33Z" name: elasticsearch namespace: logging resourceVersion: "5924749" selfLink: /api/v1/namespaces/logging/configmaps/elasticsearch uid: 2224da1f-78ac-47e7-bcda-814952bbb776
-
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。
Kubernetes StatefulSet 允許我們為 Pod 分配一個穩定的標識和持久化儲存,Elasticsearch 需要穩定的儲存來保證 Pod 在重新排程或者重啟後的資料依然不變,所以需要使用 StatefulSet 來管理 Pod。
新建名為 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: elasticsearch:7.5.0 imagePullPolicy: IfNotPresent 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: POD_NAME valueFrom: fieldRef: fieldPath: metadata.name - name: ES_JAVA_OPTS value: "-Xms512m -Xmx512m" volumeMounts: - name: elasticsearch-config mountPath: /usr/share/elasticsearch/config/elasticsearch.yml subPath: elasticsearch.yml volumes: - name: elasticsearch-config configMap: name: elasticsearch
-
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: registry.cn-hangzhou.aliyuncs.com/google_containers/busybox imagePullPolicy: IfNotPresent 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: registry.cn-hangzhou.aliyuncs.com/google_containers/busybox imagePullPolicy: IfNotPresent command: ['sysctl','-w','vm.max_map_count=262144'] securityContext: privileged: true - name: increase-fd-ulimit image: busybox command: ['sh','-c','ulimit -n 65535'] securityContext: privileged: true
第一個名為 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
命令增加開啟檔案描述符的最大數量的。
此外
現在我們已經定義了主應用容器和它之前執行的 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 物件,新建一個 elasticsearch-storageclass.yaml 的檔案,檔案內容如下:
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: es-data-db provisioner: kubernetes.io/glusterfs parameters: resturl: http://192.168.10.106:18080
最後,完整的 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: elasticsearch:7.5.0 imagePullPolicy: IfNotPresent 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: POD_NAME valueFrom: fieldRef: fieldPath: metadata.name - name: ES_JAVA_OPTS value: "-Xms512m -Xmx512m" volumeMounts: - name: elasticsearch-config mountPath: /usr/share/elasticsearch/config/elasticsearch.yml subPath: elasticsearch.yml volumes: - name: elasticsearch-config configMap: name: elasticsearch initContainers: - name: fix-permissions image: registry.cn-hangzhou.aliyuncs.com/google_containers/busybox imagePullPolicy: IfNotPresent 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: registry.cn-hangzhou.aliyuncs.com/google_containers/busybox imagePullPolicy: IfNotPresent command: ['sysctl','-w','vm.max_map_count=262144'] securityContext: privileged: true - name: increase-fd-ulimit image: busybox command: ['sh','-c','ulimit -n 65535'] securityContext: privileged: true volumeClaimTemplates: - metadata: name: data labels: app: elasticsearch spec: accessModes: [ "ReadWriteOnce" ] storageClassName: es-data-db resources: requests: storage: 2Gi
部署
# 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
檢視
# kubectl get sts -n logging NAME READY AGE es-cluster 3/3 7m37s # kubectl get pods -n logging NAME READY STATUS RESTARTS AGE es-cluster-0 1/1 Running 0 7m44s es-cluster-1 1/1 Running 0 6m20s es-cluster-2 1/1 Running 0 5m1s # kubectl get svc -n logging NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE elasticserch ClusterIP None <none> 9200/TCP,9300/TCP 3h1m
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 | more % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0{ "cluster_name" : "k8s-log", "cluster_uuid" : "iXCjUz9jS_2ndq1VHQhptg", "version" : 18, "state_uuid" : "BGVTBoDGTSmnM2BXdJVlbw", "master_node" : "aL-lsgOIQJ64EMP9T_IRqA", "blocks" : { }, "nodes" : { "aL-lsgOIQJ64EMP9T_IRqA" : { "name" : "es-cluster-0", "ephemeral_id" : "8TGAhf9xQ9id2yqImo7y9A", "transport_address" : "10.32.0.2:9300", "attributes" : { "ml.machine_memory" : "2983755776", "xpack.installed" : "true", "ml.max_open_jobs" : "20" } }, "NbVg-sSYQFuMx0gyyu0ugw" : { "name" : "es-cluster-2", "ephemeral_id" : "IGDXyo33S5GV779CJgl4fQ", "transport_address" : "10.38.0.3:9300", "attributes" : { "ml.machine_memory" : "2983759872", "ml.max_open_jobs" : "20", "xpack.installed" : "true" } }, "26cjOCdeSwiOIZaNP095Dw" : { "name" : "es-cluster-1", "ephemeral_id" : "RtSL9qqHQya_m2VAYkTJRA", "transport_address" : "10.34.0.1: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: selector: app: kibana type: NodePort ports: - port: 5601 --- 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: kibana:7.5.0 resources: limits: cpu: 1000m requests: cpu: 100m env: - name: ELASTICSEARCH_URL value: http://elasticsearch:9200 ports: - containerPort: 5601
建立
# kubectl create -f kibana.yaml # kubectl get svc -n logging NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kibana NodePort 10.97.159.197 <none> 5601:32092/TCP 15m
如果 Pod 已經是 Running 狀態了,證明應用已經部署成功了,然後可以通過 NodePort 來訪問 Kibana 這個服務,在瀏覽器中開啟http://<任意節點IP>:32092
即可,如果看到如下歡迎介面證明 Kibana 已經成功部署到了 Kubernetes叢集之中。
部署Fluentd
Fluentd
是一個高效的日誌聚合器,是用 Ruby 編寫的,並且可以很好地擴充套件。對於大部分企業來說,Fluentd 足夠高效並且消耗的資源相對較少,另外一個工具Fluent-bit
更輕量級,佔用資源更少,但是外掛相對 Fluentd 來說不夠豐富,所以整體來說,Fluentd 更加成熟,使用更加廣泛,所以我們這裡也同樣使用 Fluentd 來作為日誌收集工具。
工作原理
Fluentd 通過一組給定的資料來源抓取日誌資料,處理後(轉換成結構化的資料格式)將它們轉發給其他服務,比如 Elasticsearch、物件儲存等等。Fluentd 支援超過300個日誌儲存和分析服務,所以在這方面是非常靈活的。主要執行步驟如下:
-
首先 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 檔案,檔案內容如下:
(這個配置貌似沒效果,直接再daemonset中設定)
apiVersion: v1 kind: ConfigMap 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-docker @type systemd filters [{ "_SYSTEMD_UNIT": "docker.service" }] <storage> @type local persistent true </storage> read_from_head true tag docker </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 --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole 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" --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding 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: rbac.authorization.k8s.io --- 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: serviceAccount: fluentd-es containers: - name: fluentd-es #image: cnych/fluentd-elasticsearch:v2.0.4 image: fluent/fluentd-kubernetes-daemonset:v1.4.2-debian-elasticsearch-1.1 env: - name: FLUENTD_ARGS value: --no-supervisor -q - name: FLUENT_ELASTICSEARCH_HOST value: "elasticsearch.logging.svc.cluster.local" - name: FLUENT_ELASTICSEARCH_PORT value: "9200" - name: FLUENT_ELASTICSEARCH_SCHEME value: "http" - name: FLUENTD_SYSTEMD_CONF value: disable resources: limits: memory: 500Mi requests: memory: 100Mi cpu: 100m volumeMounts: - name: varlog mountPath: /var/log - name: varlibdockercontainers mountPath: /var/lib/docker/containers readOnly: true 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: /var/log - name: varlibdockercontainers hostPath: path: /var/lib/docker/containers
我們將上面建立的 fluentd-config 這個 ConfigMap 物件通過 volumes 掛載到了 Fluentd 容器中,另外為了能夠靈活控制哪些節點的日誌可以被收集,所以我們這裡還添加了一個 nodSelector 屬性:
nodeSelector: beta.kubernetes.io/fluentd-ds-ready: "true"
先給kubernetes叢集打標籤
# kubectl label nodes node1 beta.kubernetes.io/fluentd-ds-ready=true node/node1 labeled #類似所有節點打上label
另外由於我們的叢集使用的是 kubeadm 搭建的,預設情況下 master 節點有汙點,所以要想也收集 master 節點的日誌,則需要新增上容忍:
tolerations: - key: node-role.kubernetes.io/master operator: Exists effect: NoSchedule
建立flunetd
# 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-es created
啟動後檢視kibana,點選discover
如果建立的index無法儲存,總是要重新建立,建議重啟elasticsearch和kibana
# kubectl scale statefulset es-cluster -n logging --replicas=0 # kubectl scale deployment kibana -n logging --replicas=0 # kubectl scale statefulset es-cluster -n logging --replicas=3 # kubectl scale deployment kibana -n logging --replicas=1
新建index pattern: logstash-*, 時間過濾日誌資料,在下拉列表中,選擇@timestamp
欄位
最後顯示: