首页 > 技术文章 > helm自定义chart

tcy1 2021-11-05 17:00 原文

helm

helm介绍

**官方中文站点:https://v3.helm.sh/zh/docs/

官方地址:https://helm.sh/

helm官方chart站点:https://hub.kubeapps.com/

为什么要使用helm:

在服务部署中通常需要多个yaml文件,deployment,service组成,但通常在微服务架构中,工作中需要用的yaml文件存在多个,不便于管理,因此引出helm。

使用流程:

chart--->通过 values.yaml 这个文件赋值-->生成 release 实例

helm组件

helm:命令行客户端工具,主要用于 Kubernetes 应用中的 chart 的创建、打包、发布和管理。

Chart:helm 程序包,一系列用于描述 k8s 资源相关文件的集合,比方说我们部署 nginx,需要deployment 的 yaml,需要 service 的 yaml,这两个清单文件就是一个 helm 程序包,在 k8s 中把这些yaml 清单文件叫做 chart 图表

vlues.yaml: 文件为模板中的文件赋值,可以实现自定义安装,如果是 chart 开发者需要自定义模板,如果是 chart 使用者只需要修改 values.yaml 即可

repository: 存放chart图表的仓库,提供部署k8s应用程序需要的那些yaml清单文件。

release: 基于chart的部署实体,一个chart被helm运行后将会生成对应的一个release,将在k8s中创建出真实的资源对象。

chart.yaml: 存放chart的相关信息,作者,包对应的github存放地址。

template:主体文件,具备定义yaml文件

​ helpers.tpl: 存放能够复用的模板

​ notes.txt: 说明文件

总结:

helm 把 kubernetes 资源打包到一个 chart 中,制作并完成各个 chart 和 chart 本身依赖关系并利用
chart 仓库实现对外分发,而 helm 还可通过 values.yaml 文件完成可配置的发布,如果 chart 版本更新
了,helm 自动支持滚更更新机制,还可以一键回滚,但是不是适合在生产环境使用,除非具有定义自制
chart 的能力。

helm版本

helm v3和v2的比对:

v2

  1. 部署需要安装tiller

v3:

  1. 可以将chart推送至docker镜像仓库
  2. Helm 服务端 Tiller 被删除
  3. Release 名称可以在不同命名空间重用
  4. 使用 JSONSchema 验证 chartvalues

  • helm v3部署
# 各版本对照表
https://helm.sh/zh/docs/topics/version_skew/

1.下载地址

https://github.com/helm/helm/releases

找 Linux amd64 这个 checksum 的,下载之后传到机器即可,目前 Helm 最新稳定版本是 3.6.3,下载后,解压即可。

2.解压使用

[root@master1 opt]# tar xf helm-v3.7.1-linux-amd64.tar.gz
[root@master1 helm]# mv helm /usr/bin/

国内仓库地址

阿里云仓库(https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts)
官方仓库(https://hub.kubeapps.com/charts/incubator)官方 chart 仓库,国内可能无法访问。
微软仓库(http://mirror.azure.cn/kubernetes/charts/)这个仓库推荐,基本上官网有的 chart这里都有,国内可能无法访问。

# 添加阿里云仓库
[root@xianchaomaster1 ~]# helm repo add aliyun https://kubernetes.oss-cn-
hangzhou.aliyuncs.com/charts

# 添加bitnami的chart仓库
[root@xianchaomaster1 ~]# helm repo add bitnami https://charts.bitnami.com/bitnami

# 更新 chart 仓库
[root@xianchaomaster1 ~]# helm repo update

# 查看配置的 chart 仓库有哪些
[root@xianchaomaster1 ~]# helm repo list
NAME URL
aliyun https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts
bitnami https://charts.bitnami.com/bitnami

# 删除 chart 仓库地址
[root@xianchaomaster1 ~]# helm repo remove aliyun
"aliyun" has been removed from your repositories

# 从指定chart仓库搜索chart
[root@xianchaomaster1 ~]# helm search repo aliyun

helm基本使用

案例①: memcached部署

  1. 查看阿里云chart仓库中的memcached
[root@master1 helm]# helm show chart aliyun/memcached
apiVersion: v1
description: Free & open source, high-performance, distributed memory object caching
  system.
home: http://memcached.org/
icon: https://upload.wikimedia.org/wikipedia/en/thumb/2/27/Memcached.svg/1024px-Memcached.svg.png
keywords:
- memcached
- cache
maintainers:
- email: gtaylor@gc-taylor.com
  name: Greg Taylor
name: memcached
sources:
- https://github.com/docker-library/memcached
version: 2.0.1

2.下载chart包到本地

[root@master1 helm]# helm pull aliyun/memcached
[root@master1 helm]# tar xf memcached-2.0.1.tgz
[root@master1 memcached]# ll
total 12
-rwxr-xr-x 1 root root  415 Jan  1  1970 Chart.yaml
-rwxr-xr-x 1 root root 2804 Jan  1  1970 README.md
drwxr-xr-x 2 root root   94 Nov  5 14:02 templates
-rwxr-xr-x 1 root root  882 Jan  1  1970 values.yaml
# chart.yaml:
chart的基本信息,包括版本名字之类
# templates: 
存放k8s的部署资源模板,通过渲染变量得到部署文件
#values.yaml: 
存放全局变量,templates下的文件可以调用

[root@master1 memcached]# cd templates/
[root@master1 templates]# ll
-rwxr-xr-x 1 root root  536 Jan  1  1970 _helpers.tpl
-rwxr-xr-x 1 root root  570 Jan  1  1970 NOTES.txt
-rwxr-xr-x 1 root root  373 Jan  1  1970 pdb.yaml
-rwxr-xr-x 1 root root 2305 Jan  1  1970 statefulset.yaml
-rwxr-xr-x 1 root root  420 Jan  1  1970 svc.yaml
# _helpers.tpl 	
存放能够复用的模板
# NOTES.txt
为用户提供一个关于chart部署后的使用说明文件

3.helm部署memcached服务

`安装memcached服务`
[root@master1 templates]# docker load -i memcache_1_4_36.tar.gz
[root@master1 memcached]# cat templates/statefulset.yaml
# 原本的v1beta1改为v1
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: {{ template "memcached.fullname" . }}
  labels:
    app: {{ template "memcached.fullname" . }}
    chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
    release: "{{ .Release.Name }}"
    heritage: "{{ .Release.Service }}"
spec:
  selector:
    matchLabels:
      app: {{ template "memcached.fullname" . }}
      chart: "{{ .Chart.Name }}-{{ .Chart.Versioin }}"
      release: "{{ .Release.Name }}"
      heritage: "{{ .Release.Service }}"
  serviceName: {{ template "memcached.fullname" . }}
  replicas: {{ .Values.replicaCount }}
  template:
    metadata:
      labels:
        app: {{ template "memcached.fullname" . }}
        chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
        release: "{{ .Release.Name }}"
        heritage: "{{ .Release.Service }}"
    spec:
  # 关于pod亲和性删除
      containers:
      - name: {{ template "memcached.fullname" . }}
        image: {{ .Values.image }}
        imagePullPolicy: {{ default "" .Values.imagePullPolicy | quote }}
        command:
        - memcached
        - -m {{ .Values.memcached.maxItemMemory  }}
        {{- if .Values.memcached.extendedOptions }}
        - -o
        - {{ .Values.memcached.extendedOptions }}
        {{- end }}
        {{- if .Values.memcached.verbosity }}
        - -{{ .Values.memcached.verbosity }}
        {{- end }}
        ports:
        - name: memcache
          containerPort: 11211
        livenessProbe:
          tcpSocket:
            port: memcache
          initialDelaySeconds: 30
          timeoutSeconds: 5
        readinessProbe:
          tcpSocket:
            port: memcache
          initialDelaySeconds: 5
          timeoutSeconds: 1
        resources:
{{ toYaml .Values.resources | indent 10 }}

# 对chart包安装成release
[root@master1 memcached]# helm install memcache ./
NAME: memcache
LAST DEPLOYED: Fri Nov  5 14:39:35 2021
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
Memcached can be accessed via port 11211 on the following DNS name from within your cluster:
memcache-memcached.default.svc.cluster.local

If you'd like to test your instance, forward the port locally:

  export POD_NAME=$(kubectl get pods --namespace default -l "app=memcache-memcached" -o jsonpath="{.items[0].metadata.name}")
  kubectl port-forward $POD_NAME 11211

In another tab, attempt to set a key:

  $ echo -e 'set mykey 0 60 5\r\nhello\r' | nc localhost 11211

You should see:

  STORED
  
# 验证memcached是否部署成功
[root@master1 memcached]# kubectl get pods
NAME                             READY   STATUS     RESTARTS   AGE
memcache-memcached-0             2/2     Running    0          2m24s
memcache-memcached-1             2/2     Running    0          2m11s
memcache-memcached-2             2/2     Running    0          2m

4.测试memcached服务是否正常

[root@master1 memcached]# yum install -y nc

# 测试mamecached服务是否正常:
[root@master1 memcached]# export POD_NAME=$(kubectl get pods --namespace default -l "app=memcache-memcached" -o jsonpath="{.items[0].metadata.name}")You have mail in /var/spool/mail/root
[root@master1 memcached]# kubectl port-forward $POD_NAME 11211

# 打开另外一个终端,测试
[root@master1 ~]# echo -e 'set mykey 0 60 5\r\nhello\r' | nc localhost 11211
STORED

5.删除release

[root@master1 ~]# helm delete memcache

# 删除release会把release下对应的资源也删除
[root@master1 ~]# kubectl get pods
NAME                             READY   STATUS     RESTARTS   AGE

案例②: 自定义chart模板

创建模板

[root@master1 myapp]# helm create myapp
[root@master1 opt]# cd myapp/
./
├── charts #用于存放所依赖的子chart
├── Chart.yaml # 描述这个 Chart 的相关信息、包括名字、描述信息、版本等
├── templates #模板目录,保留创建 k8s 的资源清单文件
│ ├── deployment.yaml #deployment 资源的 go 模板文件
│ ├── _helpers.tpl    # 模板助手文件,定义的值可在模板中使用
│ ├── hpa.yaml #水平 pod 自动扩缩容 go 模板文件
│ ├── ingress.yaml #七层代理 go 模板文件
│ ├── NOTES.txt
│ ├── serviceaccount.yaml
│ ├── service.yaml #service 的 go 模板文件
│ └── tests
│ └── test-connection.yaml
└── values.yaml #模板的值文件,这些值会在安装时应用到 GO 模板生成部署文件

chart.yaml编写规则

[root@master1 myapp]# cat Chart.yaml 
apiVersion: v2
name: myapp
description: A Helm chart for Kubernetes
type: application
version: 0.0.1
appVersion: "latest"
maintainer:
- name: tcy
  wechat: tcy@123.com
appVersion: "1.16.0"

# Chart.yaml
主要用来描述对应chart的相关属性信息,其中apiVersion字段用于描述对应chart使用额api的版本
# name
chart的名称
# description 
字段用于描述对应 chart 的说明简介
# type 
字段用户描述对应 chart 是应用程序还是库文件,应用程序类型chart,可以运行一个release,但库类型的chart不能运行为release,只能被application类型的chart所依赖
# appVersion
用于描述对应chart内部程序的版本信息

deployment.yaml编写规则

[root@master1 myapp]# cat templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ include "myapp.fullname" . }}
  labels:
    {{- include "myapp.labels" . | nindent 4 }}
spec:
  {{- if not .Values.autoscaling.enabled }}
  replicas: {{ .Values.replicaCount }}
  {{- end }}
  selector:
    matchLabels:
      {{- include "myapp.selectorLabels" . | nindent 6 }}
  template:
    metadata:
      {{- with .Values.podAnnotations }}
      annotations:
        {{- toYaml . | nindent 8 }}
      {{- end }}
      labels:
        {{- include "myapp.selectorLabels" . | nindent 8 }}
    spec:
      {{- with .Values.imagePullSecrets }}
      imagePullSecrets:
        {{- toYaml . | nindent 8 }}
      {{- end }}
      serviceAccountName: {{ include "myapp.serviceAccountName" . }}
      securityContext:
        {{- toYaml .Values.podSecurityContext | nindent 8 }}
      containers:
        - name: {{ .Chart.Name }}
          securityContext:
            {{- toYaml .Values.securityContext | nindent 12 }}
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
          imagePullPolicy: {{ .Values.image.pullPolicy }}
          ports:
            - name: http
              containerPort: 80
              protocol: TCP
          livenessProbe:
            httpGet:
              path: /
              port: http
          readinessProbe:
            httpGet:
              path: /
              port: http
          resources:
            {{- toYaml .Values.resources | nindent 12 }}
      {{- with .Values.nodeSelector }}
      nodeSelector:
        {{- toYaml . | nindent 8 }}
      {{- end }}
      {{- with .Values.affinity }}
      affinity:
        {{- toYaml . | nindent 8 }}
      {{- end }}
      {{- with .Values.tolerations }}
      tolerations:
        {{- toYaml . | nindent 8 }}
      {{- end }}
   
# 解释
该部署清单模板文件,主要用 go 模板语言来写的,
{{ include "myapp.fullname" . }}:
示取 myapp 的全名;

{{ .Values.image.repository }}:
这段代码表示读取当前目录下的 values 文件中的image.repository 字段的值;

{{ .Values.image.tag | default .Chart.AppVersion }}:
表示对于 values文件中 image.tag 的值或者读取 default.chart 文件中的 AppVersion 字段的值;简单讲 go 模板就是应用对应 go 模板语法来定义关属性的的值;一般都是从 values.yaml 文件中加载对应字段的值作为模板文件
相关属性的值。

nindent 4:表示首行缩进 4 个字母
TRUNC(NUMBER)表示截断数字

values.yaml

[root@master1 myapp]# cat values.yaml 
replicaCount: 2
image:
  repository: nginx
  pullPolicy: IfNotPresent
  tag: ""
imagePullSecrets: []
nameOverride: ""
fullnameOverride: ""
serviceAccount:
  create: true
  annotations: {}
  name: ""
podAnnotations: {}
podSecurityContext: {}
securityContext: {}
service:
  type: ClusterIP
  port: 80
ingress:
  enabled: false
  className: ""
  annotations: {}
  hosts:
    - host: chart-example.local
      paths:
        - path: /
          pathType: ImplementationSpecific
  tls: []
resources: {}
autoscaling:
  enabled: false
  minReplicas: 1
  maxReplicas: 100
  targetCPUUtilizationPercentage: 80
nodeSelector: {}
tolerations: []
affinity: {}


解释:比如我们要引用 values.yaml 文件中的 image 字段下的 tag 字段的值,我们可以在模板文件中写成
{{ .Values.image.tag }};如果在命令行使用--set 选项来应用我们可以写成 image.tag;修改对应的
值可以直接编辑对应 values.yaml 文件中对应字段的值,也可以直接使用--set 指定对应字段的对应值即
可;默认情况在命令行使用--set 选项给出的值,都会直接被替换,没有给定的值,默认还是使用
values.yaml 文件中给定的默认值;

release部署

# 服务部署
[root@master1 myapp]# helm install myapp .

# 根据提示验证
[root@master1 myapp]# kubectl get pods
NAME                             READY   STATUS     RESTARTS   AGE
myapp-566d9f58b5-4rz2f           2/2     Running    0          91s

命令行版本升级

# 1.当前clusterIP修改为nodeport类型
[root@master1 myapp]# kubectl get svc
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
myapp        ClusterIP   10.108.254.12    <none>        80/TCP     4m8s

# 2.更换类型为nodeport
[root@master1 myapp]# helm upgrade --set service.type="NodePort" myapp .
Release "myapp" has been upgraded. Happy Helming!
NAME: myapp
LAST DEPLOYED: Fri Nov  5 15:58:44 2021
NAMESPACE: default
STATUS: deployed
REVISION: 2
NOTES:
1. Get the application URL by running these commands:
  export NODE_PORT=$(kubectl get --namespace default -o jsonpath="{.spec.ports[0].nodePort}" services myapp)
  export NODE_IP=$(kubectl get nodes --namespace default -o jsonpath="{.items[0].status.addresses[0].address}")
  echo http://$NODE_IP:$NODE_PORT
You have mail in /var/spool/mail/root

# 3.查看更改后的类型
[root@master1 myapp]# kubectl get svc
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
myapp        NodePort    10.108.254.12    <none>        80:32185/TCP   6m10s

回滚release

# 1.查看当前历史版本
[root@master1 myapp]# helm history myapp
REVISION	UPDATED                 	STATUS    	CHART      	APP VERSION	DESCRIPTION     
1       	Fri Nov  5 15:52:39 2021	superseded	myapp-0.0.1	1.16.0     	Install complete
2       	Fri Nov  5 15:58:44 2021	deployed  	myapp-0.0.1	1.16.0     	Upgrade complete

# 2.把myapp回滚到版本1(切换到clusterIP模式)
[root@master1 templates]# helm rollback myapp 1
[root@master1 myapp]# kubectl get svc
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
myapp        ClusterIP   10.108.254.12    <none>        80/TCP     4m8s

chart打包

[root@master1 myapp]# helm package /opt/myapp/
Successfully packaged chart and saved it to: /opt/myapp/myapp-0.0.1.tgz

常用命令

# 检查values语法格式
[root@master1 myapp]# helm lint /opt/myapp

# upgrade升级release
helm upgrade

# 回滚release版本
helmm roollback

# 实例创建
helm install

# 卸载release
helm uninstall

# 查看历史版本
helm history

# 查看chart的详细信息
helm inspect

# 下载chart
helm pull

# 把chart打包
helm package

推荐阅读