K8S 使用 SideCar 模式部署 Filebeat 收集容器日誌

徐似安然Aaron發表於2020-10-30

對於 K8S 內的容器日誌收集,業內一般有兩種常用的方式:

  • 使用 DaemonSet 在每臺 Node 上部署一個日誌收集容器,用於收集當前 Node 上所有容器掛載到宿主機目錄下的日誌
  • 使用 SideCar 模式將日誌收集容器與業務容器部署在同一個 Pod 中,只收集對應容器的日誌

這兩種方式各有優缺點。使用 DaemonSet 方式部署日誌收集服務,管理起來簡單,但是如果一個 Node 中執行了過多的 Pod,那麼日誌收集會存在效能瓶頸。使用 SideCar 模式可以更有針對性的收集容器的日誌,但是缺點是在執行了很多的業務時,SideCar 佔用的資源也會增加。同時這種方式也會出現跟業務耦合的問題。

在我們實踐 K8S 的過程中,結合當前業務的特點,最終選定了 SideCar 的方式,雖然佔用的資源會增加,但是基於後期大規模日誌收集穩定性的考慮,這些資源消耗是在承受範圍之內的。

而日誌收集的元件,經過長時間比對各種開源服務,選擇了 Filebeat。一個是因為在業務未上容器之前,就是使用的 Filebeat 來收集的日誌,在維護方面有很多的經驗。還有就是 Filebeat 可以處理一些日誌收集中出現的複雜情況,例如對於多行日誌的處理(堆疊日誌)。

下面對於整個實施步驟進行說明。

一、建立名稱空間

首先建立一個名稱空間,yaml 檔案內容如下:

---
apiVersion: v1
kind: Namespace
metadata:
  name: ns-smc-gateway
  labels:
    name: ns-smc-gateway

二、建立 Filebeat 配置檔案

由於是使用容器的方式執行 FIlebeat,所以需要使用 Configmap 建立一個 Filebeat 的配置檔案,然後通過卷掛載的方式掛載到 Filebeat 容器的指定目錄下。

建立 Configmap 的 yaml 檔案內容如下(注意名稱空間的配置,否則後面 Filebeat 無法掛載 Configmap,如果對於下面的配置有不清楚的地方,可以參考我的另一片博文:Filebeat根據不同的日誌設定不同的索引):

---
apiVersion: v1
kind: ConfigMap
metadata:
  name: filebeat-config
  namespace: ns-smc-gateway
  labels:
    k8s-app: filebeat
data:
  filebeat.yml: |-
    filebeat.idle_timeout: 2s
    filebeat.inputs:
    - type: log
      paths:
       - /opt/logs/app.log
      fields:
        type: app-log
      enabled: true
      backoff: 1s
      backoff_factor: 2
      close_inactive: 1h
      encoding: plain
      harvester_buffer_size: 262144
      max_backoff: 10s
      max_bytes: 10485760
      scan_frequency: 10s
      tail_lines: true
    - type: log
      paths:
       - /opt/logs/app.err
      fields:
        type: app-err-log
      enabled: true
      backoff: 1s
      backoff_factor: 2
      close_inactive: 1h
      encoding: plain
      harvester_buffer_size: 262144
      max_backoff: 10s
      max_bytes: 10485760
      scan_frequency: 10s
      tail_lines: true

    filebeat.name: filebeat-shiper
    filebeat.spool_zie: 50000
    output.elasticsearch:
      bulk_max_size: 8192
      hosts:
      - 10.16.12.206:30187
      - 10.16.12.207:30187
      - 10.16.12.208:30187
      - 10.16.13.214:30187
      - 10.16.13.215:30187
      index: smc-gateway-%{[fields.type]}-*
      indices:
        - index: smc-gateway-app-log-%{+yyyy.MM.dd}
          when.equals:
            fields.type: app-log
        - index: smc-gateway-app-err-log-%{+yyyy.MM.dd}
          when.equals:
            fields.type: app-err-log
      workers: 4
    processors:
    - drop_fields:
        fields:
        - agent.ephemeral_id
        - agent.hostname
        - agent.id
        - agent.type
        - agent.version
        - ecs.version
        - input.type
        - log.offset
        - version
    - decode_json_fields:
        fields:
        - message
        max_depth: 1
        overwrite_keys: true
    setup.ilm.enabled: false
    setup.template.name: smc-gateway-log
    setup.template.pattern: smc-gateway-*
    setup.template.overwrite: true
    setup.template.enabled: true

三、建立 Deployment

接下來使用 Deployment 控制器來部署 Pod,這個 Pod 中包含了業務容器和 Filebeat 服務容器。yaml 檔案內容如下:

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: smc-gateway
  namespace: ns-smc-gateway
  labels:
    app: smc-gateway
