一、為啥要用helm
對於一些微服務架構來說,會有不同的服務在上面運行,你可能要管理諸如deployment、service、有狀態的Statefulset、權限的控制等等。你會發現,部署應用后還會有很多其他關聯的東西以及你需要考慮的點:比如說你的不同團隊,要去管理這樣一個應用,從開發到測試再到生產,在不同的環境中,同樣一套東西可能都需要不同的配置。例如,你在開發的時候,不需要用到PV,而是用一些暫時的存儲就行了;但是在生產環境中,你必須要持久存儲;並且你可能會在團隊之間做共享,然后去存檔。
另外,你不僅僅要部署這個應用資源,你還要去管理其生命周期,包括升級、更新換代、后續的刪除等。我們知道,K8S里面的deployment是有版本管理的,但是從整個應用或某個應用模塊來考慮的話,除了deployment,可能還會有其他的configmap之類的去跟其關聯。這時我們會想,是否有這樣一個工具可以在更上層的維度去管理這些應用呢?這個時候我們就有了社區的一個包管理工具:Helm。
Helm的好處,大概就有這些:
利用已有的Chart快速部署進行實驗
• 創建自定義Chart,方便地在團隊間共享
• 便於管理應用的生命周期
• 便於應用的依賴管理和重用
• 將K8S集群作為應用發布協作中心
二、helm安裝
Helm其實就是一個二進制工具。你只要把它下載下來,已經配置好了kubeconfig的一些相關配置信息,就可以在K8S中做應用的部署和管理了。
用Helm可以做什么事情呢?其實Helm分為服務端跟客戶端兩部分,你在helm init之后,它會把一個叫做Tiller的服務端,部署在K8S里面。這個服務端可以幫你管理Helm Chart應用包的一個完整生命周期。

自Kubernetes 1.6版本開始,API Server啟用了RBAC授權。而目前的Tiller部署沒有定義授權的ServiceAccount,這會導致訪問API Server時被拒絕。我們可以采用如下方法,明確為Tiller部署添加授權。
kubectl create serviceaccount --namespace kube-system tiller kubectl create clusterrolebinding tiller-cluster-rule --clusterrole=cluster-admin --serviceaccount=kube-system:tiller kubectl patch deploy --namespace kube-system tiller-deploy -p '{"spec":{"template":{"spec":{"serviceAccount":"tiller"}}}}'
加入這幾行,就可以使用helm list等命令了
三、Helm Chart
它本質上是一個應用包,你可以把它理解成dpkg或者像rpm這樣的包。只不過,它是基於K8S領域的一個應用包的概念。你可以對同一個chart包進行多次部署,每次安裝它都會產生一個Release。這個Release相當於一個chart中的安裝實例
現在我們已經把Tiller部署進去了,那么就可以去做我們應用的管理了:
$ helm install <chart> # (stable/mariadb, ./nginx-1.2.3.tgz, ./nginx, https://example.com/charts/nginx-1.2.3.tgz) $ helm upgrade <release> $ helm delete <release>
$ helm search
$ helm list
關於一些常用的命令例如安裝一個應用包,可以用install,它其實是可以支持不同格式的:比如說本地的一些chart包,或者說你的遠程倉庫路徑。
對於應用的更新,用Helm upgrade。
如果要刪除的話,就用Helm Delete。
Helm的一個Release會生成對應的Configmap,由它去存儲這個Release的信息,並存在K8S里面。它相當於把應用的一個生命周期的迭代,直接跟K8S去做關聯,哪怕Tiller掛了,但只要你的配置信息還在,這個應用的發布和迭代歷程不會丟失:例如想回滾到以前的版本,或者是查看它的升級路徑等。
接下來我們看一個chart的結構。
$ helm create demoapp

用Helm create的話,它會提供一個大概的框架,你可以去創建自己的一個應用。比如說這個應用就叫做Demoapp,里面會有如下內容:

其中最核心的是templates,即模板化的K8S manifests文件,這里面會包括資源的定義,例如deployment、service等。現在我們create出來的是一個默認的、用一個nginx deployment去部署的應用。
它本質上就是一個Go的template模板。Helm在Go template模板的基礎上,還會增加很多東西。如一些自定義的元數據信息、擴展的庫以及一些類似於編程形式的工作流,例如條件語句、管道等等。這些東西都會使得我們的模板變得非常豐富。
有了模板,我們怎么把我們的配置融入進去呢?用的就是這個values文件。這兩部分內容其實就是chart的核心功能。


這個deployment,就是一個Go template的模板。里面可以定義一些預設的配置變量。這些變量就是從values文件中讀取出來的。這樣一來,我們就有了一個應用包的模板,可以用不同的配置將這個應用包部署在不同的環境中去。除此之外,在Helm install/upgrade時候,可以使用不同的value。
配置選項:

$ helm install --set image.tag=latest ./demoapp
$ helm install -f stagingvalues.yaml ./demoapp
比如說你可以set某個單獨的變量,你可以用整個File去做一個部署,它會用你現在的配置覆蓋掉它的默認配置。因此我們可以在不同的團隊之間,直接用不同的配置文件,並用同樣的應用包去做應用管理。Chart.yaml即chart的元數據,描述的就是這個chart包的信息。


另外還有一些文檔的說明,例如NOTES.txt,一般放在templates里面,它是在你安裝或者說你察看這個部署詳情之時(helm status),自動列出來的。通常會放一些部署了的應用和如何訪問等一些描述性的信息。

除了模板以外,Helm chart的另一個作用就是管理依賴。


