filebeat收集kubernets日志到ES集群


Kubernetes中部署ELK Stack日志收集平台

1 、ELK概念

ELK是Elasticsearch、Logstash、Kibana三大開源框架首字母大寫簡稱。市面上也被成為Elastic Stack。其中:

Elasticsearch是一個基於Lucene、分布式、通過Restful方式進行交互的近實時搜索平台框架。像類似百度、谷歌這種大數據全文搜索引擎的場景都可以使用Elasticsearch作為底層支持框架,可見Elasticsearch提供的搜索能力確實強大,市面上很多時候我們簡稱Elasticsearch為es。官方網站:https://www.elastic.co/cn/products/  ;

 

Logstash是ELK的中央數據流引擎,用於從不同目標(文件/數據存儲/MQ)收集的不同格式數據,經過過濾后支持輸出到不同目的地(文件/MQ/redis/elasticsearch/kafka等);

 

Kibana可以將elasticsearch的數據通過友好的頁面展示出來,提供實時分析的功能。 通過上面對ELK簡單的介紹,我們知道了ELK字面意義包含的每個開源框架的功能。市面上很多開發只要提到ELK能夠一致說出它是一個日志分析架構技術棧總稱,但實際上ELK不僅僅適用於日志分析,它還可以支持其它任何數據分析和收集的場景,日志分析和收集只是更具有代表性。並非唯一性。我們本教程主要也是圍繞通過ELK如何搭建一個生產級的日志分析平台來講解ELK的使用;

2、收集日志的對象

(1)、k8s系統組件日志

(2)、k8s部署應用中的日志

3、日志采集方案

采集流程:

使用ELK+Filebeat架構,還需要明確Filebeat采集K8S集群日志的方式。

方案一:Node上部署一個日志收集程序

 

 

使用DaemonSet的方式去給每一個node上部署日志收集程序logging-agent 然后使用這個agent對本node節點上的/var/log和/var/lib/docker/containers/兩個目錄下的日志進行采集 或者把Pod中容器日志目錄掛載到宿主機統一目錄上,這樣進行收集

Docker默認的日志驅動(LogDriver)是json-driver,其會將日志以JSON文件的方式存儲。所有容器輸出到控制台的日志,都會以*-json.log的命名方式保存在/var/lib/docker/containers/目錄下。

方案二:Pod中附加專用日志收集的容器

 

 

 

每個運行應用程序的Pod中增加一個日志收集容器,使用emtyDir共享日志目錄讓日志收集程序讀取到。

方案三:應用程序直接推送日志

 

 

 

這個方案需要開發在代碼中修改直接把應用程序直接推送到遠程的存儲上,不再輸入出控制台或者本地文件了,使用不太多

 

4、方案對比:

方式

優勢

缺點

方案一:Node上部署一個日志收集程序

每個Node僅需部署一個日志收集程序,資源消耗少,對應用無侵入

應用程序日志需要寫到標准輸出和標准錯誤輸出,不支持多行日志

方案二:Pod中附加專用日志收集的容器

低耦合,擴展性強,方便和升級

每個Pod啟動一個日志收集代理,增加資源消耗,並增加運維維護成本

方案三:應用程序直接推送日志

無需額外組件

侵入應用,增加應用復雜度

 

相對來說,方式1在業界使用更為廣泛,並且官方也更為推薦。因此,最終我們采用ELK+Filebeat架構,並基於方式1,如下:

 

 

 (我這里直接把日志導入到ES集群,沒有用到kafka和logstash)

 

5、 K8S中日志采集應該注意的問題

問題1: 一個K8S集群我們需要收集哪些日志?

這里只是以主要收集日志為例:

  • K8S系統的組件日志
  • K8S Cluster里面部署的應用程序日志

  -標准輸出   -日志文件

問題2: 我們需要收集的日志在哪里,如何去收集當下比較常用的runtime?

docker和containerd的容器日志及相關參數

對比項

Docker

Containerd

存儲路徑

docker作為k8s容器運行時的情況下,容器日志的落盤由docker來完成, 默認保存在/var/lib/docker/containers/$CONTAINERID目錄下。kubelet會在/var/log/pods和/var/log/containers下面建立軟鏈接,指向/var/lib/docker/containers/$CONTAINERID目錄下的容器日志文件

containerd作為k8s容器運行時的情況下, 容器日志的落盤由kubelet來完成,保存到/var/log/pods/$CONTAINER_NAME目錄下,同時在/var/log/containers目錄下創建軟鏈接,指向日志文件

配置參數

