歡迎光臨
每天分享高質量文章

S6 在 LAIN 集群中的應用實踐

近幾年,容器技術迅猛發展,併在各大企業得到了廣泛應用。它標準化了應用程式的運行環 境,從而簡化了程式的部署流程,同時也促進了 PaaS(Platform as a Service)系統的發展,LAIN 即為其中之一。作為一種革命性的新技術,Docker 具有種種優點,比如一處編譯、處處運行,易於編排和輕量等等;但是,由於發展時間較短, 在生產環境中使用時,Docker 在一些環節出現了性能問題,另外,Docker 容器與虛擬機之 間也有一些微妙的區別,在生產環境中使用時需要給予特別的註意。下麵分享一下 LAIN 生 產集群在運行過程中遇到的一些問題和解決方案。

不斷累積的僵屍行程

為了方便管理,我們把 Jenkins 搬進了容器。但是,Jenkins 容器經常停止響應, 需要定期重啟。為什麼在虛擬機上可以正常運行的程式到了容器里就出現問題了呢? 通過 ps aux 可以發現,Jenkins 容器里有大量的僵屍行程,即圖 1 中的 [git-remote-http] 行程。

圖 1:zombie processes

行程表是有限的系統資源,當僵屍行程占用了大量的行程表空間時,就會導致無法啟動新的 行程。那為什麼容器里會產生大量的僵屍行程呢?因為在類 UNIX 系統中,PID 為 1 的 行程是特殊的:它負責收割僵屍行程。在虛擬機中,PID 為 1 的行程通常是 Systemd、 Sys Vinit 或者 upstart,它們都能自動收割僵屍行程;在容器里,情況有很大的不同: PID 為 1的行程常常是用戶自己寫的程式,很可能不會收割僵屍行程,比如上面的 jenkins-master,這時候就會造成僵屍行程的累積,最終導致容器內無法再啟動新的行程。

偶爾卡死的 Docker Daemon

Docker Daemon 可以收集容器的標準輸出,然後使用 syslog 或 json-file 等 log-driver 處理。但是,這個架構是中心化的,Docker Daemon 會成為日誌收集的瓶頸。 表 1 是我們測得的 Docker 收集日誌的速度。

log-driver 日誌收集速度
syslog 14.9 MB/s
json-file 37.9 MB/s
表 1:Docker 的日誌收集速度

可以看到,這個速度並不理想,當容器的標準輸出較多時,Docker Daemon 不能及時處理, 就會影響這個容器的正常運行;同時,Docker Daemon 對標準輸出的處理會阻塞其他操作, 比如 docker ps 和 docker stop 等命令也會卡死。這時,我們只能重啟 Docker Daemon,同時禁止容器的標準輸出。

一站式解決方案 —— S6

上述 2 個問題嚴重地影響了應用的正常運行,是否有辦法可以解決呢?即,我們希望找到 一個工具,既可以收割僵屍行程,又可以把標準輸出重定向到檔案並自動 rotate。 表 2 是我們找到的一些工具。

行程管理工具 僵屍行程 重定向標準輸出並自動 rotate
S6 收割 支持
tini 收割 支持
systemd 收割 支持,但為二進制
phusion-baseimages 收割 不支持
daemontools 不收割 支持
supervisor 不收割 支持

表 2:行程管理工具的比較

從上表可以看出,S6 是最滿足我們需求的解決方案。而且,它體積很小,只有 904 KB,啟 動時間不超過 100 ms,運行時占用的 CPU 和記憶體可以忽略不計。

S6[1] 包含 s6-svscan、s6-supervise 和 s6-log 等組件。這些組件遵循 UNIX 設計哲學,相互獨立,功能正交,通過適當組合可 以實現強大的功能。那具體怎樣組合呢?S6 的作者把類 UNIX 系統的運行時可以分為 3 個 階段(Bercot,n.d.),如圖 2 所示。 而 s6-overlay[2] 實現了此方案,下麵參考 s6-overlay 說明如何在容器中使用 S6 管理行程。

圖 2:類 UNIX 系統的運行時階段8

階段 1

在階段 1,s6-overlay 準備環境變數和創建 s6 的工作目錄 /var/run/s6/services 等, 然後啟動 PID 為 1 的 s6-svscan 以管理 /var/run/s6/services下的服務:


s6-svscan -t0 /var/run/s6/services

為了適應 LAIN 的需求,我們還將 Dockerfile 里的 CMD 寫入了 /etc/services.d/app/run。整個流程如圖 3 所示。

圖 3:階段 1

階段 2

在階段 2,s6-overlay 首先把 /etc/services.d 里的檔案複製到 s6-svscan 的運行時 目錄 /var/run/s6/services,然後通過 s6-svscanctl -a /var/run/s6/services 觸 發 s6-svcan 對此目錄的檢索;s6-svcan 發現 /var/run/s6/services/app/run 和 /var/run/s6/services/app/log/run 後,會呼叫 s6-supervise 分別啟動這個兩個服 務,如圖 4 所示。

圖 4:階段 2

首先,容器運行過程中,s6-svcan 會收割僵屍行程,解決了我們的第一個問題。

其次,s6-log 將 CMD 的標準輸出重定向到 /lain/logs/default/current,而不是發送到 Docker Daemon,這樣就避免了 Docker Daemon 收集日誌的性能瓶頸, 表 3 是我們的測試結果。可以看到,在 日誌檔案 test.log 體積較小的時候,s6-log 收集日誌的速度可以達到 200 MB/s 左 右,幾乎與直接寫入檔案的速度相當;當 test.log 的體積逐漸增大時,因為會觸發越來 越頻繁的日誌輪轉,所以 s6-log 的速度逐漸降低,逐漸趨近於 90 MB/s 左右。 s6-log 只有在日誌檔案達到 256 MB 時才會觸發輪轉,而這種情況在實際的生成環境中 並不會頻繁發生,因此 s6-log 的實際日誌收集速度應該在 100 MB/s 以上,足以滿足我 們的需求,解決了我們的第二個問題。

test.log 體積 直接用檔案收集日誌的速度 日誌收集速度
80 MB 94.5 MB/s 209 MB/s
160 MB 91.4 MB/s 212 MB/s
320 MB 90.5 MB/s 103 MB/s
640 MB 234 MB/s 99.6 MB/s
1280 MB 225 MB/s 95.7 MB/s
2560 MB 212 MB/s 91.8 MB/s

表 3:s6-log 的日誌收集速度

階段 3

s6-supervise 還會監聽 SIGTERM 信號,當 s6-supervise 收到此信號後進入階段 3: 執行 /var/run/s6/services/app/finish,也就是 s6-svscanctl -t /var/run/s6/services,從而讓整個容器優雅地退出,這比 Docker 預設的等待 10 秒後 強制殺死行程的行為友好很多。

綜上,在 Docker 中使用 S6 可以獲得以下好處:

  • 自動收割僵屍行程

  • 在保留自動 rotate 功能的同時提高日誌收集的速度

  • 適當處理 SIGTERM 信號,優化 docker stop 的用戶體驗

參考文獻:

  1. Bercot, Laurent. n.d. “How to Run S6-Svscan as Process 1.” http://skarnet.org/software/s6/s6-svscan-1.html.

相關鏈接:

  1. http://www.skarnet.org/software/s6/

  2. https://github.com/just-containers/s6-overlay

基於Kubernetes的容器雲平臺實踐培訓

本次培訓包含:Kubernetes核心概念;Kubernetes集群的安裝配置、運維管理、架構規劃;Kubernetes組件、監控、網絡;針對於Kubernetes API接口的二次開發;DevOps基本理念;Docker的企業級應用與運維等,點擊識別下方二維碼加微信好友瞭解具體培訓內容

點擊閱讀原文鏈接即可報名。
赞(0)

分享創造快樂