雲原生系列5 容器化日誌之EFK

李福春發表於2021-02-18

image.png

上圖是EFK架構圖,k8s環境下常見的日誌採集方式。

日誌需求

1 集中採集微服務的日誌,可以根據請求id追蹤到完整的日誌;

2 統計請求介面的耗時,超出最長響應時間的,需要做報警,並針對性的進行調優;

3 慢sql排行榜,並報警;

4 異常日誌排行榜,並報警;

5 慢頁面請求排行,並告警;

k8s的日誌採集

k8s本身不會為你做日誌採集,需要自己做;

k8s的容器日誌處理方式採用的 叢集層級日誌,

即容器銷燬,pod漂移,Node當機不會對容器日誌造成影響;

image.png

容器的日誌會輸出到stdout,stderr,對應的儲存在宿主機的目錄中,

即 /var/lib/docker/container ;

Node上通過日誌代理轉發

image.png

在每個node上部署一個daemonset , 跑一個logging-agent收集日誌,

比如fluentd, 採集宿主機對應的資料盤上的日誌,然後輸出到日誌儲存服務或者訊息佇列;

優缺點分析:

對比 說明
優點 1每個Node只需要部署一個Pod採集日誌 2對應用無侵入
缺點 應用輸出的日誌都必須直接輸出到容器的stdout,stderr中

Pod內部通過sidecar容器轉發到日誌服務

image.png

通過在pod中啟動一個sidecar容器,比如fluentd, 讀取容器掛載的volume目錄,輸出到日誌服務端;

日誌輸入源: 日誌檔案

日誌處理: logging-agent ,比如fluentd

日誌儲存: 比如elasticSearch , kafka

優缺點分析:

對比 說明
優點 1 部署簡單;2 對宿主機友好;
缺點 1. 消耗較多的資源;2. 日誌通過kubectl logs 無法看到

示例:

apiVersion: v1
kind: Pod
metadata:
  name: counter
spec:
  containers:
  - name: count
    image: busybox
    args:
    - /bin/sh
    - -c
    - >
        i=0;
        while true;
        do
          echo "$i:$(data)" >> /var/log/1.log
          echo "$(data) 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
    valumeMounts:
    - name: varlog
        mountPath: /var/log
    - name: config-volume
        mountPath: /etc/fluentd-config
  volumes:
  - name: varlog
      emptyDir: {}
  - name: config-volume
      configMap:
        name: fluentd-config



Pod內部通過sidecar容器輸出到stdout

image.png

適用於應用容器只能把日誌輸出到檔案,無法輸出到stdout,stderr中的場景;

通過一個sidecar容器,直接讀取日誌檔案,再重新輸出到stdout,stderr中,

即可使用Node上通過日誌代理轉發的模式;

優缺點分析:

對比 說明
優點 只需耗費比較少的cpu和記憶體,共享volume處理效率比較高
缺點 宿主機上存在兩份相同的日誌,磁碟利用率不高

應用容器直接輸出日誌到日誌服務

image.png

適用於有成熟日誌系統的場景,日誌不需要通過k8s;

EFK介紹

fluentd

fluentd是一個統一日誌層的開源資料收集器。

flentd允許你統一日誌收集並更好的使用和理解資料;

image.png

四大特徵:

統一日誌層

fluentd隔斷資料來源,從後臺系統提供統一日誌層;

簡單靈活
提供了500多個外掛,連線非常多的資料來源和輸出源,核心簡單;

廣泛驗證
5000多家資料驅動公司以來Fluentd
最大的客戶通過它收集5萬多臺伺服器的日誌

**雲原生**

是雲原生CNCF的成員專案

image.png

4大優勢:

統一JSON日誌

image.png

fluentd嘗試採用JSON結構化資料,這就統一了所有處理日誌資料的方面,收集,過濾,快取,輸出日誌到多目的地,下行流資料處理使用Json更簡單,因為它已經有足夠的訪問結構並保留了足夠靈活的scemas;

外掛化架構

image.png

fluntd 有靈活的外掛體系允許社群擴充套件功能,500多個社群貢獻的外掛連線了很多資料來源和目的地; 通過外掛,你可以開始更好的使用你的日誌

最小資源消耗

image.png

c和ruby寫的,需要極少的系統資源,40M左右的記憶體可以處理13k/時間/秒 ,如果你需要更緊湊的記憶體,可以使用Fluent bit ,更輕量的Fluentd

核心可靠

image.png

Fluentd支援記憶體和基於檔案快取,防止內部節點資料丟失;
也支援robust失敗並且可以配置高可用模式, 2000多家資料驅動公司在不同的產品中依賴Fluentd,更好的使用和理解他們的日誌資料

使用fluentd的原因:

簡單靈活

10分鐘即可在你的電腦上安裝fluentd,你可以馬上下載它,500多個外掛打通資料來源和目的地,外掛也很好開發和部署;

開源

**基於Apache2.0證書  完全開源 **

可靠高效能

5000多個資料驅動公司的不同產品和服務依賴fluentd,更好的使用和理解資料,實際上,基於datadog的調查,是使用docker執行的排行top7的技術;

一些fluentd使用者實時採集上千臺機器的資料,每個例項只需要40M左右的記憶體,伸縮的時候,你可以節省很多記憶體