在docker配置文件中指定: "log-driver": "json-file", "log-opts": {"max-size": "100m","max-file": "5"}

方法一:在kubelet參數中指定:   --container-log-max-files=5 --container-log-max-size="100Mi"

方法二:在KubeletConfiguration中指定:     "containerLogMaxSize": "100Mi",     "containerLogMaxFiles": 5

把容器日志保存到數據盤

把數據盤掛載到"data-root"(缺省是/data/var/lib/docker)即可

創建一個軟鏈接/var/log/pods指向數據盤掛載點下的某個目錄(ln -s /data/var/log/pods /var/log/)


無論k8s使用哪種容器運行時,最終的日志都是讀取的xxx-json.log,是由容器以json格式stdout輸出的,了解這些后我們得到了統一的日志收集規則:

 

統一目錄 :/var/log/containers

統一的輸出方式:stdout

統一的日志格式:json 

6、部署

(1)環境

kubernets平台使用kubeadm創建

ES集群是獨立三台服務器創建的ES集群(參見:https://www.cnblogs.com/xiaoyou2018/p/13754943.html)

192.168.1.194

192.168.1.195

192.168.1.198

(2)部署filebeat收集kubernets的test-meeu空間的日志

filebeat.yml  (注意yml格式,前后都不要有多的tab和空格)

獲取kubernets的test-xx這個空間的日志

apiVersion: v1
kind: ConfigMap
metadata:
  name: filebeat-config
  namespace: kube-system
  labels:
    k8s-app: filebeat
data:
  filebeat.yml: |-
    filebeat.inputs:
    - type: container
        multiline.type: pattern
        multiline.pattern: '^\d{4}-\d{2}-\d{2}' #把不以時間開頭的日志,歸結為一行;示例“2021-12-21”
        multiline.negate: true
        multiline.match: after
      enabled: true
      paths:
      - /var/log/containers/*_test-xx_*log #需要采集的日志的目錄
      fields:
        namespace: test-xx #采集的K8S空間名稱
        env: dev
        k8s: cluster-dev
      processors: #test-meeu的“收集者”的屬性設置
        - add_kubernetes_metadata: # 增加kubernetes的屬性
            host: ${NODE_NAME}
            matchers:
            - logs_path:
                logs_path: "/var/log/containers/"
    processors: #全局“收集者”的屬性設置
      - add_cloud_metadata: # 增加cloud屬性
      - add_host_metadata: # 增加k8s node節點屬性
      - dissect: #從某個字段里(默認message)取值,按照tokenizer定義的格式 拆分(切割)數據,並輸出到target_prefix 字段里,默認是dissect
          when: 
            or:
              - contains:
                  message: "  INFO"
              - contains:
                  message: "  WARN"
          tokenizer: "%{} %{}  %{loglevel} %{}"
          field: "message"
          target_prefix: ""
          trim_values: "all"
 - dissect: #參考https://www.elastic.co/guide/en/beats/filebeat/current/dissect.html when: or: - contains: message: " ERROR" - contains: message: " DEBUG" tokenizer: "%{} %{} %{loglevel} %{}" field: "message" target_prefix: "" trim_values: "all"
      - drop_fields: #去除掉某些字段
          fields: ["host.os.family","_id","_index","_score","_type","agent.ephemeral_id","agent.hostname","agent.id","agent.name","agent.type","agent.version","ecs.version","host.architecture","host.containerized","host.hostname","host.id","host.ip","host.mac","host.name","host.os.codename","host.os.kernel","host.os.name","host.os.platform","host.os.type","host.os.version","input.type","kubernetes.labels.app","kubernetes.namespace_labels.name","kubernetes.node.labels.beta_kubernetes_io/arch","kubernetes.node.labels.beta_kubernetes_io/os","kubernetes.node.labels.kubernetes_io/arch","kubernetes.node.labels.kubernetes_io/hostname","kubernetes.node.labels.kubernetes_io/os","kubernetes.node.uid","log.offset","fields.env","fields.k8s","fields.namespace","log.file.path","kubernetes.namespace_uid","container.id","container.image.name","container.runtime","kubernetes.labels.pod-template-hash","kubernetes.labels.timestamp","kubernetes.node.hostname","kubernetes.replicaset.name","kubernetes.node.labels.scene"]      
 cloud.id: ${ELASTIC_CLOUD_ID} cloud.auth: ${ELASTIC_CLOUD_AUTH}
    setup.template.settings: #設置索引3主分片和0副本(索引自動生成,格式是 "filebeat-%{[beat.version]}-%{+yyyy.MM.dd}"(例如 "filebeat-7.15.2-2021.12.17"))
      index.number_of_shards: 3
      index.number_of_replicas: 0
    setup.template.name: "filebeat"
    setup.template.pattern: "filebeat*"
    setup.ilm.enabled: false
    output.elasticsearch: #輸出到ES集群
 hosts: ["192.168.1.194:9200","192.168.1.195:9200","192.168.1.198:9200"] username: "elastic" password: "5yKsAQ4hgbBo0jxxxx"
    setup.kibana:
      host: '192.168.1.194:5601'
    setup.dashboards.enabled: true
    setup.template.enabled: true
---
# Source: filebeat/templates/filebeat-service-account.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: filebeat
  namespace: kube-system
  labels:
    k8s-app: filebeat

---
# Source: filebeat/templates/filebeat-role.yaml(RBAC 權限)
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
  name: filebeat
  labels:
    k8s-app: filebeat
rules:
- apiGroups: [""] # "" indicates the core API group
  resources:
 - namespaces - pods - nodes
  verbs:
  - get
  - watch
  - list

---
# Source: filebeat/templates/filebeat-role-binding.yaml(RBAC 權限)
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: filebeat
subjects:
- kind: ServiceAccount
  name: filebeat
  namespace: kube-system
roleRef:
  kind: ClusterRole
  name: filebeat
  apiGroup: rbac.authorization.k8s.io
---
# Source: filebeat/templates/filebeat-daemonset.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: filebeat
  namespace: kube-system
  labels:
    k8s-app: filebeat
spec:
  selector:
    matchLabels:
      k8s-app: filebeat
  template:
    metadata:
      labels:
        k8s-app: filebeat
    spec:
      serviceAccountName: filebeat
      terminationGracePeriodSeconds: 30
      hostNetwork: true
      dnsPolicy: ClusterFirstWithHostNet
      containers:
      - name: filebeat
        image: docker.elastic.co/beats/filebeat:7.15.2
        args: [
          "-c", "/etc/filebeat.yml",
          "-e",
        ]
        env:
        - name: ELASTICSEARCH_HOST
          value: "192.168.1.194" # 指定其中一個ES的地址
        - name: ELASTICSEARCH_PORT
          value: "9200"
 - name: ELASTICSEARCH_USERNAME value: elastic - name: ELASTICSEARCH_PASSWORD value: 5yKsAQ4hgbBo0juxxxx - name: ELASTIC_CLOUD_ID value: - name: ELASTIC_CLOUD_AUTH value:
        - name: NODE_NAME
          valueFrom:
            fieldRef:
              fieldPath: spec.nodeName
        securityContext:
          runAsUser: 0
          # If using Red Hat OpenShift uncomment this:
          #privileged: true
        resources:
          limits:
            memory: 200Mi
          requests:
            cpu: 100m
            memory: 100Mi
        volumeMounts:
        - name: config #掛載的是filebeat的配置文件
          mountPath: /etc/filebeat.yml
          readOnly: true
          subPath: filebeat.yml
        - name: data ##持久化filebeat數據到宿主機上
          mountPath: /usr/share/filebeat/data
        - name: varlibdockercontainers #這里主要是把宿主機上的源日志目錄掛載到filebeat容器中
          mountPath: /var/lib/docker/containers
          readOnly: true
        - name: varlog #這里主要是把宿主機上/var/log/pods和/var/log/containers的軟鏈接掛載到filebeat容器中
          mountPath: /var/log
          readOnly: true
        - name: timezone
          mountPath: /etc/localtime
      volumes:
      - name: config
        configMap:
          defaultMode: 0600
          name: filebeat-config
      - name: varlibdockercontainers
        hostPath:
          path: /var/lib/docker/containers
      - name: varlog
        hostPath:
          path: /var/log
      # data folder stores a registry of read status for all files, so we don't send everything again on a Filebeat pod restart
      - name: data
        hostPath:
          path: /data/filebeat-data
          type: DirectoryOrCreate
      - name: timezone
        hostPath:
          path: /etc/localtime
      tolerations: #加入容忍能夠調度到每一個節點
      - effect: NoSchedule
        operator: Exists

 

(3)設置索引的生命周期

設置日志保留30天

 

 

展示

 

 日志格式

 

 

 

 參考:

https://blog.csdn.net/qq_27818541/article/details/108229185

https://www.elastic.co/guide/en/beats/filebeat/current/decode-json-fields.html

https://www.elastic.co/guide/en/beats/filebeat/current/defining-processors.html

https://www.coder.work/article/7399194


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM