Why Helm
每個成功的軟件平台都有一個優秀的打包系統,比如 Debian、Ubuntu 的 apt,Redhat、Centos 的 yum。而 Helm 則是 Kubernetes 上的包管理器。
本章我們將討論為什么需要 Helm,它的架構和組件,以及如何使用 Helm。
Why Helm
Helm 到底解決了什么問題?為什么 Kubernetes 需要 Helm?
答案是:Kubernetes 能夠很好地組織和編排容器,但它缺少一個更高層次的應用打包工具,而 Helm 就是來干這件事的。
先來看個例子。
比如對於一個 MySQL 服務, Kubernetes 需要部署下面這些對象: service secret PVC deployment
-
Service,讓外界能夠訪問到 MySQL。
-
Secret,定義 MySQL 的密碼。
-
PersistentVolumeClaim,為 MySQL 申請持久化存儲空間。
-
Deployment,部署 MySQL Pod,並使用上面的這些支持對象。
我們可以將上面這些配置保存到對象各自的文件中,或者集中寫進一個配置文件,然后通過 kubectl apply -f
部署。
到目前為止,Kubernetes 對服務的部署支持得都挺好,如果應用只由一個或幾個這樣的服務組成,上面的部署方式完全足夠了。
但是,如果我們開發的是微服務架構的應用,組成應用的服務可能多達十個甚至幾十上百個,這種組織和管理應用的方式就不好使了:
-
很難管理、編輯和維護如此多的服務。每個服務都有若干配置,缺乏一個更高層次的工具將這些配置組織起來。
-
不容易將這些服務作為一個整體統一發布。部署人員需要首先理解應用都包含哪些服務,然后按照邏輯順序依次執行
kubectl apply
。即缺少一種工具來定義應用與服務,以及服務與服務之間的依賴關系。 -
不能高效地共享和重用服務。比如兩個應用都要用到 MySQL 服務,但配置的參數不一樣,這兩個應用只能分別拷貝一套標准的 MySQL 配置文件,修改后通過
kubectl apply
部署。也就是說不支持參數化配置和多環境部署。 -
不支持應用級別的版本管理。雖然可以通過
kubectl rollout undo
進行回滾,但這只能針對單個 Deployment,不支持整個應用的回滾。 -
不支持對部署的應用狀態進行驗證。比如是否能通過預定義的賬號訪問 MySQL。雖然 Kubernetes 有健康檢查,但那是針對單個容器,我們需要應用(服務)級別的健康檢查。
Helm 能夠解決上面這些問題,Helm 幫助 Kubernetes 成為微服務架構應用理想的部署平台。
下一節我們討論 Helm 的架構。
Helm 架構
在實踐之前,我們先來看看 Helm 的架構。
Helm 有兩個重要的概念:chart 和 release。
chart 是創建一個應用的信息集合,包括各種 Kubernetes 對象的配置模板、參數定義、依賴關系、文檔說明等。
chart 是應用部署的自包含邏輯單元。可以將 chart 想象成 apt、yum 中的軟件安裝包。
release 是 chart 的運行實例,代表了一個正在運行的應用。
當 chart 被安裝到 Kubernetes 集群,就生成一個 release。chart 能夠多次安裝到同一個集群,每次安裝都是一個 release。 --name=指定release名稱
Helm 是包管理工具,這里的包就是指的 chart。
Helm 能夠:
- 從零創建新 chart。
- 與存儲 chart 的倉庫交互,拉取、保存和更新 chart。
- 在 Kubernetes 集群中安裝和卸載 release。
- 更新、回滾和測試 release。
Helm 包含兩個組件:Helm 客戶端 和 Tiller 服務器。
Helm 客戶端是終端用戶使用的命令行工具,用戶可以:
- 在本地開發 chart。
- 管理 chart 倉庫。
- 與 Tiller 服務器交互。
- 在遠程 Kubernetes 集群上安裝 chart。
- 查看 release 信息。
- 升級或卸載已有的 release。
Tiller 服務器運行在 Kubernetes 集群中,它會處理 Helm 客戶端的請求,與 Kubernetes API Server 交互。Tiller 服務器負責:
- 監聽來自 Helm 客戶端的請求。
- 通過 chart 構建 release。
- 在 Kubernetes 中安裝 chart,並跟蹤 release 的狀態。
- 通過 API Server 升級或卸載已有的 release。
簡單的講:Helm 客戶端負責管理 chart;Tiller 服務器負責管理 release。
下一節我們將安裝和部署 Helm。
Helm 客戶端
通常,我們將 Helm 客戶端安裝在能夠執行 kubectl
命令的節點上,只需要下面一條命令:
curl https://raw.githubusercontent.com/kubernetes/helm/master/scripts/get | bash
安裝后,執行 helm version
驗證。
daweij@master:~$ curl https://raw.githubusercontent.com/kubernetes/helm/master/scripts/get | bash % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 6689 100 6689 0 0 6634 0 0:00:01 0:00:01 --:--:-- 6629 Downloading https://kubernetes-helm.storage.googleapis.com/helm-v2.8.2-linux-amd64.tar.gz Preparing to install into /usr/local/bin [sudo] password for daweij: helm installed into /usr/local/bin/helm Run 'helm init' to configure helm. daweij@master:~$ helm version Client: &version.Version{SemVer:"v2.8.2", GitCommit:"a80231648a1473929271764b920a8e346f6de844", GitTreeState:"clean"} Error: cannot connect to Tiller
目前只能查看到客戶端的版本,服務器還沒有安裝。
helm 有很多子命令和參數,為了提高使用命令行的效率,通常建議安裝 helm 的 bash 命令補全腳本,方法如下:
helm completion bash > .helmrc
echo "source .helmrc" >> .bashrc
重新登錄后就可以通過 Tab
鍵補全 helm 子命令和參數了。
daweij@master:~$ helm completion bash > .helmrc daweij@master:~$ echo "source .helmrc" >> .bashrc daweij@master:~$ logout root@master:/# su - daweij daweij@master:~$ helm completion dependency history inspect list repo search template verify create fetch home install package reset serve test version delete get init lint plugin rollback status upgrade daweij@master:~$ helm install -- --ca-file= --kube-context= --timeout= --cert-file= --name= --tls --debug --namespace= --tls-ca-cert= --dep-up --name-template= --tls-cert= --devel --no-hooks --tls-key= --dry-run --replace --tls-verify --home= --repo= --values= --host= --set= --verify --key-file= --tiller-connection-timeout= --version= --keyring= --tiller-namespace= --wait
Tiller 服務器
Tiller 服務器安裝非常簡單,只需要執行 helm init
:
daweij@master:~$ helm init Creating /home/daweij/.helm Creating /home/daweij/.helm/repository Creating /home/daweij/.helm/repository/cache Creating /home/daweij/.helm/repository/local Creating /home/daweij/.helm/plugins Creating /home/daweij/.helm/starters Creating /home/daweij/.helm/cache/archive Creating /home/daweij/.helm/repository/repositories.yaml Adding stable repo with URL: https://kubernetes-charts.storage.googleapis.com Adding local repo with URL: http://127.0.0.1:8879/charts $HELM_HOME has been configured at /home/daweij/.helm. Tiller (the Helm server-side component) has been installed into your Kubernetes Cluster. Please note: by default, Tiller is deployed with an insecure 'allow unauthenticated users' policy. For more information on securing your installation see: https://docs.helm.sh/using_helm/#securing-your-helm-installation Happy Helming!
Tiller 本身也是作為容器化應用運行在 Kubernetes Cluster 中的:
daweij@master:~$ kubectl get svc tiller-deploy --namespace=kube-system NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE tiller-deploy ClusterIP 10.233.21.116 <none> 44134/TCP 9m daweij@master:~$ kubectl get deployment tiller-deploy --namespace=kube-system NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE tiller-deploy 1 1 1 0 9m daweij@master:~$ kubectl get pod tiller-deploy-865dd6c794-g74qv --namespace=kube-system NAME READY STATUS RESTARTS AGE tiller-deploy-865dd6c794-g74qv 0/1 ImagePullBackOff 0 10m
可以看到 Tiller 的 Service、Deployment 和 Pod。
因無法FAN牆,鏡像下載失敗:
daweij@master:~$ kubectl describe pod tiller-deploy-865dd6c794-g74qv --namespace=kube-system ...... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 10m default-scheduler Successfully assigned tiller-deploy-865dd6c794-g74qv to node2 Normal SuccessfulMountVolume 10m kubelet, node2 MountVolume.SetUp succeeded for volume "default-token-7m87c" Normal SandboxChanged 9m kubelet, node2 Pod sandbox changed, it will be killed and re-created. Warning Failed 8m (x3 over 9m) kubelet, node2 Error: ErrImagePull Normal BackOff 8m (x6 over 9m) kubelet, node2 Back-off pulling image "gcr.io/kubernetes-helm/tiller:v2.8.2" Normal Pulling 7m (x4 over 10m) kubelet, node2 pulling image "gcr.io/kubernetes-helm/tiller:v2.8.2" Warning Failed 7m (x4 over 9m) kubelet, node2 Failed to pull image "gcr.io/kubernetes-helm/tiller:v2.8.2": rpc error: code = Unknown desc = Error response from daemon: Get https://gcr.io/v2/: net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers) Warning Failed 5s (x36 over 9m) kubelet, node2 Error: ImagePullBackOff
鏡像為:
gcr.io/kubernetes-helm/tiller:v2.8.2
dockerhub中比較新的可以用:
docker pull jiang7865134/tiller:v2.8.2
docker tag jiang7865134/tiller:v2.8.2 gcr.io/kubernetes-helm/tiller:v2.8.2
現在, helm version
已經能夠查看到服務器的版本信息了。
daweij@master:~$ helm version Client: &version.Version{SemVer:"v2.8.2", GitCommit:"a80231648a1473929271764b920a8e346f6de844", GitTreeState:"clean"} Server: &version.Version{SemVer:"v2.8.2", GitCommit:"a80231648a1473929271764b920a8e346f6de844", GitTreeState:"clean"}
Helm 部署完畢,下一節開始使用 Helm。
Helm 安裝成功后,可執行 helm search
查看當前可安裝的 chart。
daweij@master:~$ helm search NAME CHART VERSION APP VERSION DESCRIPTION stable/acs-engine-autoscaler 2.1.3 2.1.1 Scales worker nodes within agent pools stable/aerospike 0.1.7 v3.14.1.2 A Helm chart for Aerospike in Kubernetes stable/anchore-engine 0.1.4 0.1.6 Anchore container analysis and policy evaluatio... stable/artifactory 7.0.6 5.9.1 Universal Repository Manager supporting all maj... stable/artifactory-ha 0.1.3 5.9.1 Universal Repository Manager supporting all maj... stable/aws-cluster-autoscaler 0.3.3 Scales worker nodes within autoscaling groups. stable/bitcoind 0.1.1 0.15.1 Bitcoin is an innovative payment network and a ... stable/buildkite 0.2.2 3 Agent for Buildkite stable/burrow 0.4.2 0.17.1 Burrow is a permissionable smart contract machine stable/centrifugo 2.0.1 1.7.3 Centrifugo is a real-time messaging server. stable/cert-manager 0.2.4 0.2.3 A Helm chart for cert-manager
這個列表很長,這里只截取了一部分。大家不禁會問,這些 chart 都是從哪里來的?
前面說過,Helm 可以像 apt 和 yum 管理軟件包一樣管理 chart。apt 和 yum 的軟件包存放在倉庫中,同樣的,Helm 也有倉庫。
daweij@master:~$ helm repo list NAME URL stable https://kubernetes-charts.storage.googleapis.com local http://127.0.0.1:8879/charts
Helm 安裝時已經默認配置好了兩個倉庫:stable
和 local
。
stable
是官方倉庫,local
是用戶存放自己開發的 chart 的本地倉庫。
helm search
會顯示 chart 位於哪個倉庫,比如 local/cool-chart
和 stable/acs-engine-autoscaler
。
用戶可以通過 helm repo add
添加更多的倉庫,比如企業的私有倉庫,倉庫的管理和維護方法請參考官網文檔 https://docs.helm.sh
與 apt 和 yum 一樣,helm 也支持關鍵字搜索:
daweij@master:~$ helm search mysql NAME CHART VERSION APP VERSION DESCRIPTION stable/mysql 0.3.6 Fast, reliable, scalable, and easy to use open-... stable/percona 0.3.1 free, fully compatible, enhanced, open source d... stable/percona-xtradb-cluster 0.1.3 5.7.19 free, fully compatible, enhanced, open source d... stable/gcloud-sqlproxy 0.3.1 Google Cloud SQL Proxy stable/mariadb 2.1.17 10.1.32 Fast, reliable, scalable, and easy to use open-... daweij@master:~$
包括 DESCRIPTION 在內的所有信息,只要跟關鍵字匹配,都會顯示在結果列表中。
安裝 chart 也很簡單,執行如下命令可以安裝 MySQL。
helm install stable/mysql
如果看到如下報錯,通常是因為 Tiller 服務器的權限不足。
daweij@master:~$ helm install stable/mysql Error: no available release name found daweij@master:~$ helm install stable/mysql:0.3.6 Error: failed to download "stable/mysql:0.3.6"
執行如下命名添加權限:
kubectl create serviceaccount --namespace kube-system tiller kubectl create clusterrolebinding tiller-cluster-rule --clusterrole=cluster-admin --serviceaccount=kube-system:tiller
查看
daweij@master:~$ kubectl get serviceaccount tiller --namespace=kube-system NAME SECRETS AGE tiller 1 1h daweij@master:~$ kubectl describe clusterrolebinding tiller-cluster-rule Name: tiller-cluster-rule Labels: <none> Annotations: <none> Role: Kind: ClusterRole Name: cluster-admin Subjects: Kind Name Namespace ---- ---- --------- ServiceAccount tiller kube-system
編輯應用:
kubectl patch deployment --namespace kube-system tiller-deploy -p '{"spec":{"template":{"spec":{"serviceAccount":"tiller"}}}}'
或kubectl edit deploy --namespace kube-system tiller-deploy
中添加serviceAccount: tiller
然后再次執行
helm install stable/mysql
添加權限后,報錯如下:(下述為k8s集群創建時導致的問題(node4后添加))
daweij@master:~$ helm install stable/mysql Error: forwarding ports: error upgrading connection: error dialing backend: dial tcp: lookup node4 on 172.16.0.1:53: server misbehaving
輸出分為三部分:
① chart 本次部署的描述信息:
NAME
是 release 的名字,因為我們沒用 -n
參數指定,Helm 隨機生成了一個,這里是 fun-zorse
。
NAMESPACE
是 release 部署的 namespace,默認是 default
,也可以通過 --namespace
指定。
STATUS
為 DEPLOYED
,表示已經將 chart 部署到集群。
② 當前 release 包含的資源:Service、Deployment、Secret 和 PersistentVolumeClaim,其名字都是 fun-zorse-mysql
,命名的格式為 ReleasName
-ChartName
。
③ NOTES
部分顯示的是 release 的使用方法。比如如何訪問 Service,如何獲取數據庫密碼,以及如何連接數據庫等。
通過 kubectl get
可以查看組成 release 的各個對象:

daweij@master:~/helm$ kubectl get service limping-angelfish-mysql NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE limping-angelfish-mysql ClusterIP 10.233.43.76 <none> 3306/TCP 44s daweij@master:~/helm$ kubectl get deployment limping-angelfish-mysql NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE limping-angelfish-mysql 1 1 1 0 1m daweij@master:~/helm$ kubectl get pod limping-angelfish-mysql-5645f4b999-5lk8s NAME READY STATUS RESTARTS AGE limping-angelfish-mysql-5645f4b999-5lk8s 0/1 Init:0/1 0 1m daweij@master:~/helm$ kubectl get pvc limping-angelfish-mysql NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE limping-angelfish-mysql Pending 1m
因為還沒有准備 PersistentVolume,當前 release 還不可用。
helm list
顯示已經部署的 release,helm delete
可以刪除 release。
daweij@master:~/helm$ helm list limping-angelfish NAME REVISION UPDATED STATUS CHART NAMESPACE limping-angelfish 1 Tue Apr 24 13:33:42 2018 DEPLOYED mysql-0.3.6 default daweij@master:~/helm$ helm delete limping-angelfish release "limping-angelfish" deleted
Helm 的使用方法像極了 apt 和 yum,用 Helm 來管理 Kubernetes 應用非常方便。
chart 是 Helm 的應用打包格式,下節我們詳細介紹。
chart 是 Helm 的應用打包格式。chart 由一系列文件組成,這些文件描述了 Kubernetes 部署應用時所需要的資源,比如 Service、Deployment、PersistentVolumeClaim、Secret、ConfigMap 等。
單個的 chart 可以非常簡單,只用於部署一個服務,比如 Memcached;chart 也可以很復雜,部署整個應用,比如包含 HTTP Servers、 Database、消息中間件、cache 等。
chart 將這些文件放置在預定義的目錄結構中,通常整個 chart 被打成 tar 包,而且標注上版本信息,便於 Helm 部署。
下面我們將詳細討論 chart 的目錄結構以及包含的各類文件。
chart 目錄結構
以前面 MySQL chart 為例。一旦安裝了某個 chart,我們就可以在 ~/.helm/cache/archive 中找到 chart 的 tar 包。
daweij@master:~/helm$ ll ~/.helm/cache/archive/ total 16 drwxr-xr-x 2 daweij daweij 4096 3月 29 11:09 ./ drwxr-xr-x 3 daweij daweij 4096 3月 28 10:00 ../ -rw-r--r-- 1 daweij daweij 5533 3月 29 13:08 mysql-0.3.6.tgz daweij@master:~/helm$ tar -xzf /home/daweij/.helm/cache/archive/mysql-0.3.6.tgz daweij@master:~/helm$ ls k01-chart mysql ns-helmtest.yml uat daweij@master:~/helm$ cd mysql/ daweij@master:~/helm/mysql$ tree . ├── Chart.yaml ├── README.md ├── templates │ ├── configmap.yaml │ ├── deployment.yaml │ ├── _helpers.tpl │ ├── NOTES.txt │ ├── pvc.yaml │ ├── secrets.yaml │ └── svc.yaml └── values.yaml 1 directory, 10 files daweij@master:~/helm/mysql$
解壓后,MySQL chart 目錄結構如上。
目錄名就是 chart 的名字(不帶版本信息),這里是 mysql
,包含如下內容:
Chart.yaml
YAML 文件,描述 chart 的概要信息。
daweij@master:~/helm/mysql$ cat Chart.yaml description: Fast, reliable, scalable, and easy to use open-source relational database system. engine: gotpl home: https://www.mysql.com/ icon: https://www.mysql.com/common/logos/logo-mysql-170x115.png keywords: - mysql - database - sql maintainers: - email: viglesias@google.com name: Vic Iglesias name: mysql sources: - https://github.com/kubernetes/charts - https://github.com/docker-library/mysql version: 0.3.6
name
和 version
是必填項,其他都是可選。
README.md
Markdown 格式的 README 文件,相當於 chart 的使用文檔,此文件為可選。

