簡述 Kubernetes 集群日志基礎
服務器和應用程序日志記錄是開發(fā)人員、運維人員和安全團隊了解應用程序在其生產(chǎn)環(huán)境中運行狀態(tài)的重要工具。
日志記錄使運維人員能夠確定應用程序和所需組件是否運行平穩(wěn),并檢測是否發(fā)生了異常情況,以便他們能夠?qū)@種情況做出反應。
對于開發(fā)人員,日志記錄提供了在開發(fā)期間和之后對代碼進行故障排除的可見性。在生產(chǎn)環(huán)境中,開發(fā)人員通常依賴于沒有調(diào)試工具的日志記錄工具。在加上系統(tǒng)的日志記錄,開發(fā)人員可以與運維人員攜手合作,有效地解決問題。
日志記錄工具最重要的受益者是安全團隊,尤其是在云原生的環(huán)境中。能夠從應用程序和系統(tǒng)日志中收集信息使得安全團隊能夠分析來自身份驗證、應用程序訪問惡意軟件活動的數(shù)據(jù),并在需要時進行響應。
Kubernetes 是領先的容器平臺,越來越多的應用程序通過 Kubernetes 部署到生產(chǎn)環(huán)境。我相信了解 Kubernetes 的日志架構是一項非常重要的工作,每個開發(fā)、運維和安全團隊都需要認真對待。
在本文中,我將討論 Kubernetes 中不同容器日志記錄模式的工作原理。
系統(tǒng)日志記錄和應用日志記錄
在深入研究 Kubernetes 日志記錄架構之前,我想探索不同的日志記錄方法以及這兩種功能如何成為 Kubernetes 日志記錄的關鍵特性。
有兩種類型的系統(tǒng)組件:在容器中運行的組件和不在容器中運行的組件。例如:
- Kubernetes 調(diào)度者和 kube-proxy 運行在容器中。
- kubelet 和容器運行時不在容器中運行。
與容器日志類似,系統(tǒng)容器日志存儲在 /var/log 目錄中,你應該定期輪換它們。
在這里,我研究的是容器日志記錄。首先,我看一下集群級別的日志記錄以及為什么它對集群運維人員很重要。集群日志提供有關集群如何執(zhí)行的信息。諸如為什么 吊艙Pod 被下線或節(jié)點死亡之類的信息。集群日志記錄還可以捕獲諸如集群和應用程序訪問以及應用程序如何利用計算資源等信息??傮w而言,集群日志記錄工具為集群運維人員提供操作集群和安全有用的信息。
捕獲容器日志的另一種方法是通過應用程序的本機日志記錄工具?,F(xiàn)代應用程序設計很可能具有日志記錄機制,可幫助開發(fā)人員通過標準輸出 (stdout) 和錯誤流 (stderr) 解決應用程序性能問題。
為了擁有有效的日志記錄工具,Kubernetes 實現(xiàn)需要應用程序和系統(tǒng)日志記錄組件。
Kubernetes 容器日志的 3 種類型
如今,在大多數(shù)的 Kubernetes 實現(xiàn)中,你可以看到三種主要的集群級日志記錄方法。
- 節(jié)點級日志代理
- 用于日志記錄的挎斗Sidecar容器應用程序
- 將應用程序日志直接暴露給日志后端
節(jié)點級日志代理
我想考慮節(jié)點級日志代理。你通常使用 DaemonSet 作為部署策略來實現(xiàn)這些,以便在所有 Kubernetes 節(jié)點中部署一個吊艙(充當日志代理)。然后,該日志代理被配置為從所有 Kubernetes 節(jié)點讀取日志。你通常將代理配置為讀取節(jié)點 /var/logs 目錄捕獲 stdout/stderr 流并將其發(fā)送到日志記錄后端存儲。
下圖顯示了在所有節(jié)點中作為代理運行的節(jié)點級日志記錄。
Node-level logging agent
以使用 fluentd 方法為例設置節(jié)點級日志記錄,你需要執(zhí)行以下操作:
(1) 首先,你需要創(chuàng)建一個名為 fluentdd 的服務賬戶。Fluentd 吊艙使用此服務賬戶來訪問 Kubernetes API,你需要在日志命名空間中使用標簽 app: fluentd 創(chuàng)建它們:
- #fluentd-SA.yaml
- apiVersion: v1
- kind: ServiceAccount
- metadata:
- name: fluentd
- namespace: logging
- labels:
- app: fluentd
你可以在此 倉庫 中查看完整示例。
(2) 接著,你需要創(chuàng)建一個名稱為 fluentd-configmap 的 ConfigMap。這為 fluentd daemonset 提供了一個配置文件,其中包含所有必需的屬性。
- #fluentd-daemonset.yaml
- apiVersion: extensions/v1beta1
- kind: DaemonSet
- metadata:
- name: fluentd
- namespace: logging
- labels:
- app: fluentd
- kubernetes.io/cluster-service: "true"
- spec:
- selector:
- matchLabels:
- app: fluentd
- kubernetes.io/cluster-service: "true"
- template:
- metadata:
- labels:
- app: fluentd
- kubernetes.io/cluster-service: "true"
- spec:
- serviceAccount: fluentd
- containers:
- - name: fluentd
- image: fluent/fluentd-kubernetes-daemonset:v1.7.3-debian-elasticsearch7-1.0
- env:
- - name: FLUENT_ELASTICSEARCH_HOST
- value: "elasticsearch.logging.svc.cluster.local"
- - name: FLUENT_ELASTICSEARCH_PORT
- value: "9200"
- - name: FLUENT_ELASTICSEARCH_SCHEME
- value: "http"
- - name: FLUENT_ELASTICSEARCH_USER
- value: "elastic"
- - name: FLUENT_ELASTICSEARCH_PASSWORD
- valueFrom:
- secretKeyRef:
- name: efk-pw-elastic
- key: password
- - name: FLUENT_ELASTICSEARCH_SED_DISABLE
- value: "true"
- resources:
- limits:
- memory: 512Mi
- requests:
- cpu: 100m
- memory: 200Mi
- volumeMounts:
- - name: varlog
- mountPath: /var/log
- - name: varlibdockercontainers
- mountPath: /var/lib/docker/containers
- readOnly: true
- - name: fluentconfig
- mountPath: /fluentd/etc/fluent.conf
- subPath: fluent.conf
- terminationGracePeriodSeconds: 30
- volumes:
- - name: varlog
- hostPath:
- path: /var/log
- - name: varlibdockercontainers
- hostPath:
- path: /var/lib/docker/containers
- - name: fluentconfig
- configMap:
- name: fluentdconf
你可以在此 倉庫 中查看完整示例。
現(xiàn)在,我們來看看如何將 fluentd daemonset 部署為日志代理的代碼。
- #fluentd-daemonset.yaml
- apiVersion: extensions/v1beta1
- kind: DaemonSet
- metadata:
- name: fluentd
- namespace: logging
- labels:
- app: fluentd
- kubernetes.io/cluster-service: "true"
- spec:
- selector:
- matchLabels:
- app: fluentd
- kubernetes.io/cluster-service: "true"
- template:
- metadata:
- labels:
- app: fluentd
- kubernetes.io/cluster-service: "true"
- spec:
- serviceAccount: fluentd
- containers:
- - name: fluentd
- image: fluent/fluentd-kubernetes-daemonset:v1.7.3-debian-elasticsearch7-1.0
- env:
- - name: FLUENT_ELASTICSEARCH_HOST
- value: "elasticsearch.logging.svc.cluster.local"
- - name: FLUENT_ELASTICSEARCH_PORT
- value: "9200"
- - name: FLUENT_ELASTICSEARCH_SCHEME
- value: "http"
- - name: FLUENT_ELASTICSEARCH_USER
- value: "elastic"
- - name: FLUENT_ELASTICSEARCH_PASSWORD
- valueFrom:
- secretKeyRef:
- name: efk-pw-elastic
- key: password
- - name: FLUENT_ELASTICSEARCH_SED_DISABLE
- value: "true"
- resources:
- limits:
- memory: 512Mi
- requests:
- cpu: 100m
- memory: 200Mi
- volumeMounts:
- - name: varlog
- mountPath: /var/log
- - name: varlibdockercontainers
- mountPath: /var/lib/docker/containers
- readOnly: true
- - name: fluentconfig
- mountPath: /fluentd/etc/fluent.conf
- subPath: fluent.conf
- terminationGracePeriodSeconds: 30
- volumes:
- - name: varlog
- hostPath:
- path: /var/log
- - name: varlibdockercontainers
- hostPath:
- path: /var/lib/docker/containers
- - name: fluentconfig
- configMap:
- name: fluentdconf
將這些放在一起執(zhí)行:
- kubectl apply -f fluentd-SA.yaml \
- -f fluentd-configmap.yaml \
- -f fluentd-daemonset.yaml
用于日志記錄的挎斗容器應用程序
另一種方法是使用帶有日志代理的專用挎斗容器。容器最常見的實現(xiàn)是使用 Fluentd 作為日志收集器。在企業(yè)部署中(你無需擔心一點計算資源開銷),使用 fluentd(或類似)實現(xiàn)的挎斗容器提供了集群級日志記錄的靈活性。這是因為你可以根據(jù)需要捕獲的日志類型、頻率和其它可能的調(diào)整來調(diào)整和配置收集器代理。
下圖展示了作為日志代理的挎斗容器。
Sidecar container as logging agent例如,一個吊艙運行單個容器,容器使用兩種不同的格式寫入兩個不同的日志文件。吊艙的配置文件如下:
- #log-sidecar.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
- image: busybox
- args: [/bin/sh, -c, 'tail -n+1 -f /var/log/1.log']
- volumeMounts:
- - name: varlog
- mountPath: /var/log
- volumes:
- - name: varlog
- emptyDir: {}
把它們放在一起,你可以運行這個吊艙:
- $ kubectl apply -f log-sidecar.yaml
要驗證挎斗容器是否用作日志代理,你可以執(zhí)行以下操作:
- $ kubectl logs counter count-log
預期的輸出如下所示:
- $ kubectl logs counter count-log-1
- Thu 04 Nov 2021 09:23:21 NZDT
- Thu 04 Nov 2021 09:23:22 NZDT
- Thu 04 Nov 2021 09:23:23 NZDT
- Thu 04 Nov 2021 09:23:24 NZDT
將應用程序日志直接暴露給日志后端
第三種方法(在我看來)是 Kubernetes 容器和應用程序日志最靈活的日志記錄解決方案,是將日志直接推送到日志記錄后端解決方案。盡管此模式不依賴于原生 Kubernetes 功能,但它提供了大多數(shù)企業(yè)需要的靈活性,例如:
- 擴展對網(wǎng)絡協(xié)議和輸出格式的更廣泛支持。
- 提供負載均衡能力并提高性能。
- 可配置為通過上游聚合接受復雜的日志記錄要求。
因為這第三種方法通過直接從每個應用程序推送日志來依賴非 Kubernetes 功能,所以它超出了 Kubernetes 的范圍。
結論
Kubernetes 日志記錄工具是企業(yè)部署 Kubernetes 集群的一個非常重要的組件。我討論了三種可能的可用模式。你需要找到適合你需求的模式。
如上所述,使用 daemonset 的節(jié)點級日志記錄是最容易使用的部署模式,但它也有一些限制,可能不適合你的組織的需要。另一方面,挎斗 模式提供了靈活性和自定義,允許你自定義要捕獲的日志類型,但是會提高計算機的資源開銷。最后,將應用程序日志直接暴露給后端日志工具是另一種允許進一步定制的誘人方法。
選擇在你,你只需要找到適合你組織要求的方法。