適用於 k8s 的生產就緒映像

這個故事是關於我們如何在生產環境中使用容器,特別是 Kubernetes。 本文致力於從容器中收集指標和日誌,以及建立鏡像。

適用於 k8s 的生產就緒映像

我們來自金融科技公司 Exness,該公司為 B2B 和 B2C 開發線上交易服務和金融科技產品。 我們的研發有許多不同的團隊,開發部門有 100 多名員工。

我們代表負責為我們的開發人員收集和運行程式碼的平台的團隊。 特別是,我們負責收集、儲存和報告來自應用程式的指標、日誌和事件。 目前,我們在生產環境中運行大約三千個 Docker 容器,維護 50 TB 大數據存儲,並提供圍繞我們的基礎設施構建的架構解決方案:Kubernetes、Rancher 和各種公共雲提供商。 

我們的動力

什麼在燃燒? 沒有人能回答。 壁爐在哪裡? 這很難理解。 什麼時候起火的? 你可以發現,但不是馬上就能發現。 

適用於 k8s 的生產就緒映像

為什麼有些貨櫃能站著,而有些卻倒塌了? 哪個容器是罪魁禍首? 畢竟,容器的外部是一樣的,但裡面卻各有各的 Neo。

適用於 k8s 的生產就緒映像

我們的開發人員都是有能力的人。 他們提供良好的服務,為公司帶來利潤。 但是,當帶有應用程式的容器誤入歧途時,就會出現故障。 一個容器消耗過多的 CPU,另一個容器消耗網絡,第三個容器消耗 I/O 操作,第四個容器完全不清楚它對套接字做了什麼。 一切都倒塌了,船也沉了。 

代理商

為了了解內部發生的情況,我們決定將代理直接放置在容器中。

適用於 k8s 的生產就緒映像

這些代理是限製程序,使容器保持在不會互相破壞的狀態。 代理是標準化的,這允許使用標準化的方法來服務容器。 

在我們的例子中,代理必須提供標準格式的日誌,並進行標記和限制。 它們還應該為我們提供可從業務應用程式角度擴展的標準化指標。

代理也指用於操作和維護的實用程序,可以在支援不同鏡像的不同編排系統(Debian、Alpine、Centos 等)中工作。

最後,代理必須支援包含 Docker 檔案的簡單 CI/CD。 否則,船就會散架,因為貨櫃將開始沿著「彎曲」的鐵軌運輸。

建置流程和目標影像設備

為了保持一切標準化和可管理性,需要遵循某種標準建置流程。 因此,我們決定按容器收集容器——這就是遞歸。

適用於 k8s 的生產就緒映像

這裡的容器由實心輪廓表示。 同時,他們決定在其中放入分發包,讓「生活不再像覆盆子」。 為什麼這樣做,我們將在下面解釋。
 
結果是一個建置工具-一個引用特定發行版本和特定腳本版本的特定版本的容器。

我們如何使用它? 我們有一個包含容器的 Docker Hub。 我們將其鏡像到系統內部以擺脫外部依賴。 結果是一個標記為黃色的容器。 我們建立一個範本來將我們需要的所有發行版和腳本安裝到容器中。 之後,我們組裝一個隨時可用的鏡像:開發人員將程式碼和一些自己的特殊依賴項放入其中。 

這種方法有什麼好處呢? 

  • 首先,建置工具的完整版本控制——建置容器、腳本和分發版本。 
  • 其次,我們實現了標準化:我們以相同的方式創建模板、中間圖像和即用圖像。 
  • 第三,容器為我們帶來了可移植性。 今天我們使用 Gitlab,明天我們將切換到 TeamCity 或 Jenkins,我們將能夠以相同的方式運行容器。 
  • 第四,最小化依賴性。 我們將分發包放入容器中並非巧合,因為這樣我們就可以避免每次都從網路上下載它們。 
  • 第五,建立速度提高了 - 映像本地副本的存在使您可以避免在下載上浪費時間,因為有本地映像。 

換句話說,我們已經實現了受控且靈活的組裝流程。 我們使用相同的工具來建立任何完全版本化的容器。 

我們的建構過程如何運作

適用於 k8s 的生產就緒映像

該組件透過一個命令啟動,該進程在圖像中執行(以紅色突出顯示)。 開發人員有一個 Docker 檔案(以黃色突出顯示),我們渲染它,並用值取代變數。 一路上我們添加頁眉和頁腳 - 這些是我們的代理。 

標題添加了相應圖像的分佈。 頁腳在裡面安裝我們的服務,配置工作負載的啟動,日誌記錄和其他代理,替換入口點等。 

適用於 k8s 的生產就緒映像

我們想了很久要不要裝一個supervisor。 最後,我們決定需要他。 我們選擇了S6。 Supervisor 提供容器管理:讓您在主進程崩潰時連接到它,並提供容器的手動管理而無需重新建立它。 日誌和指標是在容器內運行的進程。 它們還需要以某種方式受到控制,我們在主管的幫助下做到這一點。 最後,S6 負責內務處理、訊號處理和其他任務。