daweij@master:~/helm/mysql$ cat README.md # MySQL [MySQL](https://MySQL.org) is one of the most popular database servers in the world. Notable users include Wikipedia, Facebook and Google. ## Introduction This chart bootstraps a single node MySQL deployment on a [Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager. ## Prerequisites - Kubernetes 1.6+ with Beta APIs enabled - PV provisioner support in the underlying infrastructure ## Installing the Chart To install the chart with the release name `my-release`: ```bash $ helm install --name my-release stable/mysql ``` The command deploys MySQL on the Kubernetes cluster in the default configuration. The [configuration](#configuration) section lists the parameters that can be configured during installation. By default a random password will be generated for the root user. If you'd like to set your own password change the mysqlRootPassword in the values.yaml. You can retrieve your root password by running the following command. Make sure to replace [YOUR_RELEASE_NAME]: printf $(printf '\%o' `kubectl get secret [YOUR_RELEASE_NAME]-mysql -o jsonpath="{.data.mysql-root-password[*]}"`) > **Tip**: List all releases using `helm list` ## Uninstalling the Chart To uninstall/delete the `my-release` deployment: ```bash $ helm delete my-release ``` The command removes all the Kubernetes components associated with the chart and deletes the release. ## Configuration The following table lists the configurable parameters of the MySQL chart and their default values. | Parameter | Description | Default | | ------------------------------------ | ----------------------------------------- | ---------------------------------------------------- | | `imageTag` | `mysql` image tag. | Most recent release | | `imagePullPolicy` | Image pull policy | `IfNotPresent` | | `mysqlRootPassword` | Password for the `root` user. | `nil` | | `mysqlUser` | Username of new user to create. | `nil` | | `mysqlPassword` | Password for the new user. | `nil` | | `mysqlDatabase` | Name for new database to create. | `nil` | | `livenessProbe.initialDelaySeconds` | Delay before liveness probe is initiated | 30 | | `livenessProbe.periodSeconds` | How often to perform the probe | 10 | | `livenessProbe.timeoutSeconds` | When the probe times out | 5 | | `livenessProbe.successThreshold` | Minimum consecutive successes for the probe to be considered successful after having failed. | 1 | | `livenessProbe.failureThreshold` | Minimum consecutive failures for the probe to be considered failed after having succeeded. | 3 | | `readinessProbe.initialDelaySeconds` | Delay before readiness probe is initiated | 5 | | `readinessProbe.periodSeconds` | How often to perform the probe | 10 | | `readinessProbe.timeoutSeconds` | When the probe times out | 1 | | `readinessProbe.successThreshold` | Minimum consecutive successes for the probe to be considered successful after having failed. | 1 | | `readinessProbe.failureThreshold` | Minimum consecutive failures for the probe to be considered failed after having succeeded. | 3 | | `persistence.enabled` | Create a volume to store data | true | | `persistence.size` | Size of persistent volume claim | 8Gi RW | | `persistence.storageClass` | Type of persistent volume claim | nil (uses alpha storage class annotation) | | `persistence.accessMode` | ReadWriteOnce or ReadOnly | ReadWriteOnce | | `persistence.existingClaim` | Name of existing persistent volume | `nil` | | `persistence.subPath` | Subdirectory of the volume to mount | `nil` | | `resources` | CPU/Memory resource requests/limits | Memory: `256Mi`, CPU: `100m` | | `configurationFiles` | List of mysql configuration files | `nil` | Some of the parameters above map to the env variables defined in the [MySQL DockerHub image](https://hub.docker.com/_/mysql/). Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. For example, ```bash $ helm install --name my-release \ --set mysqlRootPassword=secretpassword,mysqlUser=my-user,mysqlPassword=my-password,mysqlDatabase=my-database \ stable/mysql ``` The above command sets the MySQL `root` account password to `secretpassword`. Additionally it creates a standard database user named `my-user`, with the password `my-password`, who has access to a database named `my-database`. Alternatively, a YAML file that specifies the values for the parameters can be provided while installing the chart. For example, ```bash $ helm install --name my-release -f values.yaml stable/mysql ``` > **Tip**: You can use the default [values.yaml](values.yaml) ## Persistence The [MySQL](https://hub.docker.com/_/mysql/) image stores the MySQL data and configurations at the `/var/lib/mysql` path of the container. By default a PersistentVolumeClaim is created and mounted into that directory. In order to disable this functionality you can change the values.yaml to disable persistence and use an emptyDir instead. > *"An emptyDir volume is first created when a Pod is assigned to a Node, and exists as long as that Pod is running on that node. When a Pod is removed from a node for any reason, the data in the emptyDir is deleted forever."* ## Custom MySQL configuration files The [MySQL](https://hub.docker.com/_/mysql/) image accepts custom configuration files at the path `/etc/mysql/conf.d`. If you want to use a customized MySQL configuration, you can create your alternative configuration files by passing the file contents on the `configurationFiles` attribute. Note that according to the MySQL documentation only files ending with `.cnf` are loaded. ```yaml configurationFiles: mysql.cnf: |- [mysqld] skip-host-cache skip-name-resolve sql-mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION mysql_custom.cnf: |- [mysqld] ```
LICENSE
文本文件,描述 chart 的許可信息,此文件為可選。
requirements.yaml
chart 可能依賴其他的 chart,這些依賴關系可通過 requirements.yaml 指定,比如:
此處可參考kube-prometheus,要求./charts/中包含依賴的各chart的壓縮包
daweij@master:~/prometheus-operator/helm/kube-prometheus$ ls charts Chart.yaml README.md requirements.bak requirements.yaml templates values.yaml daweij@master:~/prometheus-operator/helm/kube-prometheus$ pwd /home/daweij/prometheus-operator/helm/kube-prometheus daweij@master:~/prometheus-operator/helm/kube-prometheus$ cd charts/ daweij@master:~/prometheus-operator/helm/kube-prometheus/charts$ ls alertmanager-0.0.13.tgz exporter-kube-dns-0.1.5.tgz exporter-kubelets-0.2.7.tgz exporter-kube-scheduler-0.1.6.tgz exporter-node-0.2.0.tgz prometheus-0.0.24.tgz exporter-kube-controller-manager-0.1.7.tgz exporter-kube-etcd-0.1.8.tgz exporter-kubernetes-0.1.6.tgz exporter-kube-state-0.1.15.tgz grafana-0.0.24.tgz
在安裝過程中,依賴的 charts 也會被一起安裝。
values.yaml
chart 支持在安裝的時根據參數進行定制化配置,而 values.yaml 則提供了這些配置參數的默認值。

