使用 Helm 批量部署应用

2020-06-18 16:08:34 浏览数 (1)

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

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

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

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

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

写在前面 - 关于腾讯云 TKE 和 helm

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

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

代码语言:txt复制
alias helm2="helm --kubeconfig ~/.kube/config2"

创建一个 helm chart

使用命令创建一个chart

代码语言:txt复制
helm create chart-demo

创建出来的目录结构

代码语言:txt复制
./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 下的所有文件。用自己熟悉的方式,先创建部署,目录结构如下:

代码语言:txt复制
./chart-demo
├── Chart.yaml
├── templates
│   └── deploy.yaml
└── values.yaml

deploy.yaml

代码语言:txt复制
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

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

代码语言:txt复制
helm install --debug --dry-run xyz-product .
代码语言:txt复制
---
# 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 一下:

代码语言:txt复制
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

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

代码语言:txt复制
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 仓库

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

代码语言:txt复制
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 仓库:

代码语言:txt复制
helm search repo charts

便有了你的图样。

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

代码语言:txt复制
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制品库

0 人点赞