W3Cschool
恭喜您成為首批注冊用戶
獲得88經(jīng)驗值獎勵
應用日志可以讓你了解應用內(nèi)部的運行狀況。日志對調(diào)試問題和監(jiān)控集群活動非常有用。 大部分現(xiàn)代化應用都有某種日志記錄機制。同樣地,容器引擎也被設計成支持日志記錄。 針對容器化應用,最簡單且最廣泛采用的日志記錄方式就是寫入標準輸出和標準錯誤流。
但是,由容器引擎或運行時提供的原生功能通常不足以構成完整的日志記錄方案。 例如,如果發(fā)生容器崩潰、Pod 被逐出或節(jié)點宕機等情況,你可能想訪問應用日志。 在集群中,日志應該具有獨立的存儲和生命周期,與節(jié)點、Pod 或容器的生命周期相獨立。 這個概念叫 集群級的日志 。
集群級日志架構需要一個獨立的后端用來存儲、分析和查詢?nèi)罩尽?nbsp;Kubernetes 并不為日志數(shù)據(jù)提供原生的存儲解決方案。 相反,有很多現(xiàn)成的日志方案可以集成到 Kubernetes 中。 下面各節(jié)描述如何在節(jié)點上處理和存儲日志。
這里的示例使用包含一個容器的 Pod 規(guī)約,每秒鐘向標準輸出寫入數(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']
用下面的命令運行 Pod:
kubectl apply -f https://k8s.io/examples/debug/counter-pod.yaml
輸出結果為:
pod/counter created
像下面這樣,使用 ?kubectl logs
? 命令獲取日志:
kubectl logs counter
輸出結果為:
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
? 檢索之前容器實例的日志。 如果 Pod 中有多個容器,你應該為該命令附加容器名以訪問對應容器的日志。 詳見 ?kubectl logs
? 文檔。 如果 Pod 有多個容器,你應該為該命令附加容器名以訪問對應容器的日志, 使用 ?-c
? 標志來指定要訪問的容器的日志,如下所示:
kubectl logs counter -c count
詳見 ?kubectl logs
? 文檔。
容器化應用寫入 ?stdout
?和 ?stderr
?的任何數(shù)據(jù),都會被容器引擎捕獲并被重定向到某個位置。 例如,Docker 容器引擎將這兩個輸出流重定向到某個 日志驅(qū)動(Logging Driver) , 該日志驅(qū)動在 Kubernetes 中配置為以 JSON 格式寫入文件。
Note: Docker JSON 日志驅(qū)動將日志的每一行當作一條獨立的消息。 該日志驅(qū)動不直接支持多行消息。你需要在日志代理級別或更高級別處理多行消息。
默認情況下,如果容器重啟,kubelet 會保留被終止的容器日志。 如果 Pod 在工作節(jié)點被驅(qū)逐,該 Pod 中所有的容器也會被驅(qū)逐,包括容器日志。
節(jié)點級日志記錄中,需要重點考慮實現(xiàn)日志的輪轉(zhuǎn),以此來保證日志不會消耗節(jié)點上全部可用空間。 Kubernetes 并不負責輪轉(zhuǎn)日志,而是通過部署工具建立一個解決問題的方案。 例如,在用 ?kube-up.sh
? 部署的 Kubernetes 集群中,存在一個 ?logrotate
?,每小時運行一次。 你也可以設置容器運行時來自動地輪轉(zhuǎn)應用日志。
例如,你可以找到關于 ?kube-up.sh
? 為 GCP 環(huán)境的 COS 鏡像設置日志的詳細信息, 腳本為 ?configure-helper
? 腳本。
當使用某 CRI 容器運行時 時,kubelet 要負責對日志進行輪換,并 管理日志目錄的結構。kubelet 將此信息發(fā)送給 CRI 容器運行時,后者 將容器日志寫入到指定的位置。在 kubelet 配置文件 中的兩個 kubelet 參數(shù) ?containerLogMaxSize
?和 ?containerLogMaxFiles
?可以用來配置每個日志文件的最大長度和每個容器可以生成的日志文件個數(shù)上限。
當運行 kubectl logs 時, 節(jié)點上的 kubelet 處理該請求并直接讀取日志文件,同時在響應中返回日志文件內(nèi)容。
Note: 如果有外部系統(tǒng)執(zhí)行日志輪轉(zhuǎn)或者使用了 CRI 容器運行時,那么 ?
kubectl logs
? 僅可查詢到最新的日志內(nèi)容。 比如,對于一個 10MB 大小的文件,通過 ?logrotate
?執(zhí)行輪轉(zhuǎn)后生成兩個文件, 一個 10MB 大小,一個為空,?kubectl logs
? 返回最新的日志文件,而該日志文件 在這個例子中為空。
系統(tǒng)組件有兩種類型:在容器中運行的和不在容器中運行的。例如:
在使用 systemd 機制的服務器上,kubelet 和容器容器運行時將日志寫入到 journald 中。 如果沒有 systemd,它們將日志寫入到 ?/var/log
? 目錄下的 ?.log
? 文件中。 容器中的系統(tǒng)組件通常將日志寫到 ?/var/log
? 目錄,繞過了默認的日志機制。 他們使用 klog 日志庫。 你可以在日志開發(fā)文檔 找到這些組件的日志告警級別約定。
和容器日志類似,?/var/log
? 目錄中的系統(tǒng)組件日志也應該被輪轉(zhuǎn)。 通過腳本 ?kube-up.sh
? 啟動的 Kubernetes 集群中,日志被工具 ?logrotate
?執(zhí)行每日輪轉(zhuǎn),或者日志大小超過 100MB 時觸發(fā)輪轉(zhuǎn)。
雖然Kubernetes沒有為集群級日志記錄提供原生的解決方案,但你可以考慮幾種常見的方法。 以下是一些選項:
你可以通過在每個節(jié)點上使用 節(jié)點級的日志記錄代理 來實現(xiàn)集群級日志記錄。 日志記錄代理是一種用于暴露日志或?qū)⑷罩就扑偷胶蠖说膶S霉ぞ摺?nbsp;通常,日志記錄代理程序是一個容器,它可以訪問包含該節(jié)點上所有應用程序容器的日志文件的目錄。
由于日志記錄代理必須在每個節(jié)點上運行,通常可以用 ?DaemonSet
?的形式運行該代理。 節(jié)點級日志在每個節(jié)點上僅創(chuàng)建一個代理,不需要對節(jié)點上的應用做修改。
容器向標準輸出和標準錯誤輸出寫出數(shù)據(jù),但在格式上并不統(tǒng)一。 節(jié)點級代理 收集這些日志并將其進行轉(zhuǎn)發(fā)以完成匯總。
你可以通過以下方式之一使用邊車(Sidecar)容器:
利用邊車容器向自己的 ?stdout
?和 ?stderr
?傳輸流的方式, 你就可以利用每個節(jié)點上的 kubelet 和日志代理來處理日志。 邊車容器從文件、套接字或 journald 讀取日志。 每個邊車容器向自己的 ?stdout
?和 ?stderr
?流中輸出日志。
這種方法允許你將日志流從應用程序的不同部分分離開,其中一些可能缺乏對寫入 ?stdout
?或 ?stderr
?的支持。重定向日志背后的邏輯是最小的,因此它的開銷幾乎可以忽略不計。 另外,因為 ?stdout
?、?stderr
?由 kubelet 處理,你可以使用內(nèi)置的工具 ?kubectl logs
?。
例如,某 Pod 中運行一個容器,該容器向兩個文件寫不同格式的日志。 下面是這個 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: {}
不建議在同一個日志流中寫入不同格式的日志條目,即使你成功地將其重定向到容器的 ?stdout
?流。相反,你可以創(chuàng)建兩個邊車容器。每個邊車容器可以從共享卷 跟蹤特定的日志文件,并將文件內(nèi)容重定向到各自的 ?stdout
?流。
下面是運行兩個邊車容器的 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)在當你運行這個 Pod 時,你可以運行如下命令分別訪問每個日志流:
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é)點級代理會自動獲取這些日志流,而無需進一步配置。 如果你愿意,你也可以配置代理程序來解析源容器的日志行。
注意,盡管 CPU 和內(nèi)存使用率都很低(以多個 CPU 毫核指標排序或者按內(nèi)存的兆字節(jié)排序), 向文件寫日志然后輸出到 ?stdout
?流仍然會成倍地增加磁盤使用率。 如果你的應用向單一文件寫日志,通常最好設置 ?/dev/stdout
? 作為目標路徑, 而不是使用流式的邊車容器方式。
應用本身如果不具備輪轉(zhuǎn)日志文件的功能,可以通過邊車容器實現(xiàn)。 該方式的一個例子是運行一個小的、定期輪轉(zhuǎn)日志的容器。 然而,還是推薦直接使用 ?stdout
?和 ?stderr
?,將日志的輪轉(zhuǎn)和保留策略 交給 kubelet。
如果節(jié)點級日志記錄代理程序?qū)τ谀愕膱鼍皝碚f不夠靈活,你可以創(chuàng)建一個 帶有單獨日志記錄代理的邊車容器,將代理程序?qū)iT配置為與你的應用程序一起運行。
Note:
在邊車容器中使用日志代理會帶來嚴重的資源損耗。 此外,你不能使用 ?kubectl logs
? 命令訪問日志,因為日志并沒有被 kubelet 管理。
下面是兩個配置文件,可以用來實現(xiàn)一個帶日志代理的邊車容器。 第一個文件包含用來配置 fluentd 的 ConfigMap。
apiVersion: v1
kind: ConfigMap
metadata:
name: fluentd-config
data:
fluentd.conf: |
<source>
type tail
format none
path /var/log/1.log
pos_file /var/log/1.log.pos
tag count.format1
</source>
<source>
type tail
format none
path /var/log/2.log
pos_file /var/log/2.log.pos
tag count.format2
</source>
<match **>
type google_cloud
</match>
Note:
要進一步了解如何配置 fluentd,請參考 fluentd 官方文檔。
第二個文件描述了運行 fluentd 邊車容器的 Pod 。 flutend 通過 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 替換為任何日志代理,從應用容器內(nèi) 的任何來源讀取數(shù)據(jù)。
從各個應用中直接暴露和推送日志數(shù)據(jù)的集群日志機制 已超出 Kubernetes 的范圍。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網(wǎng)安備35020302033924號
違法和不良信息舉報電話:173-0602-2364|舉報郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: