一、背景
Kubernetes是目前最爲流行、成爲事實標準的容器集羣管理平臺,爲容器化應用提供了部署運行、資源調度、服務發現和動態伸縮等一系列完整功能。在Kubernetes當中,用戶通過使用API對象,如Pod、Service、Deployment等,來描述應用的程序規則,而這些資源對象的定義一般需要寫入一系列的YAML文件中,然後通過 Kubernetes 命令行工具Kubectl進行部署。由於通常應用程序都涉及到多個Kubernetes API對象,而要描述這些API對象就可能要同時維護多個YAML文件,從而在進行 Kubernetes 軟件部署時,通常會面臨下述幾個問題:
· 如何管理、編輯和更新這些這些分散的 Kubernetes 應用配置文件
· 如何把一套相關的配置文件作爲一個應用進行管理
· 如何分發和重用 Kubernetes 的應用配置
Helm (https://helm.sh)的出現就是爲了很好地解決上面這些問題,是Kubernetes官方提供的包管理工具,主要是是通過管理被稱作Helm Chart的包來描述和管理雲服務的。使用 Helm後就不需要再編寫複雜的應用部署文件,可以以簡單的方式在 Kubernetes 上查找、安裝、升級、回滾、卸載應用程序。
在現在常用的Helm V2架構中,有一個稱爲“Tiller”的服務端組件。Tiller是一個集羣內服務器,可與Helm客戶端進行交互,並與Kubernetes API服務器連接。但由於Tiller具有root用戶訪問權限,使得有人可以未經授權訪問Kubernetes服務器你,從而構成了很大的風險。
JFrog的專家,也是Helm的聯合創始人,Rimas Mocevicius,提供了一種創新的、優雅的方法——Tillerless Helm,來解決這種情況,從而保護用戶的Kubernetes集羣。
二、Helm V2的應用架構
從Helm v2開始,Helm的架構中有一個名爲The Tiller Server的服務器部分,該服務器部分是一個與helm客戶端交互並與Kubernetes API服務器連接的集羣內服務器。服務器負責以下各項工作:
· 監聽來自Helm客戶端的傳入請求
· 結合Chart和配置以創建發佈版本
· 將Chart安裝到Kubernetes中,然後跟蹤後續版本
· 通過與Kubernetes交互來升級和卸載Chart
簡而言之,客戶端負責管理Chart,Tiller負責管理髮布版本,其架構如下圖所示:
默認情況下,執行如下命令將Tiller部署安裝到Kubernetes集羣:
helm init
同時還需要爲Tiller創建並部署RBAC授權,使其擁有執行任務的權限。Tiller常用的RBAC授權如下所示:
目前這樣的架構工作得很好,爲用戶提供了靈活和方便,但同時也存在一些安全問題。從上面的RBAC文件中可以看出,Tiller被授予了cluster-admin的角色,也就是說,Tiller在用戶的Kubernetes集羣中具有完全的管理權限,這就具備了有人未經授權而訪問和控制集羣的風險。
三、Helm V2 中的Tillerless方案
其實,在Helm V2中創建Tillerless的架構也並不困難,能夠爲Helm的應用提供更高的安全保障。JFrog的專家Rimas給出了優化的解決方案,而本節將通過細節的描述來解釋該方案如何運行。
首先,可以將Helm客戶端和Tiller都部署在工作站上,或者運行在CI/CD流水線中,而不需要將Tiller安裝到Kubernetes集羣之中。示例的安裝方式如下:
$ export TILLER_NAMESPACE=my-team-namespace
$ export HELM_HOST=localhost:44134
$ tiller --storage=secret
[main] 2018/07/23 15:52:29 Starting Tiller v2.10.0 (tls=false)
[main] 2018/07/23 15:52:29 GRPC listening on :44134
[main] 2018/07/23 15:52:29 Probes listening on :44135
[main] 2018/07/23 15:52:29 Storage driver is Secret
[main] 2018/07/23 15:52:29 Max history per release is 0
在這種安裝方式下,Helm的運行架構如下圖所示:
在這種架構下,Tiller使用和Helm客戶端一樣的配置(kubeconfig)連接到Kubernetes集羣,並按照指定的命名空間(namespace)存儲和管理Helm的發行版本信息。用戶可以通過這種方式創建許多名稱空間,並在Tiller啓動時指定應該使用哪個命名空間。用戶定義的RBAC規則可以存儲在運行指定的名稱空間中的密鑰/配置映射中,而不再需要爲Tiller創建和指定ServiceAccount。而這個架構的另一個好處就是不再限定Kubernetes集羣中只能運行一個Tiller實例。
注意,在這種架構下,必須使用如下的命令來初始化Helm客戶端,否則Tiller仍然被安裝到Kubernetes集羣中:
helm init --client-only
四、Helm V2中的Tillerless插件
那麼,有沒有更加方便的安裝方式呢?Rimas爲大家提供了一個簡單的Helm Tillerless插件,請參見https://github.com/rimusz/helm-tiller。
插件的安裝非常方便,如下:
$ helm plugin install https://github.com/rimusz/helm-tiller
Installed plugin: tiller
該插件提供了四個簡單的命令:start,start-ci,stop和run。
4.1 在本地使用Tillerless插件
對於在本地開發或訪問遠程Kubernetes集羣時,請使用helm tiller start命令:
$ helm tiller start
Client: &version.Version{SemVer:"v2.10.0", GitCommit:"20adb27c7c5868466912eebdf6664e7390ebe710", GitTreeState:"clean"}
[main] 2018/07/23 16:08:07 Starting Tiller v2.10.0 (tls=false)
[main] 2018/07/23 16:08:07 GRPC listening on :44134
[main] 2018/07/23 16:08:07 Probes listening on :44135
[main] 2018/07/23 16:08:07 Storage driver is Secret
[main] 2018/07/23 16:08:07 Max history per release is 0
Server: &version.Version{SemVer:"v2.9.1", GitCommit:"20adb27c7c5868466912eebdf6664e7390ebe710", GitTreeState:"clean"}
Tiller namespace: kube-system
該命令將在本地啓動Tiller,並利用Tiller默認的設置,在kube-system名稱空間存儲和管理Helm版本。
也可以通過下述命令指定Tiller使用的命名空間:
$ helm tiller start my-team-namespace
Client: &version.Version{SemVer:"v2.10.0", GitCommit:"20adb27c7c5868466912eebdf6664e7390ebe710", GitTreeState:"clean"}
[main] 2018/07/23 16:08:38 Starting Tiller v2.10.0 (tls=false)
[main] 2018/07/23 16:08:38 GRPC listening on :44134
[main] 2018/07/23 16:08:38 Probes listening on :44135
[main] 2018/07/23 16:08:38 Storage driver is Secret
[main] 2018/07/23 16:08:38 Max history per release is 0
Server: &version.Version{SemVer:"v2.10.0", GitCommit:"20adb27c7c5868466912eebdf6664e7390ebe710", GitTreeState:"clean"}
Tiller namespace: my-team-namespace
該命令還會打開一個新bash shell,帶有預設的環境變量:
HELM_HOST=localhost:44134
這樣,Helm客戶端就知道如何連接Tiller了。
現在,就可以開始部署或更新Helm的發佈版本了。
當完成了所有工作之後,只需要運行下述命令,就可以關閉Tiller了。
$ exit
$ helm tiller stop
/Users/user/.helm/plugins/helm-tiller
Stopping Tiller..
接下來,用戶也可以重複上面的過程,通過指定新的命名空間來部署和更新其他團隊的發佈版本。
4.2 在CI/CD流水線中使用Tillerless插件
那如何在CI/CD流水線當中使用該插件呢?有兩種方法:
第一種與上面的過程非常相似,只是沒有啓動帶有預設變量的bash shell。
$ helm tiller start-ci
$ export HELM_HOST=localhost:44134
然後,Helm客戶端將知道連接到Tiller的位置,而無需在CI流水線中進行任何更改。並且在流水線的結尾執行:
$ helm tiller stop
結束全部工作。
第二種也很容易,就是運行helm tiller run,可以使Tiller在指定命令之前或之後啓動/停止:
$ helm tiller run helm list
$ helm tiller run my-team-namespace -- helm list
$ helm tiller run my-team-namespace -- bash -c 'echo running helm; helm list'
舉例來看:
$ helm tiller run test -- bash -c 'echo running helm; helm list'
Installed Helm version v2.10.0
Installing Tiller v2.10.0 ...
x tiller
args=bash -c echo running helm; helm list
Client: &version.Version{SemVer:"v2.10.0", GitCommit:"20adb27c7c5868466912eebdf6664e7390ebe710", GitTreeState:"clean"}
[main] 2018/07/25 17:33:54 Starting Tiller v2.10.0 (tls=false)
[main] 2018/07/25 17:33:54 GRPC listening on :44134
[main] 2018/07/25 17:33:54 Probes listening on :44135
[main] 2018/07/25 17:33:54 Storage driver is Secret
[main] 2018/07/25 17:33:54 Max history per release is 0
Server: &version.Version{SemVer:"v2.10.0", GitCommit:"20adb27c7c5868466912eebdf6664e7390ebe710", GitTreeState:"clean"}
Tiller namespace: test
running helm
[storage] 2018/07/25 17:33:55 listing all releases with filter
NAME REVISION UPDATED STATUS CHART NAMESPACE
keel 1 Sun Jul 22 15:42:43 2018 DEPLOYED keel-0.5.0 default
Stopping Tiller...
附加功能:該插件還能夠檢查安裝的Helm客戶端和Tiller的版本,如果不匹配,則下載正確的Tiller版本文件。
五、總結
Helm作爲Kubenetes的官方包管理工具,爲用戶提供了方便、快捷的在Kubernetes集羣裏部署和管理自己應用程序的方式。然而,Helm V2架構中的Tiller組件,在提供了操作便利的同時,也帶來了安全上的隱患。
本文爲大家介紹了一種在Helm V2中實現Tillerless的Helm部署和應用的解決方案,在保留了Helm V2靈活性和便利性的同時,也大大提升了應用和管理的安全性。