初探雲原生應用管理(二): 爲什麼你必須儘快轉向 Helm v3

在研究了一番“開放雲原生應用中心(AppHub)”之後,程序員小張似乎已經明白了“雲原生應用”到底是怎麼一回事情。

“不就是 Helm 嘛!”

這不,小張這就準備把自己開發多年的“圖書館管理系統”通過 Helm 打包成 Charts,提交到 AppHub 上個線試試。

“這樣,全中國的開發者就都能使用到我開發的圖書館管理系統了!”
想想還有點小激動呢!
然而,還沒等編譯完,小張就發現 Helm 官方文檔上有這麼一句提示非常辣眼睛:

這,到底是咋回事兒?

Helm 項目的緣起

Helm 是目前雲原生技術體系中進行應用管理最被廣泛使用的開源項目,沒有之一。根據 CNCF 剛剛發佈的 KubeCon EU 2019 的總結報告,Kubernetes(k8s),Prometheus 和 Helm 這三個項目,再次蟬聯 KubeCon 上最被關注的開源項目前三名。

Helm 項目本身的發佈,則要追述到 Deis 還是一家獨立創業公司的時代。

2016 年,容器 PaaS (所謂的 CaaS)創業方興未艾,但也開始呈現出同質化競爭和低附加值的種種苗頭,而在這片紅海當中,當時已經委身賣給 Engine Yard 的 Deis 尤其步履維艱。幸運的是,敏銳的技術嗅覺在最困難的時刻拯救了這個的團隊。 2016 年底,Deis 開始全面轉向 K8s 體系,很快就發佈了一系列專門爲 k8s 進行應用管理的開源項目。這其中,定位爲“k8s 應用包管理器”的 Helm,是最受歡迎的一個。

我們知道,K8s 本身是沒有“應用”這個概念的。比如,小張要在 K8s 上部署的“圖書館管理系統”,實際是由四個 YAML 文件組成的:

  1. web-deploy.yaml,用 K8s 的 Deployment 描述的 Java Web 程序;
  2. web-svc.yaml,用 K8s 的 Service 描述的程序訪問的入口;
  3. mysql.yaml,用 K8s StatefulSet 描述的 MySQL 實例;
  4. mysql-svc.yaml,用 K8s Service 描述的 MySQL 實例的訪問入口。

然後,小張需要執行四次 kubectl apply -f 把這些 YAML文件都提交給 K8s 來負責運行和管理這個應用。這裏面的麻煩之處在於,怎麼樣去管理這個應用對應的所有 k8s 資源?

於是 Helm 項目提供了一種簡單的思路:它定義了一種新的應用打包格式叫 Chart。一個 myapp 應用的文件佈局如下所示:

myapp/
  Chart.yaml          
  values.yaml           
  templates/                 

其中,Chart.yaml 裏面用來寫應用元數據,比如:

apiVersion: v1
name:  圖書館管理系統
version:  0.1
description: 全中國最受歡迎的圖書館管理系統
maintainers: 
  - name: 小張

在 templates/ 目錄下,則存放小張編寫好的四個 YAML 文件。

此外,小張還可以將這些 YAML 裏需要修改的字段定義成“模板變量”,在部署時由 Helm去負責注入。比如 web-deploy.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: 圖書館管理系統網站
spec:
  replicas: {{ .Values.replicaCount }}
  template:
    ...
    spec:
      containers:
        ...

通過上面的語法,小張就把這個 Deployment 的 replicas 值定義成了一個變量,將來就可以在部署的時候通過傳參來決定這個圖書館管理系統啓動後具體有幾個實例了,比如,指定 100 個實例:

helm install apphub/圖書館管理系統 --set replicaCount=100

最後,Helm 項目允許你把上面這一系列文件和目錄,做成一個壓縮包上傳到網上,從而被別人通過 helm install 下載安裝到。這個上傳的地址,就是 Helm Hub 了。

這種應用打包的方法,很大程度上解決了 K8s 應用管理能力缺失的問題,所以在推出之後就很快贏得了開發者的青睞。而 Helm Hub 也成爲了繼 Docker Hub 之後雲原生技術體系裏第二個重要的應用分發中心。

Helm 的架構問題

不過,上面這個流程聽起來很簡單,但是 Helm 在項目的一開始設計中,卻使用了一種讓人“匪夷所思”的架構。

可以想象,無論是安裝還是更新應用,Helm 其實都可以在客戶端調用 K8s API 來完成這些功能。但現實情況是,Helm 一定需要在 Kubernetes 集羣裏部署了一個叫做 Tiller 的 Server 端,然後把請求都提交給 Tiller,再由 Tiller 去跟 K8s APIServer 進行交互,完成應用的安裝操作,這個複雜的過程,可以用下圖表示清楚:

圖片來源:Helm 官方文檔

而這個“畫蛇添足”的架構,不但成爲了 Helm 發佈之處的一個假設,也貫穿了 Helm v2 的整個項目生命週期。