比如說你部署一個Wordpress,它可以依賴一些數據庫服務。你可以把數據庫服務作為一個chart形式,放在一個依賴的目錄下面。這樣的話應用之間的依賴管理就可以做的很方便了。
假如現在已經創建了我們自己的應用包,想要有一個倉庫去管理這個包,在團隊之間共享應該怎么做?
chart的倉庫其實就是一個HTTP服務器。只要你把你的chart以及它的索引文件放到上面,在Helm install的時候,就可以通過上面的路徑去拿。
Helm工具本身也提供一個簡單的指令,叫Helm serve,幫你去做一個開發調試用的倉庫。
例如 https://example.com/charts 的倉庫目錄結構:
關於 Helm,社區版其實已經有了很多的應用包,一般放在K8S下面的一些項目中,比如安裝Helm時候,它默認就有一個Stable的項目。里面會有各種各樣的應用包。Stable和incubator chart 倉庫:https://github.com/kubernetes/charts
使用templates/_helpers.tpl
在_helpers.tpl里面定義內容,比如
{{- define "prometheus-operator.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 50 | trimSuffix "-" -}} #Chart和Values為文件
{{- end }}
{{- define "prometheus-operator.labels" }}
release: {{ .Release.Name | quote }} #Release為一個文件
{{- end }}
在文件里面引用
apiVersion: v1 kind: ServiceAccount metadata: name: prometheus-operator labels: app: {{ template "prometheus-operator.name" . }}-alertmanager #template表示引用模版變量 {{ include "prometheus-operator.labels" . | indent 4 }} #include標表示必須有這個內容 imagePullSecrets: {{ toYaml .Values.global.imagePullSecrets | indent 2 }} #toYaml表示引用后轉化yaml文件格式,官方沒找到,應該這個含義吧。。 {{- end }}
四、Operator
我們接下來說說Operator。為什么講Operator呢?Operator其實並不是一個工具,而是為了解決一個問題而存在的一個思路。什么問題?就是我們在管理應用時,會遇到無狀態和有狀態的應用。管理無狀態的應用是相對來說比較簡單的,但是有狀態的應用則比較復雜。在Helm chart的stable倉庫里面,很多數據庫的chart其實是單節點的,因為分布式的數據庫做起來會較為麻煩。
Operator的理念是希望注入領域知識,用軟件管理復雜的應用。例如對於有狀態應用來說,每一個東西都不一樣,都可能需要你有專業的知識去處理。對於不同的數據庫服務,擴容縮容以及備份等方式各有區別。能不能利用K8S便捷的特性去把這些復雜的東西簡單化呢?這就是Operator想做的事情。
以無狀態應用來說,把它做成一個Scale UP的話是比較簡單的:擴充一下它的數量就行了。


接着在deployment或者是說ReplicaSet的controller中,會去判斷它當前的狀態,並向目標狀態進行遷移。對有狀態的應用來說,我們常常需要考慮很多復雜的事情,包括升級、配置更新、備份、災難恢復、Scale調整數量等等,有時相當於將整個配置刷一遍,甚至可能要重啟一些服務。
比如像Zookeeper315以前不能實時更新集群狀態,想要擴容非常麻煩,可能需要把整個節點重啟一輪。有些數據庫可能方便一點,到master那里注冊一下就好。因此每個服務都會有它自己的特點。
拿etcd來說,它是K8S里面主要的存儲。如果對它做一個Scale up的話,需要往集群中添加一些新節點的連接信息,從而獲取到集群的不同Member的配置連接。然后用它的集群信息去啟動一個新的etcd節點。
如果有了etcd Operator,會怎么樣?Operator其實是CoreOS布道的東西。CoreOS給社區出了幾個開源的Operator,包括etcd,那么如何在這種情況下去擴容一個etcd集群?
首先可以以deployment的形式把etcd Operator部署到K8S中。部署完這個Operator之后,想要部署一個etcd的集群,其實很方便。因為不需要再去管理這個集群的配置信息了,你只要告訴我,你需要多少的節點,你需要什么版本的etcd,然后創建這樣一個自定義的資源,Operator會監聽你的需求,幫你創建出配置信息來。
$ kubectl create –f etcd-cluster.yaml
要擴容的話也很簡單,只要更新數量(比如從3改到5),再apply一下,它同樣會監聽這個自定義資源的變動,去做對應的更新。
$ kubectl apply -f upgrade-example.yaml

這樣就相當於把以前需要運維人員去處理集群的一些工作全部都交付給Operator去完成了。如何做到的呢?即應用了K8S的一個擴展性的API——CRD(在以前稱為第三方資源)。
在部署了一個etcd Operator之后,通過kubernetes API去管理和維護目標的應用狀態。本質上走的就是K8S里面的Controller的模式。K8S Controller會對它的resource做這樣的一個管理:去監聽或者是說檢查它預期的狀態,然后跟當前的狀態作對比。如果其中它會有一些差異的話,它會去做對應的更新。
Kubernetes Controller 模式:

etcd的做法是在拉起一個etcd Operator的時候,創建一個叫etcd cluster的自定義資源,監聽應用的變化。比如你的聲明你的更新,它都會去產生對應的一個事件,去做對應的更新,將你的etcd集群維護在這樣的狀態。
除了etcd以外,社區比如還有普羅米修斯Operator都可以以這種方便的形式,去幫你管理一些有狀態的應用。
值得一提的是,Rancher2.0廣泛采用了Kubernetes-native的Controller模式,去管理應用負載乃至K8S集群,調侃地說,是個Kubernetes operator。
五、Helm和Operator的對比
這兩個東西講完了,我們來對比一下二者吧。
Operator本質上是針對特定的場景去做有狀態服務,或者說針對擁有復雜應用的應用場景去簡化其運維管理的工具。Helm的話,它其實是一個比較普適的工具,想法也很簡單,就是把你的K8S資源模板化,方便共享,然后在不同的配置中重用。
其實Operator做的東西Helm大部分也可以做。用Operator去監控更新etcd的集群狀態,也可以用定制的Chart做同樣的事情。只不過你可能需要一些更復雜的處理而已,例如在etcd沒有建立起來時候,你可能需要一些init Container去做配置的更新,去檢查狀態,然后把這個節點用對應的信息給拉起來。刪除的時候,則加一些PostHook去做一些處理。所以說Helm是一個更加普適的工具。兩者甚至可以結合使用,比如stable倉庫里就有etcd-operator chart。
就個人理解來說,在K8S這個龐然大物之上,他們兩者都誕生於簡單但自然的想法,helm是為了配置分離,operator則是針對復雜應用的自動化管理。
