Helm 設備及其陷阱

Helm 設備及其陷阱
Typhon 貨運概念車,安東·斯瓦內普爾 (Anton Swanepoel)

我叫 Dmitry Sugrobov,是 Leroy Merlin 的開發人員。 在本文中,我將告訴您為什麼需要 Helm、它如何簡化 Kubernetes 的使用、第三個版本中的更改以及如何使用它在生產中更新應用程式而無需停機。

這是根據會議演講總結的 @Kubernetes 會議 by Mail.ru 雲解決方案 - 如果您不想閱讀,請觀看影片。

為什麼我們在生產中使用 Kubernetes

樂華梅蘭 (Leroy Merlin) 是俄羅斯和歐洲 DIY 零售市場的領導者。 我們公司擁有一百多名開發人員、33 名內部員工以及大量的大賣場和網站訪問人數。 為了讓他們都滿意,我們決定遵循業界標準方法。 使用微服務架構開發新的應用程式; 使用容器隔離環境並確保正確交付; 並使用 Kubernetes 進行編排。 使用編排器的價格正在迅速變得更便宜:市場上精通該技術的工程師數量正在增長,供應商正在提供 Kubernetes 作為服務。

當然,Kubernetes 所做的一切都可以透過其他方式來完成,例如,透過使用腳本覆蓋一些 Jenkins 和 docker-compose,但如果有現成的可靠解決方案,為什麼還要讓生活變得複雜呢? 這就是我們選擇 Kubernetes 並在生產中使用它一年的原因。 我們目前有 XNUMX 個 Kubernetes 集群,其中最舊的已經有一年多了,大約有 XNUMX 個 pod。

Kubernetes 中大型 YAML 檔案的詛咒

要在 Kubernetes 中啟動微服務,我們將建立至少 XNUMX 個 YAML 檔案:用於 Deployment、Service、Ingress、ConfigMap、Secrets,並將它們傳送到叢集。 對於下一個應用程序,我們將編寫相同的門框包,對於第三個應用程序,我們將編寫另一個,依此類推。 如果我們將文件數量乘以環境數量,我們將已經獲得數百個文件,而這尚未考慮動態環境。

Helm 設備及其陷阱
Helm 核心維護者 Adam Reese 介紹了“Kubernetes 中的開發週期”,看起來像這樣:

  1. 複製 YAML - 複製 YAML 檔案。
  2. 貼上 YAML - 貼上它。
  3. 修復縮排 - 修復縮排。
  4. 重複——再重複一遍。

該選項有效,但您必須多次複製 YAML 檔案。 為了改變這個循環,Helm 被發明了。

什麼是頭盔

首先,頭盔—— 套件管理器,它可以幫助您找到並安裝您需要的程式。 例如,要安裝MongoDB,您不需要去官方網站下載二進位文件,只需執行命令 helm install stable/mongodb.

其次,頭盔—— 模板引擎,有助於參數化文件。 讓我們回到 Kubernetes 中 YAML 檔案的情況。 編寫相同的 YAML 檔案更容易,在其中添加一些佔位符,Helm 將在其中替換值。 也就是說,不再是一大堆腳手架,而是一組模板,所需的值將在適當的時候被替換到其中。

第三,頭盔—— 部署大師。 使用它您可以安裝、回滾和更新應用程式。 讓我們弄清楚如何做到這一點。

Helm 設備及其陷阱

如何使用 Helm 部署自己的應用程式

我們來在電腦上安裝Helm客戶端,依照官方的說明 路線。 接下來,我們將建立一組 YAML 檔案。 我們將保留佔位符,而不是指定具體值,Helm 將在將來填入這些佔位符。 一組此類文件稱為 Helm 圖表。 可以透過三種方式傳送到Helm控制台用戶端:

  • 指示帶有模板的資料夾;
  • 將存檔打包成 .tar 並指向它;
  • 將範本放入遠端儲存庫中,並在 Helm 用戶端中新增指向儲存庫的連結。

您還需要一個包含值的檔案-values.yaml。 那裡的數據將被插入到模板中。 我們也來創建它吧。

Helm 設備及其陷阱
Helm 的第二個版本有一個額外的伺服器應用程式 - Tiller。 它掛在 Kubernetes 外部,等待 Helm 用戶端的請求,當被呼叫時,將所需的值代入模板中並傳送給 Kubernetes。

Helm 設備及其陷阱
Helm 3 更簡單:訊息現在完全在 Helm 用戶端處理並直接傳送到 Kubernetes API,而不是在伺服器上處理範本。 這種簡化提高了叢集安全性並促進了部署方案。