爲什麼 Helm 要堅持在 K8s 放置一個 Server 端呢?

這裏其中一個重要的原因,在於 Helm 項目最初並不只希望做一個簡單“應用包管理工具”。

作爲一個地道的 PaaS 服務商,Deis 公司從一開始就知道“應用打包”只是自己完整拼圖的入口,而 Tiller的存在,則是讓 Helm 成爲未來雲原生時代“新 PaaS” 的重要伏筆。

Tiller 這個服務端組件,其實相當於 Helm 在 K8s 內插入的一個應用管理控制器。有了它,Helm 不僅可以很容易在 K8s 側存儲應用相關的狀態,還可以基於 Tiller 在 K8s 內逐步構建出一個微型 PaaS 的功能。並且,這些功能的設立和發展,都不需要依賴於 K8s 本身的應用管理能力。

這也解釋了爲何 Helm v2 爲什麼將很多原本可以在客戶端上實現的功能都放到 Tiller 中,並且很快就提出了 Release 的概念,發佈了helm upgrade、 helm rollback 等應用升級和回滾的能力。這些設計,其實都與 Helm 最終 PaaS 化的思路有着千絲萬縷的聯繫。

Helm v3:“迫不得已”,與“勢在必行”

不過,Helm 的這條演進路線,在 Kubernetes 這個天生以“應用”爲中心的基礎設施體系裏,卻栽了個跟頭。

我們知道,Kubernetes 是圍繞着聲明式 API 來設計的。Kubernetes 的容器編排理念以及 APIServer 實現與擴展機制,其本質目的都是爲了幫助用戶屏蔽掉基礎設施管理的複雜性,允許用戶通過統一而整潔的聲明式 API 來描述自己的意圖和訴求,這正是 Kubernetes 成爲“The Platform of Platform”的重要基礎。

這也是爲何,Kubernetes 從一開始就對容器進行組合,以便藉助 Pod 的概念來模擬進程組的行爲;並且堅持使用聲明式 API 搭配控制器模型來進行應用編排,通過 API 資源對象的創建與更新(PATCH)來驅動整個系統的持續運轉。

這種設計的最終效果,就是用戶只需要將一個“描述”應用的 YAML 文件,放在 etcd 裏存起來,然後通過控制器模型驅動整個基礎設施的狀態不斷地向用戶聲明的狀態逼近,就也就是 Kubernetes 的核心工作原理了。這套理論,正是 Google Borg/Omega 進行應用管理和編排的核心與基礎,同時也是 K8s 同 Mesos 這種資源管理器項目最大的區別。

這時候,我們也就不難發現。Helm 試圖依託 Tiller 推進的應用生命週期管理功能,跟 K8s 的設計發生了衝突。

理論上來講,Helm 只需要將應用描述文件提交給 K8s,剩下的應用啓動、發佈和回滾等操作,就都交給 K8s 即可。比如在 K8s 的 Deployment 語義中,已經爲用戶提供了非常詳細的滾動更新策略,這些都是應用描述(YAML 文件)裏的主要字段:

strategy:
  type: Rolling
  rollingParams:
    updatePeriodSeconds: 1 
    intervalSeconds: 1 
    timeoutSeconds: 120 
    maxSurge: "20%" 
    maxUnavailable: "10%" 

但是現在,Helm 自己也內置了應用的更新和回滾策略,並且它們與 K8s 的策略沒有什麼關係、都通過 Tiller 幫你完成。這種“喧賓奪主”的體驗,讓不少人尤其是資深 K8s 用戶對 Helm 項目望而卻步。

另一方面,Tiller 的存在,導致 Helm v2 從一開始就引入了很多“奇葩”的設計。

比如,在 Helm v2 中,應用名稱(Release Name)必須是個全局唯一的名字,而不是像正常的 K8s API 資源一樣,是被 Namespace 隔離開的。

這是因爲 Helm 通過一個 Release 對象來記錄 Release 的信息,而運行在 K8s 端的 Tiller 要能夠訪問 Release 對象,就必須保證該對象必須和 Tiller 在同一個 Namespace ,這就導致了全集羣的 Release 名字都不能重複。

這個問題,在 Helm v3 中終於得以被修復了。類似的,Helm 的 Revision(應用版本)在 v2 中也是一個全局對象,而現在在 v3 中,一個應用終於可以由自己的 Revision 對象,並且每次升級或者回滾時關聯到對應的 Revision 即可。

不過,現在回頭來看,Helm 項目當初走向這樣的架構,其實也是可以理解的。

在 2016~2017 年,應用管理並不是 K8s 主要透出來的核心能力,很少有人能夠意識到 K8s 異常複雜的聲明式 API 、尤其是 PACTH  API 到底意味着什麼————哪怕“K8s 聲明式應用配置”的大部分理論實際上一直存在於 K8s 文檔庫最不顯眼的一個角落中。所以,在那個時候,大家在 K8s 之上進行應用管理第一個想到的 idea,基本都是在 K8s 裏安裝一個 Controller 來實現。實際上,當時 Google Cloud 團隊自己也提出了一個叫做 Deployment Manager的插件,這個插件後來跟 Tiller 部分合併在了一起。

但開源社區魔力就在於用戶“用腳投票”的神奇力量。

Helm 項目作爲 “K8s 包管理工具”的設定,讓這個項目在雲原生社區風生水起;但與此同時, Tiller 這個奇怪的存在,也成爲了 Helm 項目進一步向前發展的絆腳石。長久以來,Tiller 組件帶來的使用困惑、安全隱患、部署維護的複雜度,幾乎佔據了 Helm 社區的絕大多數板塊。一些廠商甚至乾脆自己發佈了“去 Tiller 版”的 Helm 發行版來表示“抗議“。

而另一方面, K8s 的聲明式應用管理思路也沒有走向外置 Controller 的方式去解決,而是選擇繼續在 K8s 本身去豐富和完善應用管理與發佈能力,這很快也成爲了整個K8s 社區投入的重中之重(這個故事,我們在後續的《雲原生應用管理系列文章》中會爲你進行進一步的介紹)。這也就使得 Helm 本身內置的應用管理體系開始與上游社區漸行漸遠。

當生態和社區都開始與項目的發展背道而馳的時候,“自我革命”就自然成爲了一個勢在必行的選擇。

Helm v3,雲原生應用管理的重要里程碑

除了移除 Tiller、讓 Helm 變成純客戶端工具之外,Helm v3 相對於 v2,還有如下一些重要變化:

  • Release 名字縮小至 Namespace 範圍:
    • Triller 移除後,Release (應用)名稱和 Revision(版本)不再是全局值,用戶可以非常自然的在不同 namespace 裏使用相同的 Release 名字;
  • 合併描述應用依賴的 requirements.yaml 到Chart.yaml:
    • 進一步減小用戶的學習和使用 Helm 進行應用包管理負擔
  • 支持 helm push 到遠端 Helm Hub,支持登陸認證;
  • 支持在容器鏡像 Registry 中存儲 Charts:
    • 消除 Helm Hub 和 Docker Registry 的重合定位
  • 支持 LUA 語法:
    • Helm 現有的模板變量的參數定義方法,實際上有很多問題,我們在後續文章中會詳細介紹;
  • 可以對 values.yaml 裏的內容進行驗證(Validation);

關於 Helm v3 的詳細解讀和實例,你可以繼續閱讀這篇《深度解讀Helm 3: 猶抱琵琶半遮面》來一探究竟。

經歷了這樣的重構之後,Helm v3 已經開始調整自己的發展方向,淡化了做一個“微型 PaaS”的思路,更多的關注於應用打包和包管理這兩個核心功能上,將更多的應用管理的自由度交換給了 K8s 社區。

這個變化,無論是對於 Helm 社區還是雲原生應用開發者來說,都是喜聞樂見的。不難預料,Helm v3 很大概率會成爲未來雲原生應用管理體系中的一個重要工具,而與之相對應的 App Hub,也會成爲雲應用分發與託管過程中的重要環節。

如果更向前延伸一些,未來在 K8s 上部署應用,很可能上只需要提交一個應用定義即可。這個應用定義,很大程度上會是類似 Helm Charts 這樣的、自包含的應用描述文件,用戶在客戶端就可以完成這個應用的設置和配置,然後提交給 K8s。接下來,這個應用的創建、更新和發佈流程,就都可以由 K8s 以及它所集成的應用服務能力(比如  OpenKruise、Tekton、Istio 和 Knative) 來完成。這種工作形態,很可能正是面向未來的、“雲原生應用”的最終走向。

雲原生時代,你還有什麼理由不去嘗試一下 Helm v3 呢?

即刻開始!

雖然還有一些疑惑,小張似乎也摸索出了 Helm v3 背後的一些“大計劃”。

說幹就幹!

由於 Helm v3 現在還在預覽版,沒有正式的下載渠道,小張只能打開 GitHub 從 Release 頁面下載二進制文件。然而 …………

“怎麼會這麼卡!”

由於不可描述的原因,GitHub 託管 Release 的存儲在國內訪問非常困難。不過,善於利用“百度搜索”的小張,還是找到了好心人在國內託管的 Helm v3 鏡像和安裝方法:

https://github.com/cloudnativeapp/workshop/tree/master/kubecon2019china/charts/guestbook#installing-helm-v3

在有了 Helm v3 之後,小張到底能不能順利的把“圖書館管理系統”做成 Charts,上傳到開放雲原生應用中心(AppHub)讓全國的開發者使用到呢?

我們拭目以待!

相關文章
初探雲原生應用管理(一): Helm 與 App Hub

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章