十七. k8s--日志收集方案


k8s容器日志收集方案

一. 在Node上部署logging agent

將日志文件轉發到后端存儲里保存起來

  • 不難看到,這里的核心就在於logging agent,它一般都會以DaemonSet的方式運行在節點上,然后將宿主機上的容器日志目錄掛載進去,最后由logging-agent把日志轉發出去。
  • 舉個例子,我們可以通過Fluentd項目作為宿主機上的logging-agent,然后把日志轉發到遠端的ElasticSearch里保存起來供將來進行檢索。具體的操作過程官網很多kubernetes的部署里,會自動為你啟用logrotate,在日志文件超過10MB的時候自動對日志文件進行roate操作。
  • 可以看到在Node上部署logging agent最大的優點,在於只需要部署一個agent,並且不會對應用和pod有任何入侵性。所以這個方案在社區里是最常用的一種。
  • 但是這種方案的不足之處就在於,它要求應用輸出的日志,都必須是直接輸出到容器的stdout和stderr里

二. 對特殊情況的一個處理

  • 當容器的日志只能輸出到某些文件里的時候,我們可以通過一個sidecar容器把這些日志文件重新輸出到sidecar的stdout和stderr

  • 現在我的應用pod只有一個容器,它會把日志輸出到容器里的/var/log/1.log和2.log這兩個文件里。這個pod的YAML文件如下所示:

    apiVersion: v1
    kind: Pod
    metadata:
      name: counter
    spec:
      containers:
      - name: count
        image: busybox
        args:
        - /bin/sh
        - -c
        - >
          i=0;
          while true;
          do
            echo "$i: $(date)" >> /var/log/1.log;
            echo "$(date) INFO $i" >> /var/log/2.log;
            i=$((i+1));
            sleep 1;
          done
        volumeMounts:
        - name: varlog
          mountPath: /var/log
      volumes:
      - name: varlog
        emptyDir: {}
    
  • 在這種情況下,你用kubectl logs命令是看不到應用的任何日志的。這時我們就可以為這個pod添加兩個sidecar容器,分別將上述兩個日志文件里的內容重新以stdout和stderr的方式輸出來,這個YAML文件的寫法如下:

    apiVersion: v1
    kind: Pod
    metadata:
      name: counter
    spec:
      containers:
      - name: count
        image: busybox
        args:
        - /bin/sh
        - -c
        - >
          i=0;
          while true;
          do
            echo "$i: $(date)" >> /var/log/1.log;
            echo "$(date) INFO $i" >> /var/log/2.log;
            i=$((i+1));
            sleep 1;
          done
        volumeMounts:
        - name: varlog
          mountPath: /var/log
      - name: count-log-1
        image: busybox
        args: [/bin/sh, -c, 'tail -n+1 -f /var/log/1.log']
        volumeMounts:
        - name: varlog
          mountPath: /var/log
      - name: count-log-2
        image: busybox
        args: [/bin/sh, -c, 'tail -n+1 -f /var/log/2.log']
        volumeMounts:
        - name: varlog
          mountPath: /var/log
      volumes:
      - name: varlog
        emptyDir: {}
    
  • 由於sidecar跟主容器之間是共享Volume的,所以這里的sidecar方案的額外性能損耗並不高,也就多占用一點cpu和內存。但是,這時候宿主機上實際會存在兩份相同的日志文件:一份是應用自己寫入的;另一份是sidecar的stdout和stderr對應的json文件。這對磁盤是很大的浪費。所以說,除非萬不得已或者應用容器完全不能修改,否則還是建議你直接使用方案一,或者直接使用方案三。

三. 送過sidecar容器直接把日志文件發送到遠程存儲

  • 相當於把方案一里的logging agent,放在了應用pod里。

  • 在這種方案里,你的應用還可以直接把日志輸出到固定的文件里而不是stdout,你的logging-agent還可以使用fluentd,后端存儲還可以是ElasticSearch。只不過,fluentd的輸入源變成了應用的日志文件。一般來說,我們會把fluentd的輸入源配置保存在一個ConfigMap里,如下所以:

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: fluentd-config
    data:
      fluentd.conf: |
        <source>
          type tail
          format none
          path /var/log/1.log
          pos_file /var/log/1.log.pos
          tag count.format1
        </source>
        
        <source>
          type tail
          format none
          path /var/log/2.log
          pos_file /var/log/2.log.pos
          tag count.format2
        </source>
        
        <match **>
          type google_cloud
        </match>
    復制代碼
    
  • 我們在應用pod的定義里,就可以聲明一個Fluentd容器作為sidecar,專門負責將應用生成的1.log和2.log轉發到ElasticSearch中,這個配置,如下所示:

    apiVersion: v1
    kind: Pod
    metadata:
      name: counter
    spec:
      containers:
      - name: count
        image: busybox
        args:
        - /bin/sh
        - -c
        - >
          i=0;
          while true;
          do
            echo "$i: $(date)" >> /var/log/1.log;
            echo "$(date) INFO $i" >> /var/log/2.log;
            i=$((i+1));
            sleep 1;
          done
        volumeMounts:
        - name: varlog
          mountPath: /var/log
      - name: count-agent
        image: k8s.gcr.io/fluentd-gcp:1.30
        env:
        - name: FLUENTD_ARGS
          value: -c /etc/fluentd-config/fluentd.conf
        volumeMounts:
        - name: varlog
          mountPath: /var/log
        - name: config-volume
          mountPath: /etc/fluentd-config
      volumes:
      - name: varlog
        emptyDir: {}
      - name: config-volume
        configMap:
          name: fluentd-config
    
  • 如上所示,這個Fluentd容器使用的輸入源,就是通過引用我們前面寫的ConfigMap來指定的。這里用到了Volume來把ConfigMap掛在到Pod里。

  • 這種方案部署簡單,並且對宿主機非常友好,但是這個sidecar容器很可能會消耗較多的資源,甚至拖垮應用容器。由於日志沒有輸出到stdout上,所以你通過kubectl logs 是看不到日志信息的。

總結

以上,就是k8s最常用的三種收集日志的手段了,綜合對比以上方案,比較建議你將應用日志輸出到stdout和stderr,然后通過在宿主機上部署logging-agent的方式集中處理日志、這種方案不但簡單,而且kubectl logs依然可以使用,也是官方推薦的一種。

轉載: https://juejin.im/post/5cb939b0e51d456e311649e0


免責聲明!

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



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