它是怎麼運作的

運行命令 helm install。 讓我們指定應用程式版本的名稱並給出values.yaml 的路徑。 最後,我們將指出圖表所在的儲存庫以及圖表的名稱。 在例子中,它們分別是“lmru”和“bestchart”。

helm install --name bestapp --values values.yaml lmru/bestchart

此指令只能執行一次,再次執行時會改為 install 需要使用 upgrade。 為簡單起見,您可以執行以下命令,而不是兩個命令 upgrade 附加鑰匙 --install。 第一次執行時,Helm 會發送安裝該版本的命令,並在以後進行更新。

helm upgrade --install bestapp --values values.yaml lmru/bestchart

使用 Helm 部署新版本應用程式的陷阱

在故事的這一點上,我正在與觀眾一起玩《誰想成為百萬富翁》,我們正在研究如何讓 Helm 更新應用程式的版本。 觀看視頻.

當我學習 Helm 的工作原理時,在嘗試更新正在運行的應用程式的版本時,我對奇怪的行為感到驚訝。 我更新了應用程式程式碼,將新映像上傳到 Docker 註冊表,發送了部署命令 - 但什麼也沒發生。 以下是一些不完全成功的應用程式更新方法。 透過更詳細地研究它們中的每一個,您開始了解儀器的內部結構以及這種不明顯行為的原因。

方法 1. 自上次啟動以來不要更改訊息

正如它所說 官方網站 Helm,“Kubernetes 圖表可能很大而且很複雜,所以 Helm 盡量不要接觸太多東西。” 因此,如果您在 docker 註冊表中更新最新版本的應用程式映像並執行命令 helm upgrade,那麼什麼事也不會發生。 Helm 會認為沒有任何變化,無需向 Kubernetes 發送命令來更新應用程式。

在這裡和下面,最新標籤僅作為範例顯示。 當您指定此標籤時,無論 imagePullPolicy 參數為何,Kubernetes 每次都會從 docker 註冊表下載映像。 在生產中使用最新版本是不可取的,並且會產生副作用。

方法2.更新影像中的LABEL

正如同中所寫 文件,“Helm 只會更新自上次版本以來發生更改的應用程式。” 一個合理的選擇似乎是更新 docker 映像本身中的標籤。 但是,Helm 不會查看應用程式映像,也不知道對它們進行的任何更改。 因此,當更新鏡像中的標籤時,Helm 不會知道它們,並且應用程式更新命令不會發送到 Kubernetes。

方法 3:使用密鑰 --force

Helm 設備及其陷阱
讓我們查閱手冊並尋找所需的密鑰。 關鍵是最有意義的 --force。 儘管名稱很明顯,但其行為與預期不同。 其真正目的不是強制更新應用程序,而是恢復處於 FAILED 狀態的版本。 如果不使用該鍵,則需要依序執行命令 helm delete && helm install --replace。 建議使用key代替 --force,它會自動順序執行這些命令。 更多資訊在此 拉取請求。 為了告訴Helm更新應用程式版本,不幸的是,這個鍵不起作用。

方法4.直接在Kubernetes中更改標籤

Helm 設備及其陷阱
使用命令直接在叢集中更新標籤 kubectl edit - 餿主意。 此操作將導致正在運行的應用程式與最初發送用於部署的應用程式之間的資訊不一致。 在這種情況下,Helm 在部署期間的行為與其版本不同:Helm 2 不會執行任何操作,Helm 3 將部署應用程式的新版本。 要了解原因,您需要了解 Helm 的工作原理。

頭盔如何運作?

要確定應用程式自上次發布以來是否發生了更改,Helm 可以使用:

  • 在 Kubernetes 中運行應用程式;
  • 新的values.yaml和當前圖表;
  • Helm 的內部發布資訊。

更好奇的是:Helm 在哪裡儲存有關版本的內部資訊?透過執行命令 helm history,我們將獲取有關使用 Helm 安裝的版本的所有資訊。

Helm 設備及其陷阱
還有有關發送的模板和值的詳細資訊。 我們可以要求它:

Helm 設備及其陷阱
在 Helm 的第二個版本中,此資訊位於 Tiller 運行的相同命名空間中(預設為 kube-system),在 ConfigMap 中,標有標籤「OWNER=TILLER」:

Helm 設備及其陷阱
當 Helm 的第三個版本出現時,訊息轉移到秘密,並轉移到應用程式運行的相同名稱空間。 因此,可以在具有相同版本名稱的不同命名空間中同時執行多個應用程式。 在第二個版本中,當名稱空間相互隔離但又可以相互影響時,這是一個非常令人頭痛的問題。