社群

fluentd可以改進軟體並幫助其它人更好的使用

大公司使用背書: 微軟 , 亞馬遜; pptv ;

image.png

image.png

可以結合elasticSearch + kibana來一起組成日誌套件;
快速搭建EFK叢集並收集應用的日誌,配置效能排行榜;
image.png

elasticsearch

Elasticsearch 是一個分散式、RESTful 風格的搜尋和資料分析引擎,

能夠解決不斷湧現出的各種用例。 作為 Elastic Stack 的核心,

它集中儲存您的資料,幫助您發現意料之中以及意料之外的情況。

詳細介紹:https://www.elastic.co/guide/cn/elasticsearch/guide/current/foreword_id.html

kibana

Kibana 是一款開源的資料分析和視覺化平臺,它是 Elastic Stack 成員之一,

設計用於和 Elasticsearch 協作。您可以使用 Kibana 對 Elasticsearch 索引中的資料進行搜尋、

檢視、互動操作。您可以很方便的利用圖表、表格及地圖對資料進行多元化的分析和呈現。

Kibana 可以使大資料通俗易懂。它很簡單,

基於瀏覽器的介面便於您快速建立和分享動態資料儀表板來追蹤 Elasticsearch 的實時資料變化.

詳細介紹:https://www.elastic.co/guide/cn/kibana/current/introduction.html

容器化EFK實現路徑

https://github.com/kayrus/elk-kubernetes

直接拖程式碼下來,然後配置後 context, namespace , 即可安裝;

cd elk-kubernetes

./deploy.sh --watch

下面是deploy.sh的指令碼,可以簡單看一下:

#!/bin/sh

CDIR=$(cd `dirname "$0"` && pwd)
cd "$CDIR"

print_red() {
  printf '%b' "\033[91m$1\033[0m\n"
}

print_green() {
  printf '%b' "\033[92m$1\033[0m\n"
}

render_template() {
  eval "echo \"$(cat "$1")\""
}


KUBECTL_PARAMS="--context=250091890580014312-cc3174dcd4fc14cf781b6fc422120ebd8"
NAMESPACE=${NAMESPACE:-sm}
KUBECTL="kubectl ${KUBECTL_PARAMS} --namespace=\"${NAMESPACE}\""

eval "kubectl ${KUBECTL_PARAMS} create namespace \"${NAMESPACE}\""

#NODES=$(eval "${KUBECTL} get nodes -l 'kubernetes.io/role!=master' -o go-template=\"{{range .items}}{{\\\$name := .metadata.name}}{{\\\$unschedulable := .spec.unschedulable}}{{range .status.conditions}}{{if eq .reason \\\"KubeletReady\\\"}}{{if eq .status \\\"True\\\"}}{{if not \\\$unschedulable}}{{\\\$name}}{{\\\"\\\\n\\\"}}{{end}}{{end}}{{end}}{{end}}{{end}}\"")
NODES=$(eval "${KUBECTL} get nodes -l 'sm.efk=data' -o go-template=\"{{range .items}}{{\\\$name := .metadata.name}}{{\\\$unschedulable := .spec.unschedulable}}{{range .status.conditions}}{{if eq .reason \\\"KubeletReady\\\"}}{{if eq .status \\\"True\\\"}}{{if not \\\$unschedulable}}{{\\\$name}}{{\\\"\\\\n\\\"}}{{end}}{{end}}{{end}}{{end}}{{end}}\"")
ES_DATA_REPLICAS=$(echo "$NODES" | wc -l)

if [ "$ES_DATA_REPLICAS" -lt 3 ]; then
  print_red "Minimum amount of Elasticsearch data nodes is 3 (in case when you have 1 replica shard), you have ${ES_DATA_REPLICAS} worker nodes"
  print_red "Won't deploy more than one Elasticsearch data pod per node exiting..."
  exit 1
fi

print_green "Labeling nodes which will serve Elasticsearch data pods"
for node in $NODES; do
  eval "${KUBECTL} label node ${node} elasticsearch.data=true --overwrite"
done

for yaml in *.yaml.tmpl; do
  render_template "${yaml}" | eval "${KUBECTL} create -f -"
done

for yaml in *.yaml; do
  eval "${KUBECTL} create -f \"${yaml}\""
done

eval "${KUBECTL} create configmap es-config --from-file=es-config --dry-run -o yaml" | eval "${KUBECTL} apply -f -"
eval "${KUBECTL} create configmap fluentd-config --from-file=docker/fluentd/td-agent.conf --dry-run -o yaml" | eval "${KUBECTL} apply -f -"
eval "${KUBECTL} create configmap kibana-config --from-file=kibana.yml --dry-run -o yaml" | eval "${KUBECTL} apply -f -"

eval "${KUBECTL} get pods $@"

簡單分解一下部署的流程:

k8s搭建EFK流程.png

我的k8s環境中沒有搭建成功,後續搭建成功了再出詳細的安裝筆記。

小結

一句話概括本篇:EFK是一種通過日誌代理客戶端採集應用日誌比較常用的實現方式。

讓容器日誌無處可逃.png

原創不易,關注誠可貴,轉發價更高!轉載請註明出處,讓我們互通有無,共同進步,歡迎溝通交流。

相關文章