spec:
  replicas: 1
  selector:
    matchLabels:
      app: smc-gateway
  template:
    metadata:
      name: smc-gateway
      labels:
        app: smc-gateway
    spec:
      imagePullSecrets:
      - name: harbor-secret
      containers:
      - name: smc-gateway-for-test                         # 業務容器的名稱
        image: 10.16.12.204/smc-gateway/smc-gateway:1.1    # 業務容器映象的私服下載地址
        imagePullPolicy: Always
        env:                                               # 需要傳入到業務容器中的環境變數,在服務啟動的時候呼叫
          - name: data_center
            value: bx
          - name: server_mode
            value: test
        volumeMounts:                                      # 指定業務日誌在容器中輸出的目錄
        - name: logdata
          mountPath: /opt/logs

      - name: filebeat-for-smc-gateway                     # 指定 Filebeat 容器的名稱
        image: docker.elastic.co/beats/filebeat:7.3.0      # filebeat 映象下載地址,這裡使用的官方映象倉庫
        args: [                                            # 指定服務啟動時的引數
          "-c", "/opt/filebeat/filebeat.yml",              # 注意這裡,檔案的路徑和名稱要和 Configmap 傳入的路徑和名稱一致
          "-e",
        ]
        env:
        - name: POD_IP                    # 這裡是將 pod 的 IP 地址賦值給這個變數傳入容器中,便於後面 Filebeat 在日誌中新增自定義的欄位資訊
          valueFrom:
            fieldRef:
              apiVersion: v1
              fieldPath: status.podIP
        - name: pod_name                  # 這裡是將 pod 的名稱賦值給這個變數,便於後面 Filebeat 在日誌中新增自定義的欄位資訊
          valueFrom:
            fieldRef:
              apiVersion: v1
              fieldPath: metadata.name
        securityContext:                  # 這裡用於設定 Pod 的安全上下文
          runAsUser: 0                    # 指定容器內的服務以 ID 為 0 的使用者執行(也就是root)
        volumeMounts:
        - name: config                    # 指定 filebeat 配置檔案要掛載的路徑
          mountPath: /opt/filebeat/
        - name: logdata               # 指定卷的名稱,這個名稱要和前面業務容器指定的日誌路徑的卷名稱一致,這樣後面才會掛載同一個 emptyDir      
          mountPath: /opt/logs/       # 指定要將業務的日誌掛載在 filebeat 容器中的路徑,這個路徑要和 Configmap 中指定的日誌路徑一致
      volumes:
      - name: logdata                 # 為前面宣告名稱為 logdata 的卷掛載一個 emptyDir 卷(filebeat 和業務容器都會掛載這個卷)
        emptyDir: {}
      - name: config                  # 為前面宣告名稱為 config 的卷(filebeat 配置檔案)掛載一個 configmap,並指定configmap 的名稱
        configMap:
          name: filebeat-config
          items:
          - key: filebeat.yml
            path: filebeat.yml

需要注意的是,使用 SideCar 模式收集容器日誌實現的本質,就是將業務容器內的日誌路徑儲存到本地宿主機的一個目錄下,然後這個目錄也會同時掛載到日誌收集服務容器中,這樣日誌收集服務才可以讀取到業務的日誌。

所以上面的 yaml 檔案中,首先業務容器的日誌目錄宣告為一個卷,並命名為 logdata。而下面的 Filebeat 容器中也宣告瞭一個 logdata 的卷。由於這兩個卷名稱一樣,所以這兩個卷掛載是同一個 emptyDir。也就實現了在 Filebeat 容器中讀取業務日誌的目的。當然使用 emptyDir 將容器中的日誌儲存到宿主機本地並不是持久化儲存,emptyDir 會隨著容器的刪除而銷燬。

四、建立 Service

將業務容器的 8080 埠暴露出去,yaml 檔案內容如下:

---
apiVersion: v1
kind: Service
metadata:
  name: smc-service
  labels:
    app: smc-service
  namespace: ns-smc-gateway
spec:
  ports:
  - port: 8080
    targetPort: 8080
    nodePort: 30378
  selector:
    app: smc-gateway
  type: NodePort

五、驗證

將以上 yaml 檔案執行後,會在 ns-smc-gateway 名稱空間下建立一個 Pod,這個 Pod 中包含兩個容器。

[@k8s-master2 ~]# kubectl get pods -n ns-smc-gateway
NAME                          READY   STATUS    RESTARTS   AGE
smc-gateway-fcf598c4b-wphhr   2/2     Running   0          150m

[@k8s-master2 ~]# kubectl describe pod smc-gateway-fcf598c4b-wphhr -n ns-smc-gateway | grep -B1 "Container ID"
  smc-gateway-for-test:
    Container ID:   docker://3711e3a5bc8fafc94ea174578c0a79774f5b25c7eae6c7aa47759e513645f221
--
  filebeat-for-smc-gateway:
    Container ID:  docker://1b87242cdf8632edc1bea2fe23910f68c2d5da0254163b123bfc414829f7bea7

此時到 Kibana 中的索引管理中,會看到已經新增了兩個業務索引,配置對應的索引模式後,就可以在 Kibana 中看到對應的日誌。

相關文章