daweij@master:~/helm/mysql$ cat values.yaml ## mysql image version ## ref: https://hub.docker.com/r/library/mysql/tags/ ## image: "mysql" imageTag: "5.7.14" ## Specify password for root user ## ## Default: random 10 character string # mysqlRootPassword: testing ## Create a database user ## # mysqlUser: # mysqlPassword: ## Allow unauthenticated access, uncomment to enable ## # mysqlAllowEmptyPassword: true ## Create a database ## # mysqlDatabase: ## Specify an imagePullPolicy (Required) ## It's recommended to change this to 'Always' if the image tag is 'latest' ## ref: http://kubernetes.io/docs/user-guide/images/#updating-images ## imagePullPolicy: IfNotPresent livenessProbe: initialDelaySeconds: 30 periodSeconds: 10 timeoutSeconds: 5 successThreshold: 1 failureThreshold: 3 readinessProbe: initialDelaySeconds: 5 periodSeconds: 10 timeoutSeconds: 1 successThreshold: 1 failureThreshold: 3 ## Persist data to a persistent volume persistence: enabled: true ## database data Persistent Volume Storage Class ## If defined, storageClassName: <storageClass> ## If set to "-", storageClassName: "", which disables dynamic provisioning ## If undefined (the default) or set to null, no storageClassName spec is ## set, choosing the default provisioner. (gp2 on AWS, standard on ## GKE, AWS & OpenStack) ## # storageClass: "-" accessMode: ReadWriteOnce size: 8Gi ## Configure resource requests and limits ## ref: http://kubernetes.io/docs/user-guide/compute-resources/ ## resources: requests: memory: 256Mi cpu: 100m # Custom mysql configuration files used to override default mysql settings configurationFiles: # mysql.cnf: |- # [mysqld] # skip-name-resolve ## Configure the service ## ref: http://kubernetes.io/docs/user-guide/services/ service: ## Specify a service type ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services---service-types type: ClusterIP port: 3306 # nodePort: 32000
templates 目錄
各類 Kubernetes 資源的配置模板都放置在這里。Helm 會將 values.yaml 中的參數值注入到模板中生成標准的 YAML 配置文件。
模板是 chart 最重要的部分,也是 Helm 最強大的地方。模板增加了應用部署的靈活性,能夠適用不同的環境,我們后面會詳細討論。
templates/NOTES.txt
chart 的簡易使用文檔,chart 安裝成功后會顯示此文檔內容。

