集群規模下日志處理和網絡層的經驗分享

jopen 9年前發布 | 19K 次閱讀 集群

原文  http://www.dockerone.com/article/355

我先假定今晚的聽眾至少小范圍的鋪開 docker 容器化技術在線上了,至少熟悉 docker 的工作原理和 remote api。所以我不會對簡單的 docker 操作和使用做太多的分享,主要是分享集群化容器線上管理這塊中的日志管理和網絡管理。

在早期 docker 實現中,日志這塊一直都很喪失,所有容器內的標準輸出和錯誤都會寫入到 /var/lib/docker/containers/{$cid}/{$cid}-log.json 中。因為沒有日志自動分卷以及和容器綁定,所以一旦上到線上就會出現瞬間磁盤打滿的情況。這個文件同時又是 docker logs api 的 data source,加之 docker 1.6 引入的 log-driver 參數,因此對于線上日志的收集管理我們目前有這么幾個方法。

  1. 監控這個文件,通過管道把數據轉出。這種方案最大的問題是日志文件和容器是綁定的,因此需要有一個 agent 的角色來做這件事,變相的增加了開發成本,還要考慮管道的可靠性問題。另外 CentOS 6系和7系日志地址不一樣,如果硬編碼則擴展性不佳,如果讀取系統配置,那么要考慮跨系統之間的路徑問題。
  2. 通過 docker logs api 來遠程重定向日志,這種方法最大的問題是你避免不了還是得有 agent 去清理日志這么個操作,否則的話依然磁盤會被打滿,當然也可以配合 logrotate 來做這事,不過增加了運維成本。如果是遠端調用這個 API 的話,要考慮連接可靠性,一旦出現重連,那么顯而易見的是要做日志回溯,否則會丟失一部分日志。
  3. 容器內進程自己把日志寫出
    a. 進程直接寫出,控制權交給了業務方,對業務不透明,可控性降低,畢竟是集群環境。這樣一來也要暴露集群結構給上層。
    b. 映射日志設備(/dev/log)進容器,容器內進程直接寫設備,隔離性減弱,單點問題追蹤會很麻煩,因為這時候 stdout 和 stderr 是沒有內容的,也就是 docker log 命令無任何輸出。
    3.a 的話我們試過,不過要讓業務方來改代碼整體推進進度就不太號控制了。另外暴露了遠端日志服務器地址,無論是網絡上還是安全上都是有問題的。舉個栗子一旦介入 SDN 等管理網絡的方式,那么等于就是破壞了整體的隔離性。3.b 就是定位問題 container 比較麻煩,而且還是要涉及到跟業務方溝通。
  4. 使用新版的 log-driver 參數,其中包含支持 syslog,看似很美好,但是在集群環境下要考慮 syslog 單點問題。一般來說會有多個 syslog 或者支持 syslog 協議的遠端 server (logstash)。如果使用遠程 syslog 接受日志,大量 containers 日志輸出并不平均,從而會產生性能熱點和流量熱點。如果走單機 syslog 再匯總,就跟3.b 沒多大區別了,跟蹤問題比較麻煩。我覺得目前這個實現更多的是方便了之前使用 syslog 方案的。
  5. attach 方法截獲容器輸出流重定向,需要 agent 支持,有一定開發要求。目前我們采用這種方案,通過一個模塊實現了 consistent hash 把日志流量打到遠端收集服務器上。這個方案只需要讓業務把日志輸出到 stdout/stderr 中即可,并不會增加開發成本。同時 1.6 docker 可以指定日志驅動為 none,避免了 logs 文件的產生。另外一方面可以把 container 自己的 meta info 給附加到日志流里面,從而實現遠端的日志檢索分類聚合等操作。這個方案最大的問題是開發力量的投入,不同個 dockeclient 實現質量也不一樣,當然好處也是很明顯的,靈活可控,日志流向和分配都在自己受傷。

所以日志方面,從目前 docker 實現來看,如果開發力量跟得上,agent + attach 方案是靈活性和可控性是最高的。目前 log-driver 對于上規模的集群來說還是不太好用,理想狀態下我希望是可以指定多個 log-drivers,通過 hash 方案打到遠端。當然具體方案的選取就得看各自公司本身的基礎設施和設計目標了。

說完日志來說下網絡,目前 docker 的網絡方案主要有這么幾個,當然現在大家都在等 1.7,不過我認為對于生產系統而言,已有 SDN 方案的不會太過于在乎 libnetwork,可能會研究下其和 docker 是怎樣通過 plugin 方式結合的。因為其他方案目前都是 Hook 方式去做的。

  1. 默認 NAT/BR/HOST,NAT 有性能損失,BR 有網絡閃斷,HOST 流控不好做,端口沖突靠業務保證沒法做到透明。
  2. 網絡層方案
    a. 隧道方案
    I. OVS,主要是有性能方面的損失,基于 VxLAN 和 GRE 協議,類似的方案還有 Kubernetes/Socketplane 的實現
    II. Weave,UDP 廣播,本機建立新的 BR,通過 PCAP 互通
    III. Flannel,UDP 廣播,VxLan
    隧道方案非常靈活,但是因為太過于靈活,出了網絡問題(A-B 鏈路抖動)跟蹤起來比較麻煩,大規模集群情況下這是需要考慮的一個點,畢竟即便是內網也不一定風平浪靜。
    b. 路由方案
    I. Pipework,對于 Docker BR 本身的擴展,當然也支持 OVS macvlan 等方案的結合。現在 libnetwork 出來變相的是廢了這個項目了,長遠來看后繼無人,因此它不是一個很好的選擇。
    II. Calico,基于 BGP 協議的路由方案,支持很細致的 ACL 控制,對于隔離要求比較嚴格的場景比較適合,對混合云親和度比較高,因為它不涉及到二層的支持。
    III. Macvlan,從邏輯和 Kernel 層來看隔離性和性能最優的方案,基于二層隔離,所以需要二層路由器支持,大多數云服務商不支持,所以混合云上比較難以實現。
    路由方案沒那么靈活,大多數情況下需要有一個 agent 在 container host 上去操作,一般是從 3 層或者 2 層實現隔離和跨機 container 互通的,出了問題也很容易排查。但是路由方案對本身物理網絡依賴會比隧道方案要重。另外 hook 的話畢竟還是不太優美,所以得看看 libnetwork 是怎樣和 docker 結合的。
    目前我們選取的是 macvlan 的方案實現的二層隔離,說輕量主要是對 container 而言,可以完全當 container 為一臺虛擬機。說重量,是因為其對物理網絡基礎設施依賴程度最高。

Q&A

Q. macvlan 是怎么做的

A. linux 內核支持,直接用 agent 在 host 上生成設備塞入到 container 的 namespace 中。

Q. 為何不直接打日志

A. 容器內的話得考慮 docker 本身存儲性能問題,如果是容器外得考慮卷管理問問題,如果是遠端,得考慮和業務結合的問題

Q. 網絡層比較成熟的選擇

A. macvlan 進了內核,Calico 做了十來年了,這2者都會比較成熟,weave 比較簡單和方便

Q. 日志丟失問題

A. 盡可能的不讓業務層去控制日志輸出,即便是 socket 文件或者設備都有可能被刪除從而導致日志丟失,因此盡量從平臺層面控制

Q. 二進制服務跑在 docker 里面的問題

A. 目前我們也在做類似的事情,把 redis 跑入。但是因為 container 本身沒有 init 進程,因此內核參數都是默認的,有些 binary 應用在這方面會比較敏感。我們目前也沒找到比較優美的方法解決。docker 官方 github 有不少類似的 issue

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!