由於我們使用不同的編排系統,容器在建置和運作之後,必須了解自己處於什麼環境,並根據情況採取行動。 例如:
這使我們能夠建立映像並在不同的編排系統中運行它,並將在考慮到該編排系統的具體情況的情況下啟動它。

 適用於 k8s 的生產就緒映像

對於同一個容器,我們在 Docker 和 Kubernetes 中得到不同的進程樹:

適用於 k8s 的生產就緒映像

有效負載在S6的監督下執行。 注意收集器和事件 - 這些是我們負責日誌和指標的代理。 Kubernetes 沒有它們,但 Docker 有。 為什麼? 

如果我們查看「pod」(以下稱為 Kubernetes pod)的規範,我們會發現事件容器是在 pod 中執行的,pod 具有單獨的收集器容器,用於執行收集指標和日誌的功能。 我們可以使用 Kubernetes 的功能:在單一進程和/或網路空間中的一個 Pod 中運行容器。 實際上介紹您的代理並執行一些功能。 如果在 Docker 中啟動相同的容器,它將接收所有相同的功能作為輸出,即它將能夠傳遞日誌和指標,因為代理將在內部啟動。 

指標和日誌

交付指標和日誌是一項複雜的任務。 她的決定有幾個面向。
基礎架構是為了執行有效負載而創建的,而不是為了大量交付日誌。 也就是說,必須以最少的容器資源需求來執行此程序。 我們努力幫助我們的開發人員:“獲取 Docker Hub 容器,運行它,然後我們就可以交付日誌。” 

第二個方面是限制日誌量。 如果多個容器中的日誌量激增(應用程式循環輸出堆疊追蹤),CPU、通訊通道和日誌處理系統的負載就會增加,這會影響主機的運行主機上的整個容器和其他容器,有時這會導致主機“崩潰”。 

第三個面向是需要支援盡可能多的開箱即用的指標收集方法。 從讀取檔案和輪詢 Prometheus 端點到使用特定於應用程式的協定。

最後一個面向是最大限度地減少資源消耗。

我們選擇了一個名為 Telegraf 的開源 Go 解決方案。 這是一個通用連接器,支援超過 140 種輸入通道(輸入插件)和 30 種輸出通道(輸出插件)。 我們已經完成了它,現在我們以 Kubernetes 為例告訴你我們如何使用它。 

適用於 k8s 的生產就緒映像

假設開發人員部署了一個工作負載,而 Kubernetes 收到了建立 pod 的請求。 此時,會自動為每個 pod 建立一個名為 Collector 的容器(我們使用mutation webhook)。 收藏家是我們的代理人。 一開始,容器將自身配置為與 Prometheus 和日誌收集系統配合使用。

  • 為此,它使用 Pod 註釋,並根據其內容創建 Prometheus 端點; 
  • 根據Pod規格和特定容器設置,決定如何投遞日誌。

我們透過 Docker API 收集日誌:開發人員只需將它們放入 stdout 或 stderr 中,Collector 就會對其進行整理。 日誌以區塊的形式收集,並有一定的延遲,以防止可能的主機過載。 

指標是跨容器中的工作負載實例(進程)收集的。 所有內容都被標記為:命名空間、下等,然後轉換為 Prometheus 格式 - 並可供收集(日誌除外)。 我們還將日誌、指標和事件發送到 Kafka 以及其他:

  • 日誌可在 Graylog 中取得(用於視覺化分析);
  • 日誌、指標、事件被送到 Clickhouse 進行長期儲存。

AWS 中的一切運作方式完全相同,只是我們使用 Cloudwatch 將 Graylog 替換為 Kafka。 我們將日誌發送到那裡,一切都變得非常方便:立即清楚它們屬於哪個叢集和容器。 Google Stackdriver 也是如此。 也就是說,我們的方案既可以在本地使用 Kafka,也可以在雲端運作。 

如果我們沒有帶有 Pod 的 Kubernetes,該方案會稍微複雜一些,但其工作原理相同。

適用於 k8s 的生產就緒映像

相同的進程在容器內執行,它們是使用 S6 編排的。 所有相同的進程都在同一個容器內運作。

其結果是,

我們創建了一個用於建立和啟動影像的完整解決方案,並提供了收集和交付日誌和指標的選項:

  • 我們開發了一種標準化的影像組裝方法,並在此基礎上開發了 CI 模板;
  • 資料收集代理程式是我們的 Telegraf 擴充功能。 我們在生產中對它們進行了很好的測試;
  • 我們使用mutation webhook來實現在pod中帶有代理的容器; 
  • 融入Kubernetes/Rancher生態系;
  • 我們可以在不同的編排系統中執行相同的容器並得到我們期望的結果;
  • 建立了完全動態的容器管理配置。 

共同作者: 伊利亞·普魯德尼科夫

來源: www.habr.com

添加評論