daweij@master:~/helm/mysql/templates$ cat NOTES.txt MySQL can be accessed via port 3306 on the following DNS name from within your cluster: {{ template "mysql.fullname" . }}.{{ .Release.Namespace }}.svc.cluster.local To get your root password run: MYSQL_ROOT_PASSWORD=$(kubectl get secret --namespace {{ .Release.Namespace }} {{ template "mysql.fullname" . }} -o jsonpath="{.data.mysql-root-password}" | base64 --decode; echo) To connect to your database: 1. Run an Ubuntu pod that you can use as a client: kubectl run -i --tty ubuntu --image=ubuntu:16.04 --restart=Never -- bash -il 2. Install the mysql client: $ apt-get update && apt-get install mysql-client -y 3. Connect using the mysql cli, then provide your password: $ mysql -h {{ template "mysql.fullname" . }} -p To connect to your database directly from outside the K8s cluster: {{- if contains "NodePort" .Values.service.type }} MYSQL_HOST=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath='{.items[0].status.addresses[0].address}') MYSQL_PORT=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "mysql.fullname" . }} -o jsonpath='{.spec.ports[0].nodePort}') {{- else if contains "ClusterIP" .Values.service.type }} MYSQL_HOST=127.0.0.1 MYSQL_PORT={{ default "3306" .Values.service.port }} # Execute the following commands to route the connection: export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "mysql.fullname" . }}" -o jsonpath="{.items[0].metadata.name}") kubectl port-forward $POD_NAME {{ default "3306" .Values.service.port }}:{{ default "3306" .Values.service.port }} {{- end }} mysql -h ${MYSQL_HOST} -P${MYSQL_PORT} -u root -p${MYSQL_ROOT_PASSWORD}
與模板一樣,可以在 NOTE.txt 中插入配置參數,Helm 會動態注入參數值。
chart 模板
chart 模板的用法可參考:helm--chart模板文件簡單語法使用
Helm 通過模板創建 Kubernetes 能夠理解的 YAML 格式的資源配置文件,我們將通過例子來學習如何使用模板。
以 templates/secrets.yaml
為例:

apiVersion: v1 kind: Secret metadata: name: {{ template "mysql.fullname" . }} labels: app: {{ template "mysql.fullname" . }} chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" release: "{{ .Release.Name }}" heritage: "{{ .Release.Service }}" type: Opaque data: {{ if .Values.mysqlRootPassword }} mysql-root-password: {{ .Values.mysqlRootPassword | b64enc | quote }} {{ else }} mysql-root-password: {{ randAlphaNum 10 | b64enc | quote }} {{ end }} {{ if .Values.mysqlPassword }} mysql-password: {{ .Values.mysqlPassword | b64enc | quote }} {{ else }} mysql-password: {{ randAlphaNum 10 | b64enc | quote }} {{ end }}
從結構看,文件的內容非常像 Secret 配置,只是大部分屬性值變成了{{ xxx }}
。這些 {{ xxx }}
實際上是模板的語法。
Helm 采用了 Go 語言的模板來編寫 chart。Go 模板非常強大,支持變量、對象、函數、流控制等功能。
下面我們通過解析 templates/secrets.yaml
快速學習模板。
① {{ template "mysql.fullname" . }}
定義 Secret 的 name
。
關鍵字 template
的作用是引用一個子模板 mysql.fullname
。這個子模板是在 templates/_helpers.tpl
文件中定義的。
這個定義還是很復雜的,因為它用到了模板語言中的對象、函數、流控制等概念。
現在看不懂沒關系,這里我們學習的重點是:如果存在一些信息多個模板都會用到,則可在 templates/_helpers.tpl
中將其定義為子模板,然后通過 templates
函數引用。
這里 mysql.fullname
是由 release 與 chart 二者名字拼接組成。
根據 chart 的最佳實踐,所有資源的名稱都應該保持一致,對於我們這個 chart,無論 Secret 還是 Deployment、PersistentVolumeClaim、Service,它們的名字都是子模板 mysql.fullname
的值。
② Chart
和 Release
是 Helm 預定義的對象,每個對象都有自己的屬性,可以在模板中使用。如果使用下面命令安裝 chart:
helm install stable/mysql -n my
那么:{{ .Chart.Name }}
的值為 mysql
。{{ .Chart.Version }}
的值為 0.3.0
。{{ .Release.Name }}
的值為 my
。{{ .Release.Service }}
始終取值為 Tiller
。{{ template "mysql.fullname" . }}
計算結果為 my-mysql
。
③ 這里指定 mysql-root-password
的值,不過使用了 if-else
的流控制,其邏輯為:
如果 .Values.mysqlRootPassword
有值,則對其進行 base64 編碼;否則隨機生成一個 10 位的字符串並編碼。
Values
也是預定義的對象,代表的是 values.yaml
文件。而 .Values.mysqlRootPassword
則是 values.yaml
中定義的 mysqlRootPassword
參數:
因為 mysqlRootPassword
被注釋掉了,沒有賦值,所以邏輯判斷會走 else
,即隨機生成密碼。
randAlphaNum
、b64enc
、quote
都是 Go 模板語言支持的函數,函數之間可以通過管道 |
連接。{{ randAlphaNum 10 | b64enc | quote }}
的作用是首先隨機產生一個長度為 10 的字符串,然后將其 base64 編碼,最后兩邊加上雙引號。
templates/secrets.yaml
這個例子展示了 chart 模板主要的功能,我們最大的收獲應該是:模板將 chart 參數化了,通過 values.yaml
可以靈活定制應用。
無論多復雜的應用,用戶都可以用 Go 模板語言編寫出 chart。無非是使用到更多的函數、對象和流控制。對於初學者,我的建議是盡量參考官方的 chart。
根據二八定律,這些 chart 已經覆蓋了絕大部分情況,而且采用了最佳實踐。如何遇到不懂的函數、對象和其他語法,可參考官網文檔 https://docs.helm.sh
有了上面 chart 結構和模板的知識后,下節我們將重新實踐一次 MySQL chart,相信會有更多收獲。
學習了 chart 結構和模板的知識后,重新實踐一次 MySQL chart,相信會有更多收獲。
chart 安裝前的准備
作為准備工作,安裝之前需要先清楚 chart 的使用方法。這些信息通常記錄在 values.yaml 和 README.md 中。
除了下載源文件查看,執行 helm inspect values
可能是更方便的方法。

daweij@master:~/helm/mysql$ helm inspect values stable/mysql ## mysql image version ## ref: https://hub.docker.com/r/library/mysql/tags/ ## image: "mysql" imageTag: "5.7.14" ## Specify password for root user ## ## Default: random 10 character string # mysqlRootPassword: testing ## Create a database user ## # mysqlUser: # mysqlPassword: ## Allow unauthenticated access, uncomment to enable ## # mysqlAllowEmptyPassword: true ## Create a database ## # mysqlDatabase: ## Specify an imagePullPolicy (Required) ## It's recommended to change this to 'Always' if the image tag is 'latest' ## ref: http://kubernetes.io/docs/user-guide/images/#updating-images ## imagePullPolicy: IfNotPresent livenessProbe: initialDelaySeconds: 30 periodSeconds: 10 timeoutSeconds: 5 successThreshold: 1 failureThreshold: 3 readinessProbe: initialDelaySeconds: 5 periodSeconds: 10 timeoutSeconds: 1 successThreshold: 1 failureThreshold: 3 ## Persist data to a persistent volume persistence: enabled: true ## database data Persistent Volume Storage Class ## If defined, storageClassName: <storageClass> ## If set to "-", storageClassName: "", which disables dynamic provisioning ## If undefined (the default) or set to null, no storageClassName spec is ## set, choosing the default provisioner. (gp2 on AWS, standard on ## GKE, AWS & OpenStack) ## # storageClass: "-" accessMode: ReadWriteOnce size: 8Gi ## Configure resource requests and limits ## ref: http://kubernetes.io/docs/user-guide/compute-resources/ ## resources: requests: memory: 256Mi cpu: 100m # Custom mysql configuration files used to override default mysql settings configurationFiles: # mysql.cnf: |- # [mysqld] # skip-name-resolve ## Configure the service ## ref: http://kubernetes.io/docs/user-guide/services/ service: ## Specify a service type ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services---service-types type: ClusterIP port: 3306 # nodePort: 32000
輸出的實際上是 values.yaml 的內容。
閱讀注釋就可以知道 MySQL chart 支持哪些參數,安裝之前需要做哪些准備。
其中有一部分是關於存儲的:

## Persist data to a persistent volume persistence: enabled: true ## database data Persistent Volume Storage Class ## If defined, storageClassName: <storageClass> ## If set to "-", storageClassName: "", which disables dynamic provisioning ## If undefined (the default) or set to null, no storageClassName spec is ## set, choosing the default provisioner. (gp2 on AWS, standard on ## GKE, AWS & OpenStack) ## # storageClass: "-" accessMode: ReadWriteOnce size: 8Gi
chart 定義了一個 PersistentVolumeClaim,申請 8G 的 PersistentVolume。
由於我們的實驗環境不支持動態供給,所以得預先創建好相應的 PV,其配置文件 mysql-pv.yml
內容為:
daweij@master:~/helm$ cat mysql-pv.yml apiVersion: v1 kind: PersistentVolume metadata: name: mysql-pv spec: accessModes: - ReadWriteOnce capacity: storage: 8Gi persistentVolumeReclaimPolicy: Retain nfs: path: /nfsdata/mysql-pv server: 172.28.2.211
創建 PV mysql-pv
:
daweij@master:~/helm$ kubectl apply -f mysql-pv.yml persistentvolume "mysql-pv" created daweij@master:~/helm$ kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE mysql-pv 8Gi RWO Retain Available 5s
接下來就可以安裝 chart 了。
定制化安裝 chart
除了接受 values.yaml 的默認值,我們還可以定制化 chart,比如設置 mysqlRootPassword
。
Helm 有兩種方式傳遞配置參數:
-
指定自己的 values 文件。
通常的做法是首先通過helm inspect values mysql > myvalues.yaml
生成 values 文件,然后設置mysqlRootPassword
,之后執行helm install --values=myvalues.yaml mysql
。 -
通過
--set
直接傳入參數值,比如:
helm install stable/mysql --set mysqlRootPassword=abc123 -n my
mysqlRootPassword
設置為 abc123
。另外,-n
設置 release 為 my
,各類資源的名稱即為my-mysql
。
通過 helm list
和 helm status
可以查看 chart 的最新狀態。

daweij@master:~/helm$ helm install mysql --set mysqlRootPassword=abc123 -n my NAME: my LAST DEPLOYED: Tue Apr 24 11:53:25 2018 NAMESPACE: default STATUS: DEPLOYED RESOURCES: ==> v1/Secret NAME TYPE DATA AGE my-mysql Opaque 2 55s ==> v1/PersistentVolumeClaim NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE my-mysql Bound mysql-pv 8Gi RWO 55s ==> v1/Service NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE my-mysql ClusterIP 10.233.47.112 <none> 3306/TCP 55s ==> v1beta1/Deployment NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE my-mysql 1 1 1 0 55s ==> v1/Pod(related) NAME READY STATUS RESTARTS AGE my-mysql-6d8949f555-kpcwm 0/1 Init:0/1 0 55s NOTES: MySQL can be accessed via port 3306 on the following DNS name from within your cluster: my-mysql.default.svc.cluster.local To get your root password run: MYSQL_ROOT_PASSWORD=$(kubectl get secret --namespace default my-mysql -o jsonpath="{.data.mysql-root-password}" | base64 --decode; echo) To connect to your database: 1. Run an Ubuntu pod that you can use as a client: kubectl run -i --tty ubuntu --image=ubuntu:16.04 --restart=Never -- bash -il 2. Install the mysql client: $ apt-get update && apt-get install mysql-client -y 3. Connect using the mysql cli, then provide your password: $ mysql -h my-mysql -p To connect to your database directly from outside the K8s cluster: MYSQL_HOST=127.0.0.1 MYSQL_PORT=3306 # Execute the following commands to route the connection: export POD_NAME=$(kubectl get pods --namespace default -l "app=my-mysql" -o jsonpath="{.items[0].metadata.name}") kubectl port-forward $POD_NAME 3306:3306 mysql -h ${MYSQL_HOST} -P${MYSQL_PORT} -u root -p${MYSQL_ROOT_PASSWORD} daweij@master:~/helm$ helm list my NAME REVISION UPDATED STATUS CHART NAMESPACE my 1 Tue Apr 24 11:53:25 2018 DEPLOYED mysql-0.3.6 default daweij@master:~/helm$ helm status my LAST DEPLOYED: Tue Apr 24 11:53:25 2018 NAMESPACE: default STATUS: DEPLOYED RESOURCES: ==> v1/Service NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE my-mysql ClusterIP 10.233.47.112 <none> 3306/TCP 1m ==> v1beta1/Deployment NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE my-mysql 1 1 1 0 1m ==> v1/Pod(related) NAME READY STATUS RESTARTS AGE my-mysql-6d8949f555-kpcwm 0/1 Init:0/1 0 1m ==> v1/Secret NAME TYPE DATA AGE my-mysql Opaque 2 1m ==> v1/PersistentVolumeClaim NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE my-mysql Bound mysql-pv 8Gi RWO 1m NOTES: MySQL can be accessed via port 3306 on the following DNS name from within your cluster: my-mysql.default.svc.cluster.local To get your root password run: MYSQL_ROOT_PASSWORD=$(kubectl get secret --namespace default my-mysql -o jsonpath="{.data.mysql-root-password}" | base64 --decode; echo) To connect to your database: 1. Run an Ubuntu pod that you can use as a client: kubectl run -i --tty ubuntu --image=ubuntu:16.04 --restart=Never -- bash -il 2. Install the mysql client: $ apt-get update && apt-get install mysql-client -y 3. Connect using the mysql cli, then provide your password: $ mysql -h my-mysql -p To connect to your database directly from outside the K8s cluster: MYSQL_HOST=127.0.0.1 MYSQL_PORT=3306 # Execute the following commands to route the connection: export POD_NAME=$(kubectl get pods --namespace default -l "app=my-mysql" -o jsonpath="{.items[0].metadata.name}") kubectl port-forward $POD_NAME 3306:3306 mysql -h ${MYSQL_HOST} -P${MYSQL_PORT} -u root -p${MYSQL_ROOT_PASSWORD}
PVC 已經 Bound
,Deployment 也 AVAILABLE
。
升級和回滾 release
release 發布后可以執行 helm upgrade
對其升級,通過 --values
或 --set
應用新的配置。比如將當前的 MySQL 版本升級到 5.7.15:
helm upgrade --set imageTag=5.7.15 my mysql
等待一些時間,升級成功。
helm history
可以查看 release 所有的版本。通過 helm rollback
可以回滾到任何版本。
helm history my helm rollback my 1
回滾成功,MySQL 恢復到 5.7.14。
下一節我們學習如何開發自己的 chart。
開發自己的 chart
Kubernetes 給我們提供了大量官方 chart,不過要部署微服務應用,還是需要開發自己的 chart,下面就來實踐這個主題。
創建 chart
執行 helm create mychart
的命令創建 chart mychart
:
daweij@master:~/helm$ helm create mychart Creating mychart daweij@master:~/helm$ tree mychart/ mychart/ ├── charts ├── Chart.yaml ├── templates │ ├── deployment.yaml │ ├── _helpers.tpl │ ├── ingress.yaml │ ├── NOTES.txt │ └── service.yaml └── values.yaml 2 directories, 7 files daweij@master:~/helm$
Helm 會幫我們創建目錄 mychart
,並生成了各類 chart 文件。這樣我們就可以在此基礎上開發自己的 chart 了。
新建的 chart 默認包含一個 nginx 應用示例,values.yaml 內容如下:

daweij@master:~/helm$ cat mychart/values.yaml # Default values for mychart. # This is a YAML-formatted file. # Declare variables to be passed into your templates. replicaCount: 1 image: repository: nginx tag: stable pullPolicy: IfNotPresent service: type: ClusterIP port: 80 ingress: enabled: false annotations: {} # kubernetes.io/ingress.class: nginx # kubernetes.io/tls-acme: "true" path: / hosts: - chart-example.local tls: [] # - secretName: chart-example-tls # hosts: # - chart-example.local resources: {} # We usually recommend not to specify default resources and to leave this as a conscious # choice for the user. This also increases chances charts run on environments with little # resources, such as Minikube. If you do want to specify resources, uncomment the following # lines, adjust them as necessary, and remove the curly braces after 'resources:'. # limits: # cpu: 100m # memory: 128Mi # requests: # cpu: 100m # memory: 128Mi nodeSelector: {} tolerations: [] affinity: {}
開發時建議大家參考官方 chart 中的模板、values.yaml、Chart.yaml,里面包含了大量最佳實踐和最常用的函數、流控制,這里就不一一展開了。
調試 chart
只要是程序就會有 bug,chart 也不例外。Helm 提供了 debug 的工具:helm lint
和 helm install --dry-run --debug
。
helm lint
會檢測 chart 的語法,報告錯誤以及給出建議。
比如我們故意在 values.yaml 的第 8 行漏掉了一個 :
,
helm lint mychart
會指出這個語法錯誤。
daweij@master:~/helm$ helm lint mychart ==> Linting mychart [INFO] Chart.yaml: icon is recommended [ERROR] values.yaml: unable to parse YAML error converting YAML to JSON: yaml: line 11: could not find expected ':' Error: 1 chart(s) linted, 1 chart(s) failed
mychart
目錄被作為參數傳遞給 helm lint
。錯誤修復后則能通過檢測。
daweij@master:~/helm$ vim mychart/values.yaml daweij@master:~/helm$ helm lint mychart ==> Linting mychart [INFO] Chart.yaml: icon is recommended 1 chart(s) linted, no failures
helm install --dry-run --debug
會模擬安裝 chart,並輸出每個模板生成的 YAML 內容。
helm install --dry-run mychart --debug

daweij@master:~/helm$ helm install --dry-run mychart --debug [debug] Created tunnel using local port: '36539' [debug] SERVER: "127.0.0.1:36539" [debug] Original chart version: "" [debug] CHART PATH: /home/daweij/helm/mychart NAME: ideal-frog REVISION: 1 RELEASED: Tue Apr 24 13:43:52 2018 CHART: mychart-0.1.0 USER-SUPPLIED VALUES: {} COMPUTED VALUES: affinity: {} image: pullPolicy: IfNotPresent repository: nginx tag: stable ingress: annotations: {} enabled: false hosts: - chart-example.local path: / tls: [] nodeSelector: {} replicaCount: 1 resources: {} service: port: 80 type: ClusterIP tolerations: [] HOOKS: MANIFEST: --- # Source: mychart/templates/service.yaml apiVersion: v1 kind: Service metadata: name: ideal-frog-mychart labels: app: mychart chart: mychart-0.1.0 release: ideal-frog heritage: Tiller spec: type: ClusterIP ports: - port: 80 targetPort: http protocol: TCP name: http selector: app: mychart release: ideal-frog --- # Source: mychart/templates/deployment.yaml apiVersion: apps/v1beta2 kind: Deployment metadata: name: ideal-frog-mychart labels: app: mychart chart: mychart-0.1.0 release: ideal-frog heritage: Tiller spec: replicas: 1 selector: matchLabels: app: mychart release: ideal-frog template: metadata: labels: app: mychart release: ideal-frog spec: containers: - name: mychart image: "nginx:stable" imagePullPolicy: IfNotPresent ports: - name: http containerPort: 80 protocol: TCP livenessProbe: httpGet: path: / port: http readinessProbe: httpGet: path: / port: http resources: {} daweij@master:~/helm$
我們可以檢視這些輸出,判斷是否與預期相符。
同樣,mychart
目錄作為參數傳遞給 helm install --dry-run --debug
。
其他常用命令
刪除 helm delete --purge release-name 更新 helm upgrade release-name chart-dest-name
下一節討論如何安裝並將 chart 添加到倉庫。
管理和安裝 chart
安裝 chart
當我們覺得准備就緒,就可以安裝 chart,Helm 支持四種安裝方法:
-
安裝倉庫中的 chart,例如:
helm install stable/nginx
-
通過 tar 包安裝,例如:
helm install ./nginx-1.2.3.tgz
-
通過 chart 本地目錄安裝,例如:
helm install ./nginx
-
通過 URL 安裝,例如:
helm install https://example.com/charts/nginx-1.2.3.tgz
- 用於2,將當前目錄打包為tgz: helm package -d tardest 待壓縮chart1 待壓縮chart2

daweij@master:~/prometheus-operator$ mkdir -p helm/kube-prometheus/charts daweij@master:~/prometheus-operator$ helm package -d helm/kube-prometheus/charts helm/alertmanager helm/grafana helm/prometheus helm/exporter-kube-dns helm/exporter-kube-scheduler helm/exporter-kubelets helm/exporter-node helm/exporter-kube-controller-manager helm/exporter-kube-etcd helm/exporter-kube-state helm/exporter-kubernetes Successfully packaged chart and saved it to: helm/kube-prometheus/charts/alertmanager-0.0.13.tgz Successfully packaged chart and saved it to: helm/kube-prometheus/charts/grafana-0.0.24.tgz Successfully packaged chart and saved it to: helm/kube-prometheus/charts/prometheus-0.0.24.tgz Successfully packaged chart and saved it to: helm/kube-prometheus/charts/exporter-kube-dns-0.1.5.tgz Successfully packaged chart and saved it to: helm/kube-prometheus/charts/exporter-kube-scheduler-0.1.6.tgz Successfully packaged chart and saved it to: helm/kube-prometheus/charts/exporter-kubelets-0.2.7.tgz Successfully packaged chart and saved it to: helm/kube-prometheus/charts/exporter-node-0.2.0.tgz Successfully packaged chart and saved it to: helm/kube-prometheus/charts/exporter-kube-controller-manager-0.1.7.tgz Successfully packaged chart and saved it to: helm/kube-prometheus/charts/exporter-kube-etcd-0.1.8.tgz Successfully packaged chart and saved it to: helm/kube-prometheus/charts/exporter-kube-state-0.1.15.tgz Successfully packaged chart and saved it to: helm/kube-prometheus/charts/exporter-kubernetes-0.1.6.tgz daweij@master:~/prometheus-operator$
這里我們使用本地目錄安裝:

