k8s與審計-- 將clickhouse增加為 heapster sink

來源:互聯網
上載者:User

前言

在k8s資源審計和計費這塊,容器和虛機有很大區別。相對虛機來講,容器不容易實現。
資源指標收集可以採用heapster,也可以用prometheus。之前文章有介紹過,prometheus的儲存的瓶頸和查詢較大資料量,容易oom這兩個問題。所以選擇了heapster。此外,heapster不僅內部實現了很多aggregator和calculator,做了很多彙總層的工作。而採用prometheus,你需要在查詢的時候做彙總。
heapster支援諸多metrics輸出,稱為sink。目前支援的sink如:

而我比較傾向於clickhouse資料庫,關於clickhouse,其實前面的文章介紹過很多了。
所以本文主要講如何為heapster增加clickhouse sink。

程式碼分析和實現

看代碼,增加一種sink還是很簡單的。典型的工廠設計模式,實現 Name,Stop,ExportData 介面方法即可。最後再提供一個初始化函數,供factory調用即可。

初始化方法 NewClickhouseSink

具體代碼:

config, err := clickhouse_common.BuildConfig(uri)    if err != nil {        return nil, err    }    client, err := sql.Open("clickhouse", config.DSN)    if err != nil {        glog.Errorf("connecting to clickhouse: %v", err)        return nil, err    }    sink := &clickhouseSink{        c:       *config,        client:  client,        conChan: make(chan struct{}, config.Concurrency),    }    glog.Infof("created clickhouse sink with options: host:%s user:%s db:%s", config.Host, config.UserName, config.Database)    return sink, nil

基本上就是擷取設定檔,初始化clickhouse 的client。

在factory.go 中 build方法中,加入剛剛實現的初始化函數

func (this *SinkFactory) Build(uri flags.Uri) (core.DataSink, error) {    switch uri.Key {    case "elasticsearch":        return elasticsearch.NewElasticsearchSink(&uri.Val)    case "gcm":        return gcm.CreateGCMSink(&uri.Val)    case "stackdriver":        return stackdriver.CreateStackdriverSink(&uri.Val)    case "statsd":        return statsd.NewStatsdSink(&uri.Val)    case "graphite":        return graphite.NewGraphiteSink(&uri.Val)    case "hawkular":        return hawkular.NewHawkularSink(&uri.Val)    case "influxdb":        return influxdb.CreateInfluxdbSink(&uri.Val)    case "kafka":        return kafka.NewKafkaSink(&uri.Val)    case "librato":        return librato.CreateLibratoSink(&uri.Val)    case "log":        return logsink.NewLogSink(), nil    case "metric":        return metricsink.NewMetricSink(140*time.Second, 15*time.Minute, []string{            core.MetricCpuUsageRate.MetricDescriptor.Name,            core.MetricMemoryUsage.MetricDescriptor.Name}), nil    case "opentsdb":        return opentsdb.CreateOpenTSDBSink(&uri.Val)    case "wavefront":        return wavefront.NewWavefrontSink(&uri.Val)    case "riemann":        return riemann.CreateRiemannSink(&uri.Val)    case "honeycomb":        return honeycomb.NewHoneycombSink(&uri.Val)    case "clickhouse":        return clickhouse.NewClickhouseSink(&uri.Val)    default:        return nil, fmt.Errorf("Sink not recognized: %s", uri.Key)    }}

Name 和 Stop

func (sink *clickhouseSink) Name() string {    return "clickhouse"}func (tsdbSink *clickhouseSink) Stop() {    // Do nothing}

stop 函數在heapster關閉的時候調用,執行一些非託管資源的關閉。

ExportData

這是核心的地方。

func (sink *clickhouseSink) ExportData(dataBatch *core.DataBatch) {    sink.Lock()    defer sink.Unlock()    if err := sink.client.Ping(); err != nil {        glog.Warningf("Failed to ping clickhouse: %v", err)        return    }    dataPoints := make([]point, 0, 0)    for _, metricSet := range dataBatch.MetricSets {        for metricName, metricValue := range metricSet.MetricValues {            var value float64            if core.ValueInt64 == metricValue.ValueType {                value = float64(metricValue.IntValue)            } else if core.ValueFloat == metricValue.ValueType {                value = float64(metricValue.FloatValue)            } else {                continue            }            pt := point{                name:    metricName,                cluster: sink.c.ClusterName,                val:     value,                ts:      dataBatch.Timestamp,            }            for key, value := range metricSet.Labels {                if _, exists := clickhouseBlacklistLabels[key]; !exists {                    if value != "" {                        if key == "labels" {                            lbs := strings.Split(value, ",")                            for _, lb := range lbs {                                ts := strings.Split(lb, ":")                                if len(ts) == 2 && ts[0] != "" && ts[1] != "" {                                    pt.tags = append(pt.tags, fmt.Sprintf("%s=%s", ts[0], ts[1]))                                }                            }                        } else {                            pt.tags = append(pt.tags, fmt.Sprintf("%s=%s", key, value))                        }                    }                }            }            dataPoints = append(dataPoints, pt)            if len(dataPoints) >= sink.c.BatchSize {                sink.concurrentSendData(dataPoints)                dataPoints = make([]point, 0, 0)            }        }    }    if len(dataPoints) >= 0 {        sink.concurrentSendData(dataPoints)    }    sink.wg.Wait()}

主要有以下幾個地方需要注意

  • 資料的格式轉換。需要將heapster 中DataBatch 轉化為你目的儲存的格式。其實這塊做過pipeline 多output的人,很容易理解。
  • 批量寫入。一般在大資料量的時候,批量寫入是一種有效手段。
  • 根據設定參數,並發寫入目的儲存。用到了golang的協程。下面這段代碼實現了一個協程的發送資料。
func (sink *clickhouseSink) concurrentSendData(dataPoints []point) {    sink.wg.Add(1)    // use the channel to block until there's less than the maximum number of concurrent requests running    sink.conChan <- struct{}{}    go func(dataPoints []point) {        sink.sendData(dataPoints)    }(dataPoints)}

擷取配置參數

這塊在clickhouse.go中,主要做了擷取配置參數和參數初始化一些預設值,以及對配置參數校正的工作。

dockerfile的更改

原來的基礎鏡像是基於scratch

FROM scratchCOPY heapster eventer /COPY ca-certificates.crt /etc/ssl/certs/#   nobody:nobodyUSER 65534:65534ENTRYPOINT ["/heapster"]

由於需要改timezone的問題,改成了基於alpine。

FROM alpineRUN apk add -U tzdataRUN ln -sf /usr/share/zoneinfo/Asia/Shanghai  /etc/localtimeCOPY heapster eventer /COPY ca-certificates.crt /etc/ssl/certs/RUN chmod +x /heapsterENTRYPOINT ["/heapster"]

實際上,基於scratch增加timezone並且更改,也可以做到,只不過需要裝一些包指令,結果就是鏡像變大。與其如此,不如基於我比較熟悉的alpine實現。

總結

fork的項目地址。實際作業記錄:

由於ck的出色的寫入效能,運行非常穩定。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.