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
應該設置為2。
首先創建一個名為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
字段
最后顯示: