當運行在?docker?容器中的應用程序打印日志時,日志會輸出到標準輸出流 stdout 和標準錯誤流 stderr。容器日志驅動可以訪問這些流,并將日志發送到文件、本機運行的日志收集器或遠端的日志服務端點(endpoint)。本文將介紹選擇不同的日志驅動及配置對容器應用的性能和穩定性帶來的影響,以及推薦最能滿足日志記錄需求和性能的日志驅動及配置。
選擇日志驅動
Docker 提供了若干內置的日志驅動,不同的日志驅動會把日志分發到不同的地方,每個容器只能只能指定一種日志驅動。
Docker?使用?json-file 作為默認日志驅動,該驅動把日志以 json 的格式寫入宿主機指定文件:
/var/lib/docker/containers/{CONTAINER_ID}-json.log
下面是由 hello world 鏡像啟動的容器創建的 json?日志實例:
{"log":"Hello from Docker!\n","stream":"stdout","time":"2022-05-29T22:51:31.549390877Z"}
{"log":"This message shows that your installation appears to be working correctly.\n","stream":"stdout","time":"2022-05-29T22:51:31.549396749Z"}
也可以通過命令行直接查看日志:
docker?logs?<CONTAINER_ID>?or?docker?logs?<CONTAINER_NAME>
Hello from Docker!
This message shows that your installation appears to be working correctly.
其中,docker?提供了以下內置日志驅動:
none
禁用日志,且 docker logs 指令不返回任何內容。
local
保存日志內容到本地文件并對內容進行壓縮。
json-file
以 json 格式保存日志內容到本地文件,默認日志驅動。
syslog
保存日志內容到?syslog,syslog daemon 必須運行在宿主機上。
journald
保存日志內容到?journald,journald?daemon?必須運行在宿主機上。
gelf
保存日志內容到 GELF - Graylog Extended Log Format?端點,如 Graylog 和 Logstash。
fluentd
保存日志內容到?fluentd,fluentd?daemon?必須運行在宿主機上。
awslogs
保存日志內容到 Amazon CloudWatch。
splunk
保存日志內容到?splunk。
etwlogs
保存日志內容到?ETW - Event Tracing for Windows,只能在 Windows 平臺上使用。
gcplogs
保存日志內容到 GCP - Google Cloud Platform。
logentries
保存日志內容到?Rapid7 Logentries。
配置日志驅動
Docker 容器默認使用?json-file 日志驅動,大部分情況下,建議直接使用該驅動。如果你的應用場景確實需要使用其它驅動,可以在 docker run 指令中使用?--log-driver?選項來覆蓋默認驅動,以下是使用?fluntd?作為日志驅動的示例:
docker?run?--log-driver?fluentd?httpd:latest
也可以通過修改?daemon.json?來配置日志驅動,以下是使用?fluntd?作為日志驅動的示例:
{"log-driver": "fluentd","log-opts": {"fluentd-address": "fluentd-ip:fluentd-port"}
}
重啟 docker 使上述配置生效,后續創建的容器都將使用?fluentd 作為日志驅動,并把日志發送到指定的 fluentd address。
日志分發模式
無論選擇了什么日志驅動,都可以指定日志的分發模式:阻塞或非阻塞。
阻塞模式
阻塞模式是日志分發的默認模式,在該模式下,日志每次發送時會阻塞應用程序,以保證日志能正常到達指定位置,這會增加應用程序的處理延遲,降低應用程序的性能。如果日志驅動一直處于繁忙,容器會延遲應用程序的其他任務,直到日志傳輸完畢。
阻塞模式對應用程序性能的潛在影響取決于選擇的日志驅動。例如,json-file 日志驅動日志寫入速度非常快,并且寫入的是本地文件,所以不太可能出現阻塞并導致延遲。相反的,gcplogs?和?awslogs?這些需要打開遠程連接的日志驅動,很可能會出現長時間的阻塞,并對應用程序帶來明顯的延遲。
非阻塞模式
在非阻塞模式下,容器首先把日志寫入內存環形緩沖區,直到日志驅動可以處理它們為止。即使日志驅動很忙,容器也可以立即將日志輸出到緩沖區,并繼續執行應用程序。這確保了大量日志活動不會影響容器中運行的應用程序的性能。
與阻塞模式相比,非阻塞模式不能保證日志能正常到達指定位置。如果應用程序產生日志的速度快于日志驅動處理日志的速度,環形緩沖區的內存將會耗盡。如果發生這種情況,緩沖區較早的 日志將被刪除,然后才能傳遞給日志驅動,造成日志丟失。可以通過?max-buffer-size?選項來設置環形緩沖區的大小,max-buffer-size?的默認值為?1MB。如果宿主機有足夠內存的話,
配置分發模式
阻塞模式是日志分發的默認模式,可以在創建容器時使用--log-opt選項來設置非阻塞模式:
docker?run?--log-opt?mode=non-blocking?httpd:latest
也可以通過修改?daemon.json?來配置分發模式:
{"log-driver": "fluentd","log-opts": {"fluentd-address": "fluentd-ip:fluentd-port","mode": "non-blocking"}
}
選擇適合的日志驅動及分發模式
大部分場景下,建議使用阻塞模式 +?json-file,日志寫入本地文件速度非常快,在阻塞模式下能夠捕獲所有日志,但不會降低應用程序性能。
可以使用日志收集 agent,如 fluentd/fluent-bit?來 tail 本地日志文件,并將日志轉發到日志中心。json 格式的日志易于解析,可以按屬性篩選日志,識別日志趨勢并作相應警報,以及對容器應用進行分析。
阻塞模式 +?json-file?雖然能滿足大部分應用場景,但在某些情況下,可能需要考慮其它的日志驅動及分發模式組合。
磁盤密集型應用
如果應用程序產生大量日志并頻繁執行 I/O 操作,請考慮使用非阻塞模式 +?json-file。該組合可保持應用程序的性能,同時仍可提供可靠的結構化日志記錄。將日志寫入本地存儲很快,環形緩沖區不太可能被填滿。如果不需要支持記錄峰值時的日志(此時可能會填滿環形緩沖區),那么非阻塞模式 +?json-file 可以捕獲所有的日志,而不會中斷應用程序。
不能使用本地日志的內存密集型應用
如果應用程序本身很需要內存資源,并且日志不能存放在本地,需要使用?gcplogs 或 awslogs 等驅動把日志發送到遠端時,應考慮阻塞模式。因為如果出現網絡阻塞時,已無足夠內存可分配給環形緩沖區。
雖然使用阻塞模式可以確保捕獲所有日志,但通常不建議在阻塞模式下使用 json-file 以外的日志驅動,因為應用程序的性能可能會受到影響。
對于日志無法存放到本地,但性能要求又高于日志可靠性的應用程序,建議為環形緩沖區提供足夠的內存,并使用非阻塞模式。這樣可以確保應用程序性能不會受到日志記錄的影響,同時也為捕獲主要日志提供了足夠的空間。
參考總結
以上就是本文希望分享的內容,如果大家有什么問題,歡迎在公眾號 - 跬步之巔留言交流。