腾讯云海外购

使用 Helm 批量部署应用

有了 kubectl + yaml , 还要 helm 做什么呢?

在微服务场景中,使用同一模式开发的应用会变的很多,我们会使用相同的 docker 基础镜像进行应用打包。但对于部署场景,我们需要写很多类似的 yaml 文件,由此,我们希望将不同之处使用变量抽取出来,并与通用模板进行整合。

目前使用 kubectl + yaml 的这种方式是无法完成这一功能的。

我们可以使用 helm 来批量部署同类应用,并彻底将部署代码从程序中解耦。在同一类部署中,不同的值是:应用名称,应用当前版本,镜像地址,我们将这些参数提取出来,从命令行中指定进去。

下面我们来展示这一过程。

写在前面 - 关于 TKE 和 helm

的 TKE 已经安装了 helm 的 tiller 了,所以在本地使用 helm 的时候,只需要使用 helm 的命令行工具即可。 helm 默认会操作 ~/.kube/config 对应的集群。

如果要操作不同的集群,我习惯加上 --kubeconfig=xxx 来操作,建议将他做成一个别名放在你的 .bashrc 或 .zshrc 中,如:

alias helm2="helm --kubeconfig ~/.kube/config2"

创建一个 helm chart

使用命令创建一个chart

helm create chart-demo

创建出来的目录结构

./chart-demo ├── Chart.yaml ├── charts ├── templates │   ├── NOTES.txt │   ├── _helpers.tpl │   ├── deployment.yaml │   ├── hpa.yaml │   ├── ingress.yaml │   ├── service.yaml │   ├── serviceaccount.yaml │   └── tests │       └── test-connection.yaml └── values.yaml

只需将共用的基础部署脚本写在 templates 里面的文件中,把可变量写到 values.yaml 中。

开始写一个简单 Chart

使用 helm create 出来的模板文件,看起来很复杂,所以,咱们不用他的那些模板,从 kubectl 的 yaml 开始。删掉 templates 下的所有文件。用自己熟悉的方式,先创建部署,目录结构如下:

./chart-demo ├── Chart.yaml ├── templates │   └── deploy.yaml └── values.yaml

deploy.yaml

apiVersion: apps/v1beta2 kind: Deployment metadata:   name: {{ .Release.Name }}   labels:     app: {{ .Release.Name }} spec:   replicas: 2   selector:     matchLabels:       app: {{ .Release.Name }}   strategy:     type: RollingUpdate     rollingUpdate:       maxSurge: 1       maxUnavailable: 0   template:     metadata:       labels:         app: {{ .Release.Name }}     spec:       containers:         - name:  {{ .Release.Name }}           image: ccr.ccs.tencentyun.com/axlyzhang-images/xyzdemo-product:v1.10           env:             - name: PATH               value: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin             - name: LANG               value: C.UTF-8             - name: JAVA_HOME               value: /usr/lib/jvm/java-8-openjdk-amd64             - name: JAVA_VERSION               value: 8u111           resources:             limits:               cpu: 500m               memory: 1Gi             requests:               cpu: 250m               memory: 256Mi

假装安装一下,看看输出的结果:

helm install --debug --dry-run xyz-product .
--- # Source: chart-demo/templates/deploy.yaml apiVersion: apps/v1beta2 kind: Deployment metadata:   name: xyz-product   labels:     app: xyz-product spec:   replicas: 2   selector:     matchLabels:       app: xyz-product   strategy:     type: RollingUpdate     rollingUpdate:       maxSurge: 1       maxUnavailable: 0   template:     metadata:       labels:         app: xyz-product     spec:       containers:         - name:  xyz-product           image: ccr.ccs.tencentyun.com/axlyzhang-images/xyzdemo-product:v1.10           env:             - name: PATH               value: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin             - name: LANG               value: C.UTF-8             - name: JAVA_HOME               value: /usr/lib/jvm/java-8-openjdk-amd64             - name: JAVA_VERSION               value: 8u111           resources:             limits:               cpu: 500m               memory: 1Gi             requests:               cpu: 250m               memory: 256Mi

上面就是合成结果,我们已经放入了一个内置变量 {{ .Release.Name }}

很简单吧。接下来,就是要把更多的变量(appName, version)放进去。

Values

helm 支持变量,函数,模板和一些流控编程。现在我们不使用 Release 这个内置变量了,我们使用 Values 变量。Values 变量一般有 2 个来源,一个是 yaml 文件,一个是命令行参数。在 Jenkins 自动化 部署的场景,我们更希望通过命令行来把参数指定进去。

我们改写 deploy.yaml 一下:

apiVersion: apps/v1beta2 kind: Deployment metadata:   name: {{ required "应用名称 appName 必须指定" .Values.appName }}   namespace: {{ default "default" .Values.ns}}   labels:     app: {{ .Values.appName }}     version: {{  required "版本号 version 必须指定" .Values.version }} spec:   replicas: {{ default 2 .Values.replicas }}   selector:     matchLabels:       app: {{ .Values.appName }}   strategy:     type: RollingUpdate     rollingUpdate:       maxSurge: 1       maxUnavailable: 0   template:     metadata:       labels:         app: {{ .Values.appName }}     spec:       containers:         - name: {{ .Values.appName }}           image: ccr.ccs.tencentyun.com/axlyzhang-images/{{ .Values.appName }}:{{ .Values.version }}           env:             - name: PATH               value: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin             - name: LANG               value: C.UTF-8             - name: JAVA_HOME               value: /usr/lib/jvm/java-8-openjdk-amd64             - name: JAVA_VERSION               value: 8u111           resources:             limits:               cpu: 500m               memory: 1Gi             requests:               cpu: 250m               memory: 256Mi

我们通过命令行,将参数指定进去,如下:

helm install --debug --dry-run springboot-app . --set appName=xyzdemo-product --set version=v1.10

看到结果,已经按照我们想要的结果输出了。去掉 --debug --dry-run 就可以直接执行到 K8S 环境了。

上传到 Chart “私服”

有多种方法可以搭建自己的私服,如:ChartMuseum,  Github Pages, JFrog Artifactory 等。目前使用 coding.net 的制品库已经可以完美支持 helm charts 。只需要创建仓库即可。

开通 coding helm 仓库

在本地设置你的仓库(下面这些命令在 coding 中会自动帮你生成):

helm plugin install https://e.coding.net/coding-public/helm-push helm repo add --username <userName> --password <pwd> charts "https://your-repo-url"

推送步骤:

  • 打包: helm package . 
  • 推送 helm push chart-demo-0.1.0.tgz charts 

现在搜一下 coding 的 helm 仓库:

helm search repo charts

便有了你的图样。

现在远程的 repo 已经设置到本地了。可以使用远程图样,直接部署同环境的应用了。 

helm install microservice1 charts/chart-demo --set appName=microservice1 --set version=1.0 helm install microservice2 charts/chart-demo --set appName=microservice2 --set version=1.1 ...

在 Jenkins 的脚本中,无法多次 install 同一个,可以使用 helm upgrade --install

More

到这里,我们只是应用了 helm 很少的功能,便实现了应用的批量部署。

其实,helm 的功能很强大,他的模板系统可以支持更多的变量,模板,流控,函数等,并可以支持很多部署操作命令,这些可以去他的官网研究一下。

总结

helm 可以理解为一套 YAML 的模板系统,按照 helm 特定的模板语法编写 yaml,他就可以“智能地”将这些模板合成为正确的 Yaml 部署文件,并可以通过简单的命令部署到 K8S 环境中。

当然,Helm 也可以是你的应用的“包管理系统”。


参考:

HELM 官网

CODING制品库