新聞中心
日志架構(gòu)
應(yīng)用日志可以讓你了解應(yīng)用內(nèi)部的運(yùn)行狀況。日志對(duì)調(diào)試問(wèn)題和監(jiān)控集群活動(dòng)非常有用。 大部分現(xiàn)代化應(yīng)用都有某種日志記錄機(jī)制。同樣地,容器引擎也被設(shè)計(jì)成支持日志記錄。 針對(duì)容器化應(yīng)用,最簡(jiǎn)單且最廣泛采用的日志記錄方式就是寫入標(biāo)準(zhǔn)輸出和標(biāo)準(zhǔn)錯(cuò)誤流。

但是,由容器引擎或運(yùn)行時(shí)提供的原生功能通常不足以構(gòu)成完整的日志記錄方案。 例如,如果發(fā)生容器崩潰、Pod 被逐出或節(jié)點(diǎn)宕機(jī)等情況,你可能想訪問(wèn)應(yīng)用日志。 在集群中,日志應(yīng)該具有獨(dú)立的存儲(chǔ)和生命周期,與節(jié)點(diǎn)、Pod 或容器的生命周期相獨(dú)立。 這個(gè)概念叫 集群級(jí)的日志 。
集群級(jí)日志架構(gòu)需要一個(gè)獨(dú)立的后端用來(lái)存儲(chǔ)、分析和查詢?nèi)罩尽?nbsp;Kubernetes 并不為日志數(shù)據(jù)提供原生的存儲(chǔ)解決方案。 相反,有很多現(xiàn)成的日志方案可以集成到 Kubernetes 中。 下面各節(jié)描述如何在節(jié)點(diǎn)上處理和存儲(chǔ)日志。
Kubernetes 中的基本日志記錄
這里的示例使用包含一個(gè)容器的 Pod 規(guī)約,每秒鐘向標(biāo)準(zhǔn)輸出寫入數(shù)據(jù)。
apiVersion: v1
kind: Pod
metadata:
name: counter
spec:
containers:
- name: count
image: busybox:1.28
args: [/bin/sh, -c,
'i=0; while true; do echo "$i: $(date)"; i=$((i+1)); sleep 1; done']
用下面的命令運(yùn)行 Pod:
kubectl apply -f https://K8S.io/examples/debug/counter-pod.yaml
輸出結(jié)果為:
pod/counter created
像下面這樣,使用 ?kubectl logs? 命令獲取日志:
kubectl logs counter
輸出結(jié)果為:
0: Mon Jan 1 00:00:00 UTC 2001
1: Mon Jan 1 00:00:01 UTC 2001
2: Mon Jan 1 00:00:02 UTC 2001
...你可以使用命令 ?kubectl logs --previous? 檢索之前容器實(shí)例的日志。 如果 Pod 中有多個(gè)容器,你應(yīng)該為該命令附加容器名以訪問(wèn)對(duì)應(yīng)容器的日志。 詳見 ?kubectl logs? 文檔。 如果 Pod 有多個(gè)容器,你應(yīng)該為該命令附加容器名以訪問(wèn)對(duì)應(yīng)容器的日志, 使用 ?-c? 標(biāo)志來(lái)指定要訪問(wèn)的容器的日志,如下所示:
kubectl logs counter -c count
詳見 ?kubectl logs? 文檔。
節(jié)點(diǎn)級(jí)日志記錄
容器化應(yīng)用寫入 ?stdout ?和 ?stderr ?的任何數(shù)據(jù),都會(huì)被容器引擎捕獲并被重定向到某個(gè)位置。 例如,Docker 容器引擎將這兩個(gè)輸出流重定向到某個(gè) 日志驅(qū)動(dòng)(Logging Driver) , 該日志驅(qū)動(dòng)在 Kubernetes 中配置為以 JSON 格式寫入文件。
Note: Docker JSON 日志驅(qū)動(dòng)將日志的每一行當(dāng)作一條獨(dú)立的消息。 該日志驅(qū)動(dòng)不直接支持多行消息。你需要在日志代理級(jí)別或更高級(jí)別處理多行消息。
默認(rèn)情況下,如果容器重啟,kubelet 會(huì)保留被終止的容器日志。 如果 Pod 在工作節(jié)點(diǎn)被驅(qū)逐,該 Pod 中所有的容器也會(huì)被驅(qū)逐,包括容器日志。
節(jié)點(diǎn)級(jí)日志記錄中,需要重點(diǎn)考慮實(shí)現(xiàn)日志的輪轉(zhuǎn),以此來(lái)保證日志不會(huì)消耗節(jié)點(diǎn)上全部可用空間。 Kubernetes 并不負(fù)責(zé)輪轉(zhuǎn)日志,而是通過(guò)部署工具建立一個(gè)解決問(wèn)題的方案。 例如,在用 ?kube-up.sh? 部署的 Kubernetes 集群中,存在一個(gè) ?logrotate?,每小時(shí)運(yùn)行一次。 你也可以設(shè)置容器運(yùn)行時(shí)來(lái)自動(dòng)地輪轉(zhuǎn)應(yīng)用日志。
例如,你可以找到關(guān)于 ?kube-up.sh? 為 GCP 環(huán)境的 COS 鏡像設(shè)置日志的詳細(xì)信息, 腳本為 ?configure-helper? 腳本。
當(dāng)使用某 CRI 容器運(yùn)行時(shí) 時(shí),kubelet 要負(fù)責(zé)對(duì)日志進(jìn)行輪換,并 管理日志目錄的結(jié)構(gòu)。kubelet 將此信息發(fā)送給 CRI 容器運(yùn)行時(shí),后者 將容器日志寫入到指定的位置。在 kubelet 配置文件 中的兩個(gè) kubelet 參數(shù) ?containerLogMaxSize ?和 ?containerLogMaxFiles ?可以用來(lái)配置每個(gè)日志文件的最大長(zhǎng)度和每個(gè)容器可以生成的日志文件個(gè)數(shù)上限。
當(dāng)運(yùn)行 kubectl logs 時(shí), 節(jié)點(diǎn)上的 kubelet 處理該請(qǐng)求并直接讀取日志文件,同時(shí)在響應(yīng)中返回日志文件內(nèi)容。
Note: 如果有外部系統(tǒng)執(zhí)行日志輪轉(zhuǎn)或者使用了 CRI 容器運(yùn)行時(shí),那么 ?
kubectl logs? 僅可查詢到最新的日志內(nèi)容。 比如,對(duì)于一個(gè) 10MB 大小的文件,通過(guò) ?logrotate?執(zhí)行輪轉(zhuǎn)后生成兩個(gè)文件, 一個(gè) 10MB 大小,一個(gè)為空,?kubectl logs? 返回最新的日志文件,而該日志文件 在這個(gè)例子中為空。
系統(tǒng)組件日志
系統(tǒng)組件有兩種類型:在容器中運(yùn)行的和不在容器中運(yùn)行的。例如:
- 在容器中運(yùn)行的 kube-scheduler 和 kube-proxy。
- 不在容器中運(yùn)行的 kubelet 和容器運(yùn)行時(shí)。
在使用 systemd 機(jī)制的服務(wù)器上,kubelet 和容器容器運(yùn)行時(shí)將日志寫入到 journald 中。 如果沒(méi)有 systemd,它們將日志寫入到 ?/var/log? 目錄下的 ?.log? 文件中。 容器中的系統(tǒng)組件通常將日志寫到 ?/var/log? 目錄,繞過(guò)了默認(rèn)的日志機(jī)制。 他們使用 klog 日志庫(kù)。 你可以在日志開發(fā)文檔 找到這些組件的日志告警級(jí)別約定。
和容器日志類似,?/var/log? 目錄中的系統(tǒng)組件日志也應(yīng)該被輪轉(zhuǎn)。 通過(guò)腳本 ?kube-up.sh? 啟動(dòng)的 Kubernetes 集群中,日志被工具 ?logrotate ?執(zhí)行每日輪轉(zhuǎn),或者日志大小超過(guò) 100MB 時(shí)觸發(fā)輪轉(zhuǎn)。
集群級(jí)日志架構(gòu)
雖然Kubernetes沒(méi)有為集群級(jí)日志記錄提供原生的解決方案,但你可以考慮幾種常見的方法。 以下是一些選項(xiàng):
- 使用在每個(gè)節(jié)點(diǎn)上運(yùn)行的節(jié)點(diǎn)級(jí)日志記錄代理。
- 在應(yīng)用程序的 Pod 中,包含專門記錄日志的邊車(Sidecar)容器。
- 將日志直接從應(yīng)用程序中推送到日志記錄后端。
使用節(jié)點(diǎn)級(jí)日志代理
你可以通過(guò)在每個(gè)節(jié)點(diǎn)上使用 節(jié)點(diǎn)級(jí)的日志記錄代理 來(lái)實(shí)現(xiàn)集群級(jí)日志記錄。 日志記錄代理是一種用于暴露日志或?qū)⑷罩就扑偷胶蠖说膶S霉ぞ摺?nbsp;通常,日志記錄代理程序是一個(gè)容器,它可以訪問(wèn)包含該節(jié)點(diǎn)上所有應(yīng)用程序容器的日志文件的目錄。
由于日志記錄代理必須在每個(gè)節(jié)點(diǎn)上運(yùn)行,通??梢杂?nbsp;?DaemonSet ?的形式運(yùn)行該代理。 節(jié)點(diǎn)級(jí)日志在每個(gè)節(jié)點(diǎn)上僅創(chuàng)建一個(gè)代理,不需要對(duì)節(jié)點(diǎn)上的應(yīng)用做修改。
容器向標(biāo)準(zhǔn)輸出和標(biāo)準(zhǔn)錯(cuò)誤輸出寫出數(shù)據(jù),但在格式上并不統(tǒng)一。 節(jié)點(diǎn)級(jí)代理 收集這些日志并將其進(jìn)行轉(zhuǎn)發(fā)以完成匯總。
使用 sidecar 容器運(yùn)行日志代理
你可以通過(guò)以下方式之一使用邊車(Sidecar)容器:
- 邊車容器將應(yīng)用程序日志傳送到自己的標(biāo)準(zhǔn)輸出。
- 邊車容器運(yùn)行一個(gè)日志代理,配置該日志代理以便從應(yīng)用容器收集日志。
傳輸數(shù)據(jù)流的 sidecar 容器
利用邊車容器向自己的 ?stdout ?和 ?stderr ?傳輸流的方式, 你就可以利用每個(gè)節(jié)點(diǎn)上的 kubelet 和日志代理來(lái)處理日志。 邊車容器從文件、套接字或 journald 讀取日志。 每個(gè)邊車容器向自己的 ?stdout ?和 ?stderr ?流中輸出日志。
這種方法允許你將日志流從應(yīng)用程序的不同部分分離開,其中一些可能缺乏對(duì)寫入 ?stdout ?或 ?stderr ?的支持。重定向日志背后的邏輯是最小的,因此它的開銷幾乎可以忽略不計(jì)。 另外,因?yàn)?nbsp;?stdout?、?stderr ?由 kubelet 處理,你可以使用內(nèi)置的工具 ?kubectl logs?。
例如,某 Pod 中運(yùn)行一個(gè)容器,該容器向兩個(gè)文件寫不同格式的日志。 下面是這個(gè) pod 的配置文件:
apiVersion: v1
kind: Pod
metadata:
name: counter
spec:
containers:
- name: count
image: busybox:1.28
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: {}
不建議在同一個(gè)日志流中寫入不同格式的日志條目,即使你成功地將其重定向到容器的 ?stdout ?流。相反,你可以創(chuàng)建兩個(gè)邊車容器。每個(gè)邊車容器可以從共享卷 跟蹤特定的日志文件,并將文件內(nèi)容重定向到各自的 ?stdout ?流。
下面是運(yùn)行兩個(gè)邊車容器的 Pod 的配置文件:
apiVersion: v1
kind: Pod
metadata:
name: counter
spec:
containers:
- name: count
image: busybox:1.28
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:1.28
args: [/bin/sh, -c, 'tail -n+1 -F /var/log/1.log']
volumeMounts:
- name: varlog
mountPath: /var/log
- name: count-log-2
image: busybox:1.28
args: [/bin/sh, -c, 'tail -n+1 -F /var/log/2.log']
volumeMounts:
- name: varlog
mountPath: /var/log
volumes:
- name: varlog
emptyDir: {}
現(xiàn)在當(dāng)你運(yùn)行這個(gè) Pod 時(shí),你可以運(yùn)行如下命令分別訪問(wèn)每個(gè)日志流:
kubectl logs counter count-log-1
輸出為:
0: Mon Jan 1 00:00:00 UTC 2001
1: Mon Jan 1 00:00:01 UTC 2001
2: Mon Jan 1 00:00:02 UTC 2001
...kubectl logs counter count-log-2
輸出為:
Mon Jan 1 00:00:00 UTC 2001 INFO 0
Mon Jan 1 00:00:01 UTC 2001 INFO 1
Mon Jan 1 00:00:02 UTC 2001 INFO 2
...集群中安裝的節(jié)點(diǎn)級(jí)代理會(huì)自動(dòng)獲取這些日志流,而無(wú)需進(jìn)一步配置。 如果你愿意,你也可以配置代理程序來(lái)解析源容器的日志行。
注意,盡管 CPU 和內(nèi)存使用率都很低(以多個(gè) CPU 毫核指標(biāo)排序或者按內(nèi)存的兆字節(jié)排序), 向文件寫日志然后輸出到 ?stdout ?流仍然會(huì)成倍地增加磁盤使用率。 如果你的應(yīng)用向單一文件寫日志,通常最好設(shè)置 ?/dev/stdout? 作為目標(biāo)路徑, 而不是使用流式的邊車容器方式。
應(yīng)用本身如果不具備輪轉(zhuǎn)日志文件的功能,可以通過(guò)邊車容器實(shí)現(xiàn)。 該方式的一個(gè)例子是運(yùn)行一個(gè)小的、定期輪轉(zhuǎn)日志的容器。 然而,還是推薦直接使用 ?stdout ?和 ?stderr?,將日志的輪轉(zhuǎn)和保留策略 交給 kubelet。
具有日志代理功能的邊車容器
如果節(jié)點(diǎn)級(jí)日志記錄代理程序?qū)τ谀愕膱?chǎng)景來(lái)說(shuō)不夠靈活,你可以創(chuàng)建一個(gè) 帶有單獨(dú)日志記錄代理的邊車容器,將代理程序?qū)iT配置為與你的應(yīng)用程序一起運(yùn)行。
Note:
在邊車容器中使用日志代理會(huì)帶來(lái)嚴(yán)重的資源損耗。 此外,你不能使用 ?
kubectl logs? 命令訪問(wèn)日志,因?yàn)槿罩静](méi)有被 kubelet 管理。
下面是兩個(gè)配置文件,可以用來(lái)實(shí)現(xiàn)一個(gè)帶日志代理的邊車容器。 第一個(gè)文件包含用來(lái)配置 fluentd 的 ConfigMap。
apiVersion: v1
kind: ConfigMap
metadata:
name: fluentd-config
data:
fluentd.conf: |
type tail
format none
path /var/log/1.log
pos_file /var/log/1.log.pos
tag count.format1
type tail
format none
path /var/log/2.log
pos_file /var/log/2.log.pos
tag count.format2
type google_cloud
Note:
要進(jìn)一步了解如何配置 fluentd,請(qǐng)參考 fluentd 官方文檔。
第二個(gè)文件描述了運(yùn)行 fluentd 邊車容器的 Pod 。 flutend 通過(guò) Pod 的掛載卷獲取它的配置數(shù)據(jù)。
apiVersion: v1
kind: Pod
metadata:
name: counter
spec:
containers:
- name: count
image: busybox:1.28
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 替換為任何日志代理,從應(yīng)用容器內(nèi) 的任何來(lái)源讀取數(shù)據(jù)。
從應(yīng)用中直接暴露日志目錄
從各個(gè)應(yīng)用中直接暴露和推送日志數(shù)據(jù)的集群日志機(jī)制 已超出 Kubernetes 的范圍。
文章標(biāo)題:創(chuàng)新互聯(lián)kubernetes教程:Kubernetes 日志架構(gòu)
URL分享:http://fisionsoft.com.cn/article/djogcep.html


咨詢
建站咨詢
