Docker 官方出品丨Docker 最佳實踐之日誌記錄篇(二)
出品丨Docker公司(ID:docker-cn)
編譯丨小東
每週一、三、五晚6點10分 與您不見不散
簡 介
在傳統上,設計和實現集中的日誌記錄總是成為馬後炮。要等到各種問題出現,集中的日誌記錄成為優先事項,人們才會想到用這樣的解決方案查詢、檢視和分析日誌,以找到問題的根本原因。但是到了容器時代,在設計使用 Docker 企業版 (Docker EE) 的容器即服務 (CaaS) 平臺時,優先解決集中式日誌記錄是至關重要的。隨著在容器中部署的微服務數量不斷增多,它們以日誌(或事件)形式產生的資料量會發生指數增長,點選以下標題,回顧第一部分內容:
&應用日誌驅動
Docker 提供了多種可用於管理應用日誌的日誌記錄驅動。請檢視 Docker 文件獲取完整列表,以及關於如何使用它們的詳細資訊。
一般而言,如果您已經設定了日誌記錄基礎架構,就應該對此現成基礎架構使用日誌記錄驅動。如果您尚沒有現成的日誌記錄系統,那麼需要在此處強調某些方面的優點和缺點。
驅動 | 優點 | 缺點 |
無 | 超級安全,因為不記錄任何資訊 | 沒有日誌會大大增加故障排除的難度 |
json-file | 預設驅動,docker logs 可使用它,支援標籤 | 日誌駐留在本地,並不聚合,如果沒有限制措施,日誌可能會佔滿本地磁碟 |
syslog | 大多數機器都附帶 syslog,它是唯一支援 TLS 以實現加密日誌傳輸的驅動,支援標籤 | 需要設定為具有高度可用性 (HA),否則如果其不可用,容器啟動時可能發生問題 |
journald | docker logs 也可使用此驅動,因為它在本地記錄日誌 - 日誌聚合停止執行也不會造成影響,它還會收集 Docker 守護程序日誌 | 由於日誌是二進位制格式的,需要執行附加步驟才能將其傳輸到日誌收集器,不支援標籤 |
gelf | 預設情況下提供可加索引的欄位(container id、host、container name 等),支援標籤 | 僅支援 UDP 協議,不支援 docker logs |
fluentd | fluentd 預設提供 container_name 和 container_id 欄位,支援多路輸出 | 對於本地日誌不支援 docker logs |
awslogs | 使用 Amazon Web Services 時可方便地整合,減少了需要維護的基礎架構,支援標籤 | 用於混合雲配置或本地部署安裝時並非最理想的選擇,不支援 docker logs |
splunk | 可方便地與 Splunk 整合,支援 TLS,高度可配置,支援標籤,附加指標 | Splunk 需要有高可用性,否則容器啟動時可能發生問題,不支援 docker logs |
etwlogs | 用於在 Windows 上進行日誌記錄的通用框架,預設可索引值 | 僅可在 Windows 上工作,必須使用其他實用程式將這些日誌從 Windows 機器轉移到日誌聚合 |
gcplogs | 可簡單地與 Google Compute 整合,減少了需要維護的基礎架構,支援標籤 | 用於混合雲配置或本地部署安裝時並非最理想的選擇,不支援 docker logs |
應用日誌驅動注意事項
選擇應用日誌驅動時,請考慮下列因素:
如果日誌資料高度敏感,則 syslog 和 splunk 是很好的選擇,因為可以配置他們使用 TLS 來傳輸日誌。
journald 日誌驅動非常適合用於保留 docker logs 的使用情況以及記錄 Docker 守護程序日誌。此驅動既方便故障排除,又實現日誌可移植性。此驅動的另一個優點是,日誌將首先在本地寫入,因此減少了對日誌記錄基礎架構的依賴。
如果 Docker EE 叢集僅在一個雲提供商處存在,則可以使用 awslogs 或 gcplogs。
如果存在現有的 Splunk 安裝,則應使用 splunk 日誌驅動。
如果環境中存在可以儲存日誌的 NoSQL 資料庫,那麼 gelf 和 fluentd 日誌驅動都是好選擇。
對於開發或測試環境,如果檢視日誌流比檢視索引並搜尋日誌更為有效,那麼使用 json-file 或 journald 可能很有幫助。(如果使用 json-file,請考慮傳遞 max-size 和 max-file 選項,以免日誌填滿檔案系統。)
日誌記錄驅動設定導引
要實現全系統的日誌記錄,請在 /etc/docker/daemon.json 中建立一個條目。例如,使用下列程式碼來啟用 gelf 輸出外掛:
{
“log-driver":“gelf",
“log-opts":{
"gelf-address":“udp://1.2.3.4:12201",
“tag":"{{.ImageName}}/{{.Name}}/{{.ID}}"
}
}
然後重啟 Docker 守護程序。所有日誌記錄驅動都可以通過使用 /etc/docker/daemon.json 檔案以類似的方式配置。在上面的示例中使用了 gelf 日誌驅動,tag 欄位設定在收集日誌時可以搜尋和索引的附加資料。請參閱每種日誌記錄驅動的文件,瞭解可以從日誌驅動設定的其他欄位。
使用 /etc/docker/daemon.json 檔案設定日誌將會分別對每個節點設定預設日誌記錄行為。這些設定可以被每個服務或每個容器級別的設定覆蓋。覆蓋預設日誌記錄行為可能對故障排除很有用,因為可以實時檢視日誌。
如果在配置 daemon.json 檔案使用 gelf 日誌驅動的系統上建立服務,則所有在該主機上執行的容器日誌都將轉至 gelf-address 配置設定的地址。
如果希望使用其他日誌記錄驅動,例如用於檢視來自容器的 stdout 的日誌流,則可以臨時覆蓋預設日誌記錄行為。
docker service create \
--log-driver json-file --log-opt max-size=10m \
nginx:alpine
然後可以配合 Docker 服務日誌,更輕鬆地識別服務的問題。
Docker 服務日誌
docker service logs 是在 Docker EE 的 17.05 版和 17.06 版中推出的。當服務有多個從節點任務時,它可提供多路複用的日誌流。只要輸入 docker service logs,這些日誌就會在第一列顯示發起任務名稱,然後在右側的列中顯示每個從節點的實時日誌。例如:
$ docker service create -d --name ping --replicas=3 alpine:latest ping 8.8.8.8
5x3enwyyr1re3hg1u2nogs40z
$ docker service logs ping
ping.2.n0bg40kksu8e@m00 | 64 bytes from 8.8.8.8: seq=43 ttl=43 time=24.791 ms
ping.3.pofxdol20p51@w01 | 64 bytes from 8.8.8.8: seq=44 ttl=43 time=34.161 ms
ping.1.o07dvxfx2ou2@w00 | 64 bytes from 8.8.8.8: seq=44 ttl=43 time=30.111 ms
ping.2.n0bg40kksu8e@m00 | 64 bytes from 8.8.8.8: seq=44 ttl=43 time=25.276 ms
ping.3.pofxdol20p51@w01 | 64 bytes from 8.8.8.8: seq=45 ttl=43 time=24.239 ms
ping.1.o07dvxfx2ou2@w00 | 64 bytes from 8.8.8.8: seq=45 ttl=43 time=26.403 ms
在嘗試檢視包含多個從節點的服務的日誌輸出時,此命令很有幫助。通過實時檢視跨多個從節點流式傳輸的日誌,可以即時瞭解跨整個叢集的服務問題,並進行故障排除。
ELK 設定
請參閱 swarm-elk 映象倉庫獲取關於在 Docker Swarm 上如何向 ELK 傳送日誌的資訊。此映象倉庫包含一個 Docker Compose 檔案,它會設定完整的 ELK 技術棧。該映象倉庫是試驗使用 ELK 的 Docker 日誌記錄的良好起點,但是在將它用於生產之前,也要考慮高可用性和排隊系統。
Splunk 設定
Splunk 是另一種流行的日誌記錄實用程式。要設定 Splunk,請使用此 swarm-splunk 映象倉庫中提供的 Docker Compose 檔案,按相應步驟操作。
每個 Splunk 轉發程式都連線到本地 Docker 套接字,因此在守護程序級別不需要其他日誌驅動配置。連線本地 Docker 套接字也使 Splunk 在拉取日誌之外還能拉取 Docker 容器統計資訊。
傳統應用現代化
沒有理由認為只有現代化的應用才能使用容器記錄日誌。我們可以在不更改任何應用程式碼的情況下,使傳統應用現代化,同時仍然保留現代化的日誌記錄的優點。
在理想情況下,應用會將日誌傳送到 stdout/stderr,而 Docker 將這些日誌傳送到配置的日誌記錄目標。有時某些應用配置為將日誌傳送到多個位置。如何捕獲這些日誌,而又不更改任何應用原始碼?
可以建立一個 Docker 儲存卷(或多個儲存卷),指向應用中日誌檔案駐留的位置。利用 Docker 模板功能,可以給每個儲存卷加上服務 ID(一個整數)字尾。如果有多個服務任務在同一個主機上執行,給儲存卷名稱加上字尾可以避免任何與日誌記錄相關的衝突。需要建立一個全域性服務,使用目錄萬用字元支援執行日誌記錄代理程式。最後,可以通過日誌記錄實用程式設定附加的正則表示式,將檔案的源目錄轉變為帶索引的值。
下面的示例顯示瞭如何使用官方的 Tomcat 映象實現此目的。官方的 Tomcat 映象在 /usr/local/tomcat/logs 中記錄多個檔案,這與大多數 Java 應用的行為非常相似。在該路徑下,可以找到 catalina.2017-07-06.log、host-manager.2017-07-06.log、localhost.2017-07-06.log、localhost_access_log.2017-07-06.txt 和 manager.2017-07-06.log 等檔案。
為日誌記錄實用程式建立一個掛載 /var/lib/docker/volumes:/logs/volumes 的全域性服務。
為使用與此一般示例類似的規則記錄日誌的日誌記錄代理程式建立日誌記錄規則:“/log/volumes/*/_data/*.log"。
啟動對儲存卷使用基於 go 的模板操作的服務:
啟動該服務時,使用這些引數:
docker service create \
-d \
--name prod-tomcat \
--label version=1.5 \
--label environment=prod \
--mount type=volume,src="{{.Task.Name}}",dst=/usr/local/tomcat/logs \
--replicas 3 \
tomcat:latest
如果兩個從節點在同一個節點上排程,則將在主機 prod-tomcat.1.oro7h0e5yow69p9yumaetor3l 和 prod-tomcat.2.ez0jpuqe2mkl6ppqnuffxqagl 上建立兩個包含日誌的儲存卷。
只要日誌記錄代理程式支援萬用字元,並且通過檢查索引節點(而不是檔案)來處理所有日誌輪替,那麼應該就會收集日誌。
如果應用將日誌記錄到多個位置,則嘗試建立從日誌到單個目錄的符號連結,或向儲存卷新增描述性名稱。如果已將描述性名稱新增到儲存卷名稱,則任何型別的提取都需要經過更新才能容納該更改。(即使用 grok)
大多數日誌記錄器應該會收集檔案路徑以及日誌內容。通過將日誌檔案駐留的儲存卷轉為可加索引的欄位,就可以從這些型別的應用搜索和聚合資訊。下面是一個示例,它使用 grok 模式,並建立了兩個新的可索引欄位 CONTAINER_NAME 和 FILENAME。
match => { "path" => "/log/volumes/%{DATA:CONTAINER_NAME}/_data/%{GREEDYDATA:FILE_NAME}" }
CONTAINER_NAME 將匹配來自容器的 stdout 流輸出,從而方便基於容器的日誌進行過濾。
在 swarm-elk 映象倉庫中可以找到更多關於某映象倉庫的資訊和一個工作示例。
Windows 日誌記錄
ETW 日誌記錄驅動將容器日誌作為 ETW 事件轉發。ETW 代表 Event Tracing in Windows(Windows 中的事件跟蹤),是用於在 Windows 中跟蹤應用的通用框架。每個 ETW 事件都包含一條訊息,其中含有日誌及其上下文資訊。然後客戶端可以建立 ETW 偵聽器來偵聽這些事件,並將它們轉發到可以收集和分析日誌的位置。
要在 Windows 上使用 ETW 驅動,請使用標誌 --log-driver=etwlogs 建立服務或執行容器:
下面是一條示例事件訊息:
container_name: backstabbing_spence,
image_name: windowsservercore,
container_id: f14bb55aa862d7596b03a33251c1be7dbbec8056bbdead1da8ec5ecebbe29731,
image_id: sha256:2f9e19bd998d3565b4f345ac9aaf6e3fc555406239a4fb1b1ba879673713824b,
source: stdout,
log:Hello world!
總 結
Docker 在日誌記錄方面提供了很多選項,在採用平臺時設計日誌記錄策略會很有幫助。對大多數系統來說,將日誌資料留在主機上是不夠的。如果具有索引和搜尋的能力,以及自助服務平臺,就可以讓運維人員和開發人員獲得更順利的體驗。
點選下列標題,閱讀更多幹貨
如果本文對你有幫助,歡迎分享到朋友圈!獲取更多Docker實用技巧,掃描下圖二維碼!