daweij@master:~/helm$ helm install mychart NAME: pondering-nightingale LAST DEPLOYED: Tue Apr 24 13:49:02 2018 NAMESPACE: default STATUS: DEPLOYED RESOURCES: ==> v1beta2/Deployment NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE pondering-nightingale-mychart 1 1 1 0 55s ==> v1/Pod(related) NAME READY STATUS RESTARTS AGE pondering-nightingale-mychart-6bf647878f-dkbss 0/1 Pending 0 55s ==> v1/Service NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE pondering-nightingale-mychart ClusterIP 10.233.53.80 <none> 80/TCP 55s NOTES: 1. Get the application URL by running these commands: export POD_NAME=$(kubectl get pods --namespace default -l "app=mychart,release=pondering-nightingale" -o jsonpath="{.items[0].metadata.name}") echo "Visit http://127.0.0.1:8080 to use your application" kubectl port-forward $POD_NAME 8080:80 daweij@master:~/helm$
當 chart 部署到 Kubernetes 集群,便可以對其進行更為全面的測試。
將 chart 添加到倉庫
chart 通過測試后可以將其添加到倉庫,團隊其他成員就能夠使用。
任何 HTTP Server 都可以用作 chart 倉庫,下面演示在 k8s-node1
172.28.2.211 上搭建倉庫。
-
在
k8s-node1
上啟動一個 httpd 容器。root@node1:~# mkdir /var/www root@node1:~# docker run -d -p 8080:80 -v /var/www/:/usr/local/apache2/htdocs/ httpd 096cc6292f59f3d6c26fbaaf5964b28e018adb4395111b14321a4c5d5a6b388e root@node1:~# curl http://172.28.2.211:8080 <html><body><h1>It works!</h1></body></html>
-
通過
helm package
將mychart
打包。daweij@master:~/helm$ helm package -d ./ mychart Successfully packaged chart and saved it to: mychart-0.1.0.tgz
-
執行
helm repo index
生成倉庫的 index 文件。
helm repo index myrepo/ --url http://172.28.2.211:8080/charts
daweij@master:~/helm$ helm package -d ./ mychart Successfully packaged chart and saved it to: mychart-0.1.0.tgz daweij@master:~/helm$ mkdir myrepo daweij@master:~/helm$ mv mychart-0.1.0.tgz myrepo/ daweij@master:~/helm$ helm repo index myrepo/ --url http://172.28.2.211:8080/charts daweij@master:~/helm$
4.Helm 會掃描 myrepo
目錄中的所有 tgz 包並生成 index.yaml
。--url
指定的是新倉庫的訪問路徑。
新生成的 index.yaml
記錄了當前倉庫中所有 chart 的信息:
daweij@master:~/helm$ cat myrepo/index.yaml apiVersion: v1 entries: mychart: - apiVersion: v1 appVersion: "1.0" created: 2018-04-24T13:55:44.146115111+08:00 description: A Helm chart for Kubernetes digest: fbf433ad49d3623fd1fec2cdec3d65022e472bb30b67463bd0f52c484177632e name: mychart urls: - http://172.28.2.211:8080/charts/mychart-0.1.0.tgz version: 0.1.0 generated: 2018-04-24T13:55:44.14525528+08:00
當前只有 mychart
這一個 chart。
5.將 mychart-0.1.0.tgz
和 index.yaml
上傳到 node1
的 /var/www/charts
目錄。
root@node1:~# mkdir /var/www/charts root@node1:~# scp root@172.28.2.210:/home/daweij/helm/myrepo/* /var/www/charts/ root@172.28.2.210's password: index.yaml 100% 396 0.4KB/s 00:00 mychart-0.1.0.tgz 100% 2562 2.5KB/s 00:00 root@node1:~# ls /var/www/charts/ index.yaml mychart-0.1.0.tgz
6.通過 helm repo add
將新倉庫添加到 Helm。
helm repo add newrepo http://172.28.2.211:8080/charts
daweij@master:~/helm$ helm repo add newrepo http://172.28.2.211:8080/charts "newrepo" has been added to your repositories daweij@master:~/helm$ helm repo list NAME URL stable https://kubernetes-charts.storage.googleapis.com local http://127.0.0.1:8879/charts newrepo http://172.28.2.211:8080/charts daweij@master:~/helm$
7.倉庫命名為 newrepo
,Helm 會從倉庫下載 index.yaml。
現在已經可以 repo search
到 mychart
了。
daweij@master:~/helm$ helm search mychart NAME CHART VERSION APP VERSION DESCRIPTION local/mychart 0.1.0 1.0 A Helm chart for Kubernetes newrepo/mychart 0.1.0 1.0 A Helm chart for Kubernetes
除了 newrepo/mychart
,這里還有一個 local/mychart
。
這是因為在執行第 2 步打包操作的同時,mychart
也被同步到了 local 的倉庫。
已經可以直接從新倉庫安裝 mychart
了。

daweij@master:~/helm$ helm install newrepo/mychart NAME: wandering-squid LAST DEPLOYED: Tue Apr 24 14:26:49 2018 NAMESPACE: default STATUS: DEPLOYED RESOURCES: ==> v1/Service NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE wandering-squid-mychart ClusterIP 10.233.59.173 <none> 80/TCP 55s ==> v1beta2/Deployment NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE wandering-squid-mychart 1 1 1 0 55s ==> v1/Pod(related) NAME READY STATUS RESTARTS AGE wandering-squid-mychart-6bf48c89d6-gcfgz 0/1 ContainerCreating 0 55s NOTES: 1. Get the application URL by running these commands: export POD_NAME=$(kubectl get pods --namespace default -l "app=mychart,release=wandering-squid" -o jsonpath="{.items[0].metadata.name}") echo "Visit http://127.0.0.1:8080 to use your application" kubectl port-forward $POD_NAME 8080:80 daweij@master:~/helm$
如果以后倉庫添加了新的 chart,需要用 helm repo update
更新本地的 index。
daweij@master:~/helm$ helm repo update Hang tight while we grab the latest from your chart repositories... ...Skip local chart repository ...Successfully got an update from the "newrepo" chart repository ...Unable to get an update from the "stable" chart repository (https://kubernetes-charts.storage.googleapis.com): Get https://kubernetes-charts.storage.googleapis.com/index.yaml: dial tcp 172.217.27.144:443: i/o timeout Update Complete. ⎈ Happy Helming!⎈
這個操作相當於 Ubutun 的 apt-get update
。
小結
本章我們學習了 Kubernetes 包管理器 Helm。
Helm 讓我們能夠像 apt 管理 deb 包那樣安裝、部署、升級和刪除容器化應用。
Helm 由客戶端和 Tiller 服務器組成。客戶端負責管理 chart,服務器負責管理 release。
chart 是 Helm 的應用打包格式,它由一組文件和目錄構成。其中最重要的是模板,模板中定義了 Kubernetes 各類資源的配置信息,Helm 在部署時通過 values.yaml 實例化模板。
Helm 允許用戶開發自己的 chart,並為用戶提供了調試工具。
用戶可以搭建自己的 chart 倉庫,在團隊中共享 chart。
Helm 幫助用戶在 Kubernetes 上高效地運行和管理微服務架構應用,Helm 非常重要。
綜上,常用的helm命令