基於filebeat二次開發Kubernetes日誌採集

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

目前最為主流的容器編排工具主要有kubernetes、mesos、swarm,個人不評價誰好誰壞因為每個東西都有自己的優勢。不過個人認為目前關注度最高的應該當屬kubernetes,現在越來越多的公司採用kubernetes作為底層編排工具開發自己的容器調度平台。既然是一個PAAS平台那麼就應該提供一個計算監控等一體的服務,因為是在kubernetes運行上面的容器大多數都是無狀態服務,所以統一的日誌管理又是其中必不可少的一部分。下面我們就講一下如何基於filebeat開發屬於自己的日誌採集。

目前用的最多的日誌管理技術應該是ELK,E應該沒有太多的疑問基本上很多公司都是採用的這個作為儲存索引引擎。L及logstash是一個日誌採集工具支援檔案採集等多種方式,但是基於容器的日誌採集又跟傳統的檔案采方式略有不同,雖然docker本身提供了一些log driver但是還是無法很好的滿足我們的需求。現在kubernetes官方有一個日誌解決方案是基於fluentd的。至於為什麼最後選擇採用filebeat而沒有用fluentd主要有一下幾點:

  • 首先filebeat是go寫的,我本身是go開發,fluentd是ruby寫的很抱歉我看不太懂
  • filbeat比較輕量,filbeat現在功能雖然比較簡單但是已經基本上夠用,而且打出來鏡像只有幾十M
  • filbeat效能比較好,沒有具體跟fluentd對比過,之前跟logstash對比過確實比logstash好不少,logtash也是ruby寫的我想應該會比fluentd好不少
  • filbeat雖然功能簡單,但是代碼結構非常易於進行定製開發
  • 還有就是雖然用了很久fluentd但是fluentd的設定檔實在是讓我很難懂

filebeat如何採集kubernetes日誌

所以基於以上幾點決定採用filebeat開發了自己的日誌採集。
filebeat的Github地址是https://github.com/elastic/beats裡面囊括了好幾個項目其中就包括filebeat。

和其他的日誌採集處理一樣filebeat也有幾個部分分別是input、processors、output,不過filebeat提供的能力還比較少,不過無所謂夠用就好。