Helm 設備及其陷阱

第二個 Helm 在嘗試了解是否需要更新時,僅使用兩個資訊來源:現在提供給它的資訊以及有關版本的內部資訊(位於 ConfigMap 中)。

Helm 設備及其陷阱
第三個 Helm 使用三向合併策略:除了這些資訊之外,它還考慮了 Kubernetes 中目前運行的應用程式。

Helm 設備及其陷阱
因此,舊版的 Helm 將不會執行任何操作,因為它不考慮叢集中的應用程式訊息,但 Helm 3 將接收變更並發送新應用程式進行部署。

方法 5. 使用 --recreate-pods 開關

有鑰匙 --recreate-pods 你可以用鑰匙實現你原本計畫要達成的目標 --force。 容器將重新啟動,並且根據 imagePullPolicy:始終針對最新標籤的策略(更多內容請參見上面的腳註),Kubernetes 將下載並啟動新版本的映像。 這不會以最佳方式完成:在不考慮部署的策略類型的情況下,它將突然關閉所有舊的應用程式實例並開始啟動新的應用程式實例。 重啟期間,系統將無法運作,用戶將受到影響。

在 Kubernetes 本身,類似的問題也長期存在。 而現在,開業四年後 問題,該問題已修復,並且從 Kubernetes 1.15 版本開始,出現了滾動重啟 pod 的功能。

Helm 只需關閉所有應用程式並在附近啟動新容器即可。 您無法在生產中執行此操作,以免導致應用程式停機。 這僅是開發需要,並且只能在階段環境中執行。

如何使用Helm更新應用程式版本?

我們將更改發送到 Helm 的值。 通常,這些是代替圖像標籤的值。 對於經常用於非生產環境的latest來說,可更改的資訊是一個註釋,這對於Kubernetes本身來說是無用的,而對於Helm來說,它將充當需要更新應用程式的訊號。 填寫註釋值的選項:

  1. 隨機值 使用標準函數 - {{ randAlphaNum 6 }}.
    有一個警告:每次部署使用具有此類變數的圖表後,註釋值將是唯一的,Helm 將假定存在變更。 事實證明,我們總是會重新啟動應用程序,即使我們沒有更改其版本。 這並不重要,因為不會出現停機,但仍然令人不快。
  2. 貼上當前 日期和時間 - {{ .Release.Date }}.
    變體類似於具有永久唯一變數的隨機值。
  3. 更正確的方法是使用 校驗和。 這是在映像的 SHA 或 git 中最後一次提交的 SHA - {{ .Values.sha }}.
    需要對它們進行計數並將其傳送到呼叫方的 Helm 用戶端,例如在 Jenkins 中。 如果應用程式已更改,則校驗和將會更改。 因此,Helm 只會在需要時更新應用程式。

讓我們總結一下我們的嘗試

  • Helm 以侵入性最小的方式進行更改,因此 Docker 註冊表中應用程式映像層級的任何更改都不會導致更新:執行命令後不會發生任何情況。
  • 關鍵 --force 用於恢復有問題的版本,與強制更新無關。
  • 關鍵 --recreate-pods 將強制更新應用程序,但會以破壞的方式進行:它會突然關閉所有容器。 使用者會因此而受苦;你不應該在生產中這樣做。
  • 直接使用指令對 Kubernetes 叢集進行更改 kubectl edit 不要這樣做:我們會破壞一致性,而行為會根據 Helm 的版本而有所不同。
  • 隨著 Helm 新版本的發布,出現了許多細微差別。 Helm 儲存庫中的問題以清晰的語言描述,它們將幫助您理解詳細資訊。
  • 在圖表中添加可編輯註釋將使圖表更加靈活。 這將使您能夠正確推出應用程序,而無需停機。

「世界和平」思想適用於生活的各個領域:使用前而不是使用後閱讀說明。 只有擁有完整的訊息,才有可能建立可靠的系統並讓使用者滿意。

其他相關連結:

  1. 相識 3
  2. 頭盔官方網站
  3. GitHub 上的 Helm 儲存庫
  4. 25 個有用的 Kubernetes 工具:部署和管理

該報告首次發佈於 @Kubernetes 會議 由 Mail.ru 雲端解決方案提供。 看 視頻 其他表演並在 Telegram 上訂閱活動公告 Mail.ru Group 圍繞 Kubernetes 展開.

來源: www.habr.com

添加評論