filebeat提供了一個add_kubernetes_metadata的processor,檔案的採集路徑就要配成/var/lib/docker/containers/*/*-json.log主要是監聽kubernetes的apiserver把容器對應的pod的資訊存到記憶體裡面,從檔案日誌source裡面(就是上面的那個路徑)裡面擷取容器id匹配得到pod的資訊。
因為json.log檔案裡面的日誌都是json格式的所以需要對日誌進行json格式化,filebeat有一個processor叫decode_json_fields這些processor都支援條件判斷,可以通過條件判斷來絕對是否要對某一條日誌進行處理。filebeat預設的日誌欄位是message但是*-json.log解析出來以後的日誌欄位是log,如果同時配置了其他的日誌採集這個時候所用的儲存日誌的欄位就不一樣了,所以需要對它們進行處理讓它們使用同一個欄位,但是filebeat並沒有提供這個功能所以自己寫了一個add_fields的功能。

整理後的設定檔如下:

filebeat.prospectors:- type: log  paths:    - /var/lib/docker/containers/*/*-json.log    - /var/log/containers/applogs/*processors:- add_kubernetes_metadata:    in_cluster: false    host: "127.0.0.1"    kube_config: /root/.kube/config- add_fields:    fields:      log: '{message}'- decode_json_fields:    when:       regexp:         log: "{*}"    fields: ["log"]    overwrite_keys: true    target: ""- drop_fields:     fields: ["source", "beat.version", "beat.name", "message"]- parse_level:     levels: ["fatal", "error", "warn", "info", "debug"]     field: "log"logging.level: infosetup.template.enabled: truesetup.template.name: "filebeat-%{+yyyy.MM.dd}"setup.template.pattern: "filebeat-*"#setup.template.fields: "${path.config}/fields.yml"setup.template.fields: "/fields.yml"setup.template.overwrite: truesetup.template.settings:   index:     analysis:       analyzer:         enncloud_analyzer:           filter: ["standard", "lowercase", "stop"]           char_filter: ["my_filter"]           type: custom           tokenizer: standard       char_filter:         my_filter:           type: mapping           mappings: ["-=>_"]output:  elasticsearch:    hosts: ["127.0.0.1:9200"]    index: "filebeat-%{+yyyy.MM.dd}"

如果線上環境filebeat也是以daemonset的方式運行在kubernetes叢集裡面,所以in_cluster就需要設定成true,對應的kube_config則不需要配置了,host參數則是監聽的某一個節點的pod,所以這個值應該是filebeat運行所在節點的pod的名稱,當然也可以不寫,那樣的話就是監聽全域的pod,不過這個對於filebeat來說是沒必要的也是不好的。

add_fieldsprocessor可以添加自己想要的欄位,值可以是字串也可以是{message}格式,如果是這種格式則會從已有的欄位裡面取值進行填充。

parse_levelprocessor是用於一個匹配日誌格式的功能,如果記錄檔最前面出現的那個記錄層級則這個日誌加一個相應層級的欄位。

filebeat還有對於template處理的功能的功能可以指定所用的mapping。

開發filebeat processor

使用的過程中主要是針對一些不滿足的processor進行了開發,filebeat的代碼結構非常清晰抽象也很好,可以很簡單的進行開發。
filebeat的processor功能主要放在libbeat和filbeat同級的目錄下,在這個目錄下就叫processors。可以看到裡面有actions,add_cloud_metadataadd_kubernetes_metadataadd_docker_metadata所以filebeat也只支援直接docker的processor的,比較普通的processor都是放在actions下面的所以如果我們需要開發一些簡單的processor的話可以直接放到下面,包括decode_json和drop_event等也是放在下面的。以add_field為例:

package actionsimport (    "fmt"    "regexp"    "strings"    "github.com/elastic/beats/libbeat/beat"    "github.com/elastic/beats/libbeat/common"    "github.com/elastic/beats/libbeat/processors")type addFields struct {    Fields map[string]string    reg    *regexp.Regexp}func init() {    processors.RegisterPlugin("add_fields",        configChecked(newAddFields,            requireFields("fields"),            allowedFields("fields", "when")))}func newAddFields(c *common.Config) (processors.Processor, error) {    config := struct {        Fields map[string]string `config:"fields"`    }{}    err := c.Unpack(&config)    if err != nil {        return nil, fmt.Errorf("fail to unpack the add_fields configuration: %s", err)    }    f := &addFields{Fields: config.Fields, reg: regexp.MustCompile("{(.*)}")}    return f, nil}func (f *addFields) Run(event *beat.Event) (*beat.Event, error) {    var errors []string    for field, value := range f.Fields {        matchers := f.reg.FindAllStringSubmatch(value, -1)        if len(matchers) == 0 {            event.PutValue(field, value)        } else {            if len(matchers[0]) >= 2 {                val, err := event.GetValue(strings.Trim(matchers[0][1], " "))                if err != nil {                    errors = append(errors, err.Error())                } else {                    event.PutValue(field, val)                }            }        }    }    return event, nil}func (f *addFields) String() string {    var fields []string    for field, _ := range f.Fields {        fields = append(fields, field)    }    return "add_fields=" + strings.Join(fields, ", ")}

需要定義自己的struct, newAddFields方法通過設定檔初始化自己的struct。並在init裡面通過RegisterPlugin把自己的processor註冊進去。這個struct主要是要實現Run方法,這個方法就是對於每一條日誌event的具體處理。

到這就基本上實現了對接kubernetes的對接改造就基本上完成了,當然還有其他很多工作可以做,比如golang本身的regex和encoding/json效能比較差,這些都是可以最佳化的地方。

我自己fork出來的地址是https://github.com/yiqinguo/beats增加了Makefile直接編譯打鏡像,和filebeat-ds.yml直接發到kubernetes叢集裡面。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.