Helm介绍

  • Helm是kubernetes的包管理工具,相当于linux环境下的yum/apt-get命令。
  • Helm可以解决的问题:运维人员写好资源文件模板,交给开发人员填写参数即可
  • Helm中的一些概念:
  • helm:命令行客户端工具,主要用于Kubernetes应用中的chart的创建、打包、发布和管理。
  • Chart:helm程序包,一系列用于描述k8s资源相关文件的集合,比方说我们部署nginx,需要deployment、svc的yaml,这两个清单文件就是一个helm程序包,在k8s中把这些yaml清单文件叫做chart图表。
  • 功能:
  • 资源管理:helm chart预定义yaml文件,描述各个组件的配置和模板
  • 版本控制:支持一键回滚到先前的版本
  • 依赖管理:声明依赖关系,自动解析并安装这些依赖
  • 模板化:charts可以受用go模板语言,动态生成资源文件

官网地址

教程文章

Helm v3版本变化

  • 2019年11月13日,Helm团队发布Helm v3的第一个稳定版本。
  • 该版本主要变化是架构变化:
  • Helm服务端Tiller被删除(v2版本中,需要装一个Tiller服务端作为通信桥梁才能与k8s交互。v3版不需要了。)

安装helm v3.12.3

下载安装包

Linux安装

# 对于k8s 1.23版本,小于等于3.11.x版本的helm是支持的
wget https://get.helm.sh/helm-v3.16.2-linux-amd64.tar.gz 
tar zxvf helm-v3.16.2-linux-amd64.tar.gz
cp linux-amd64/helm /bin/  #/bin/是默认的环境变量路径之一,所以移动后你可以在任何位置运行这个二进制文件。
# 查看helm版本
helm version

Windows安装-基于scoop

scoop

Scoop是一款适用于Windows平台的命令行软件(包)管理工具,这里是Github介绍页。简单来说,就是可以通过命令行工具(PowerShell、CMD等)实现软件(包)的安装管理等需求,通过简单的一行代码实现软件的下载、安装、卸载、更新等操作

先安装scoop:Scoop

Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
# 更改默认安装目录
$env:SCOOP='D:\0Software\scoop'
[Environment]::SetEnvironmentVariable('SCOOP', $env:SCOOP, 'User')
# 安装
Invoke-Expression (New-Object System.Net.WebClient).DownloadString('https://get.scoop.sh')

设置scoop代理:

  • 方法1:scoop config proxy 127.0.0.1:7078 (根据实际代理端口修改)
  • 方法2:修改配置文件:C:\Users\username\.config\scoop\config.json,添加“proxy”: “127.0.0.1:7078”

基本使用:

在实际使用过程中,我们可以先通过search命令查询一下是否有相应软件,软件名称是否正确,然后通过install命令完成软件的安装。另外,有两个必备的软件需要安装——git和7zip,建议完成Scoop安装后先执行以下命令:scoop install git 7zip(Scoop支持多个软件同时依次安装),虽然后续操作中未安装这两个软件时也会提醒用户安装就是了。

  • search——搜索仓库中是否有相应软件。
  • install——安装软件。
  • uninstall——卸载软件。
  • update——更新软件。可通过scoop update *更新所有已安装软件,或通过scoop update更新所有软件仓库资料及Scoop自身而不更新软件。
  • hold——锁定软件阻止其更新。
  • info——查询软件简要信息。
  • home——打开浏览器进入软件官网。

软件仓库:

软件仓库是Scoop软件管理的重要基础,通过json文件记录仓库中每一个软件的信息,从而实现软件的管理等便捷命令行操作,并由仓库管理员(其实开源项目都是大家用爱发电)负责软件信息的更新。

前面提到,默认安装Scoop后仅有main仓库,其中主要是面向程序员的工具,对于一般用户而言并不是那么实用。好在Scoop本身考虑到了这一点,添加了面向一般用户的软件仓库extras,其中收录大量好用的小软件,足够日常的使用。

Scoop添加软件仓库的命令是scoop bucket add bucketname (+ url可选)。如添加extras的命令是scoop bucket add extras,执行此命令后会在scoop文件夹中的buckets子文件夹中添加extras文件夹。

除了官方的软件仓库,Scoop也支持用户自建仓库并共享,于是又有很多大佬提供了许多好用的软件仓库。这里强推dorado仓库,里面有许多适合中国用户的软件,或者你有兴趣可以去看看仓库作者关于Scoop更多技术方面的探讨。添加dorado仓库的命令如下:scoop bucket add dorado https://github.com/chawyehsu/dorado

helm

一行命令安装:scoop install helm

helm仓库类型

ChartMuseum

  • 访问方式:HTTP/HTTPS
  • 命令:helm repo add添加仓库,helm install安装应用

OCI

  • 访问方式:OCI规范(helm 3.8之后加进来的,相当于用镜像仓库存储helm chart)

  • helm registry去登录仓库,登录完用helm pull可以直接拉chart包,或者helm install安装

helm pull oci://registry-1.docker.io/bitnamicharts/schema-registry

官方仓库:https://artifacthub.io

helm基本使用

添加chart仓库

  • 配置国内存放chart仓库的地址:

  • 阿里云仓库(https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts)

  • 官方仓库(https://hub.kubeapps.com/charts/incubator)官方chart仓库,国内可能无法访问。

  • 微软仓库(http://mirror.azure.cn/kubernetes/charts/)这个仓库推荐,基本上官网有的chart这里都有。

#添加阿里云chart仓库,aliyun参数就是要加的仓库所起的别名。根据自己的需要来命名,在你的 Helm 仓库列表中是唯一的就可以。
helm repo add aliyun https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts
#添加bitnami的chart仓库
helm repo add bitnami https://charts.bitnami.com/bitnami
#更新chart仓库。更新 Helm chart 仓库的索引。这个索引包含了 Helm chart 仓库中所有包的信息。当你添加新的仓库或者已有的仓库中有新的包发布时,你需要运行这个命令来更新本地的索引,以便 Helm 能够获取到最新的包信息。
helm repo update
#查看配置的chart仓库有哪些
helm repo list
#删除chart仓库地址
helm repo remove aliyun
#从指定仓库搜索chart
helm search repo aliyun
  • chart仓库保存位置

如果需要转移到另一台机器,复制这个文件即可

cat /root/.config/helm/repositories.yaml 

搜索和下载chart

  • 查看阿里云chart仓库中的memcached
helm search repo aliyun | grep memcached
helm search repo aliyun/memcached -l # 查看chart所有版本
  • 查看chart信息
helm show chart aliyun/memcached
  • 下载chart包到本地
helm pull aliyun/memcached
tar zxvf memcached-2.0.1.tgz
  • 一键下载helm chart并解压
helm fetch stable/mysql --version 0.2.8 --untar

部署chart

# 指定chart: 
helm install stable/mariadb
# 指定打包的chart: 
helm install ./nginx-1.2.3.tgz
# 指定打包目录: 
helm install ./nginx
# 当前已经在chart目录里面了,直接在当前目录部署helm chart
helm install .
# 指定chart包URL: 
helm install https://example.com/charts/nginx-1.2.3.tgz

release管理

# 查看release发布状态
helm list
# 查看release提示信息
helm status memcached
# 查看release历史版本
helm history memcached
# 查看修改了哪些values(仅在使用了--set设置values的情况下才会显示)
helm get values memcached
# 回滚到指定版本
helm rollback memcached 3
# 删除release,会把release对应的资源全部删除
helm uninstall memcached

helm管理crds

不像大部分的Kubernetes对象,CRD是全局安装的。因此Helm管理CRD时会采取非常谨慎的方式。 CRD受到以下限制:

  • CRD从不重新安装。如果Helm确定crds/目录中的CRD已经存在(忽略版本),Helm不会安装或升级。
  • CRD从不会在升级或回滚时安装。Helm只会在安装时创建CRD。
  • CRD从不会被删除。自动删除CRD会删除集群中所有命名空间中的所有CRD内容。因此Helm不会删除CRD。

把k8s资源加入helm管理

  • 某项资源是手动创建出来的,现在需要加到某个helm release里面,变成helm去管理,需要给这个资源加上label和annotations:
  • label: "app.kubernetes.io/managed-by"="Helm"
  • annotation: "meta.helm.sh/release-name"="xxxx" "meta.helm.sh/release-namespace"="xxxx"
  • 命令行操作:
kubectl label certificate app01 "app.kubernetes.io/managed-by"="Helm"
kubectl annotate certificate app01 "meta.helm.sh/release-name"="xxx" "meta.helm.sh/release-namespace"="xxx"
  • 脚本批量操作,以更新crd为例:
kubectl get crd --no-headers -o custom-columns=":metadata.name" | grep kyverno | xargs -I {} kubectl annotate crd {} meta.helm.sh/release-name=kyverno
kubectl get crd --no-headers -o custom-columns=":metadata.name" | grep kyverno | xargs -I {} kubectl annotate crd {} meta.helm.sh/release-namespace=kyverno
kubectl get crd --no-headers -o custom-columns=":metadata.name" | grep kyverno | xargs -I {} kubectl label crd {} app.kubernetes.io/managed-by=Helm

Helm常用命令演示

helm调试命令

helm template

  • 如果想根据Chart导出yaml,可以使用template字段,一键导出所有部署的yaml文件
helm template mamcached . --output-dir yaml # 导出所有
helm template cert-manager jetstack/cert-manager -n cert-manager -f values.yaml > cert-manager.yaml # 导出单个

helm diff

#比较升级会带来哪些变化
helm diff upgrade <release name> -n <namespace> <source-chart-location> --version $VERSION -f values.yaml --set xxx=$xxx
#比较两个chart版本的变化
helm diff revision nginx-chart 1 2

helm lint

  • 用来检查chart格式是否有问题
helm lint mysql
helm lint /root/myapp/

==> Linting /root/myapp/
[INFO] Chart.yaml: icon is recommended

1 chart(s) linted, 0 chart(s) failed

helm install --dry-run

  • 模拟安装到集群中,看看是否会有报错

部署chart

#指定chart: 
helm install stable/mariadb
#指定打包的chart: 
helm install ./nginx-1.2.3.tgz
#指定打包目录: 
helm install ./nginx
#指定chart包URL: 
helm install https://example.com/charts/nginx-1.2.3.tgz

调整参数

helm upgrade --set service.type="NodePort" nginx .
  • 在 Helm 命令中,. 表示当前目录。

  • 命令 helm upgrade --set service.type="NodePort" nginx . 中,. 表示 Helm chart 的位置是当前目录。Helm 将在这个目录下查找 Chart.yaml 文件以及其他相关的模板文件来部署或升级你的应用。

回滚版本

#查看历史版本号
helm history nginx
#简写为hist
helm hist nginx
# 回滚到指定版本号
helm rollback nginx 1

查看部署状态

helm status nginx

打包chart

helm package /root/myapp/

查看chart

#inspect和show互为alias
helm inspect chart ~/myapp/
helm show chart ~/myapp/

自定义chart模板

生成chart目录模板

helm create myapp

chart目录结构

cd myapp/
tree ./

├── charts # 用于存放依赖的子chart
├── Chart.yaml # 描述这个 Chart 的相关信息、包括名字、描述信息、版本等
|     apiVersion # Chart的apiVersion,目前默认都是v2
|     name # chart的名称
|     type # Chart的类型,一般都用application
|     version # Chart自己的版本号
|     appVersion # Chart内应用的版本号
|     description # Chart的描述信息
├── templates # 模板目录,保留创建k8s的资源清单文件   ├── deployment.yaml # deployment资源的go模板文件   ├── _helpers.tpl # 自定义的模板或者函数   ├── hpa.yaml    ├── ingress.yaml
│   ├── NOTES.txt # Chart安装完成后输出到控制台的提示信息   ├── serviceaccount.yaml
│   ├── service.yaml
│   └── tests # 存放测试文件的目录       └── test-connection.yaml
└── values.yaml # 模板的值文件,这些值会在安装时应用到 GO 模板生成部署文件

注意:Chart.yaml中的version什么时候需要改:如果只是更新了values.yaml里面的经常变更的配置,不需要改version;如果更新了template/目录里面的模板文件的配置,一般需要把version升级一个版本。

编写Chart.yaml

Helm 使用的 Go 模板是 Go 语言的一个内置包,它提供了数据驱动的模板,用于生成可读的输出。这种模板语言被广泛应用于 Go web 框架和生成文本文件。

在 Helm 中,Go 模板被用于动态生成 Kubernetes 的配置文件。这意味着你可以在模板中使用变量,然后在 Helm 安装 chart 时,根据提供的值文件(values.yaml)或者直接的命令行参数,动态替换这些变量,生成最终的 Kubernetes 配置文件。

例如,你可以在模板中定义一个变量来表示镜像的版本:

image: "{{ .Values.image.tag }}"

然后在 values.yaml 文件或者 helm 命令行参数中提供这个变量的值:

image: 
 tag: "v1.0.0"

这样,Helm 在安装 chart 时,会将模板中的 {{ .Values.image.tag }} 替换为 "v1.0.0",生成最终的 Kubernetes 配置文件。

# Helm Chart的API版本,这里使用的是v2版本。在 v2 版本的 Helm 中,apiVersion 是 v1,而在 v3 版本的 Helm 中,apiVersion 升级为 v2
apiVersion: v2 
# 指定Chart的名称,这个名称将用于在Helm中引用这个Chart
name: myapp 
description: A Helm chart for Kubernetes
# Chart的版本号。每当对Chart和其模板(templates)进行更改时,包括应用版本,都应该递增这个版本号。版本号遵循语义化版本(Semantic Versioning)规范
version: 0.0.1 
appVersion: "latest" # 镜像标签的版本号
# 指定Chart的类型,可以是'application'或'library'。在这个示例中,类型为'application',意味着这是一个可以部署的应用程序Chart
type: application

编写deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ include "myapp.fullname" . }} #include开头的变量,都是来自于helpers.tpl
  labels:
    {{- include "myapp.labels" . | nindent 4 }} # 首行缩进4字符,用于符合yaml文件格式
spec:
  {{- if not .Values.autoscaling.enabled }}
  replicas: {{ .Values.replicaCount }} 
  #.Values开头的来自于Values.yaml
  # 如果 autoscaling.enabled 参数没有启用,副本数将使用配置文件中 .Values.replicaCount 设置。如果启用了自动扩展,则不会应用这个副本数设置,而是由自动扩展机制根据负载动态调整副本数。
  {{- end }}
  selector:
    matchLabels:
      {{- include "myapp.selectorLabels" . | nindent 6 }}
  template:
    metadata:
      {{- with .Values.podAnnotations }} #条件判断,有就去下面抓换,没有就跳过。
      annotations:
        {{- toYaml . | nindent 8 }} # 将 .Values.podAnnotations 参数转换为 YAML 格式,并通过 nindent 8 命令进行缩进。toYaml 是一个 Helm 函数,它将参数转换为 YAML 格式。nindent 8 是一个 Helm 函数,用于对生成的 YAML 进行缩进,使其适应于 YAML 文件中的正确位置。
      {{- 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 }}" # | 代表默认值的判断,如果values.yaml定义了image.tag就沿用,没定义就用默认的Chart.yaml里面的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 }}

_helpers.hpl

_helpers.tpl是helm中的一个重要组成部分,通常用来定义可以被其他模板文件复用的辅助函数、片段或者变量等。

可以把常用的、可重复用的代码片段和逻辑放进去,保持模板文件的整洁。

# 定义模板 
# _helpers.tpl
{{- define "myapp.fullname" -}} # 这是定义了这个模板的名称为myapp.fullname
{{- printf "%s-%s" .Release.Name .Chart.Name | trunc 63 | trimSuffix "-" }}
{{- end }}

# 使用模板,用include来引用。
# templates/api-development.yaml
apiVersion: apps/v1
kind: deployment
metadata:
  name: {{ include "myapp.fullname" . }}-api

#  {{ include "myapp.fullname" . }} 里面的 . 意思是传递当前上下文给helpers.tpl
# 因为这个模板函数需要访问 .Release.Name 和 .Chart.Name,所以调用时必须传递包含这些信息的上下文
# 不写 . ,模板函数内部就无法访问 .Release.Name 和 .Chart.Name,会导致渲染错误。

NOTES.txt

安装说明文件,再执行helm install/upgrade之后,helm会打印出这些信息,比如使用说明等。

NOTES文件同样可以使用template语法进行生成,比如:

Thank you for installing {{ .Chart.Name }}.
Your release is named {{ .Release.Name }}.
To learn about the release, run:
 $ helm status {{ .Release.Name }}
 $ helm get all {{ .Release.Name }}

values.yaml

  • 比如我们要引用values.yaml文件中的image字段下的tag字段的值
  • 可以在模板文件中写成{{ .Values.image.tag }};
  • 如果在命令行使用--set选项来应用我们可以写成 image.tag;
  • 修改对应的值可以直接编辑对应values.yaml文件中对应字段的值,也可以直接使用--set 指定对应字段的对应值即可;默认情况在命令行使用--set选项给出的值,都会直接被替换;没有给定的值,默认还是使用values.yaml文件中给定的默认值;
# Default values for myapp.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
replicaCount: 1
image:
  repository: nginx
  pullPolicy: IfNotPresent
  # Overrides the image tag whose default is the chart appVersion.
  tag: "latest"
imagePullSecrets: []
nameOverride: ""
fullnameOverride: ""
serviceAccount:
  # Specifies whether a service account should be created
  create: true
  # Annotations to add to the service account
  annotations: {}
  # The name of the service account to use.
  # If not set and create is true, a name is generated using the fullname template
  name: ""
podAnnotations: {}
podSecurityContext: {}
  # fsGroup: 2000
securityContext: {}
  # capabilities:
  #   drop:
  #   - ALL
  # readOnlyRootFilesystem: true
  # runAsNonRoot: true
  # runAsUser: 1000
service:
  type: ClusterIP
  port: 80
ingress:
  enabled: false
  className: ""
  annotations: {}
    # kubernetes.io/ingress.class: nginx
    # kubernetes.io/tls-acme: "true"
  hosts:
    - host: chart-example.local
      paths:
        - path: /
          pathType: ImplementationSpecific
  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
autoscaling:
  enabled: false
  minReplicas: 1
  maxReplicas: 100
  targetCPUUtilizationPercentage: 80
  # targetMemoryUtilizationPercentage: 80
nodeSelector: {}
tolerations: []
affinity: {}

部署chart

cd ~/myapp/
helm install nginx ./ #Chart.yaml在当前目录下,就用 ./去部署

Helm Chart开发语法

注意:template/xxx.yaml里面的Go template语法,# 注释是不生效的。意思是即使你注释了一段Go template,里面的语法也是会被渲染生效的。所以不需要某段Go template的话就直接删掉。

常用内置变量

Release.Name # 实例的名称,helm install指定的名字
Release.Namespace # 实例对应的名称空间
Release.IsUpgrade # 如果当前对实例的操作是更新或者回滚,这个变量就是true
Release.IsInstall # 如果当前对实例的操作是安装,这个变量就是true
Release.Revision # 此次修订的版本号,从1开始,每次升级回滚都会+1
Chart # 用来取Chart.yaml文件中的内容,可以使用Chart.Version表示应用版本,Chart.Name表示Chart的名称

常用函数

字符串函数

trim # 去除字符串两边的空格
trimAll # 从字符串中移除给定的字符
trimPrefix # 从字符串前面移除某个字符
trimSuffix # 从字符串后面移除某个字符
lower # 转成小写
upper # 转成大写
title # 首字母大写
repeat # 重复产生字符串
nospace # 去除所有空格
contains # 判断是否包含某个值
hasPrefix # 判断是否以什么开头
hasSuffix # 判断是否以什么结尾
quote # 使用双引号括起来字符串
squote # 使用单引号括起来字符串
cat # 字符串使用空格连接
indent # 已制定的长度缩进
nindent # 缩进,并添加新的一行
substr # 截取字符串,从哪里到哪里
trunc # 阶段字符串,从前或者从后
print # 组合字符串
println # 和print效果一样,但是会在某位新加一行
printf # 格式化字符串,用占位符实现:printf "%s has %d dots" .Name .NumberDots

类型转换函数

atoi # 字符串转成整型
toString # 转换为字符串:12345这种数值、true/false这种布尔值,最需要转成字符串来使用,才能在yaml中作为key或者value来使用。
toStrings # 转换为字符串列表
toYaml # 将列表、切片、数组、字典等,转换成已缩进的yaml块。对于整块存在的多项配置,用这个一起打包转成yaml快很好用

逻辑比较函数

and # 且,多个条件必须同时成立
or # 或,多个条件成立一个即可
not # 取反
eq # 判断是否相等
ne # 判断是否不相等
lt # 是否小于
le # 是否小于等于
gt # 是否大于
ge # 是否大于等于
default # 设置默认值
empty # 判断是否为空

管道符

helm的管道符用 | 来表示,可以按顺序完成一系列任务,比如:

data:
  v1: {{ .Values.env.v1 | repeat 5 | quote }}
  v2: {{ .Values.env.v2 | upper | quote }}

流控制

条件语句if/else

{{ if PIPELINE }}
  # Do something
{{ if OTHER PIPELINE }}
  # Do something else
{{ else }}
  # Default case
{{ end }}
{{- if eq.Values.data.v1 "test" }}
env: "test"
{{ end }}

{{- 是为了去掉渲染之后的 env:test 这一行的上面的空行

循环语句range

{{ range xxx }}
  # Do something
{{ end }}

循环遍历列表

# 假设values.yaml中有这样一行列表配置:
pizzaToppings:
- mushrooms
- cheese
- peppers
- onions

# 在模板中可以这样生成一段字符串列表配置:
toppings: |-
  {{- range .Values.pizzaToppings }}
  - {{ . | title | quote }} # . 代表每次循环的当前上下文的值
  {{- end }}

# 渲染出来结果就是:
toppings: |-
  - "Mushrooms"
  - "Cheese"
  - "Peppers"
  - "Onions"

循环遍历字典kv

# 假设values.yaml中有一个字典
favorite:
  drink: coffee
  food: pizza

# 在模板中可以这样来渲染成字符串的k-v
{{- range $key. $val := .Values.favorite }}
  {{ $key }}: {{ $val | quote }}
{{- end }}

# 结果就是
favorite: |-
  drink: "coffee"
  food: "pizza"

更改取值作用域with

主要用于values中有多层的值,取值非常麻烦,非常长,而且如果改掉values中的母值,模板中的母值就都要改。用with把取值作用域框在母值下面,就方便很多:

{{ with PIPELINE }}
 # restricted scope
{{ end }}

# 使用之前的取值
drink: {{ .Values.favorite.drink | default "tea" | quote }}
food: {{ .Values.favorite.food | upper | quote }}

# 更改作用域之后
{{- with .Values.favorite }}
drink: {{ .drink | default "tea" | quote }}
food: {{ .food | upper | quote }}
{{- end }}

注意:在更改作用域的范围内,如果想要再取到其他外面的变量,需要指定$符,比如:{{ $.Release.Name }}

可视化管理工具-helm dashboard

helm plugin install https://github.com/komodorio/helm-dashboard.git
  • 更新插件
helm plugin update dashboard
  • 卸载
helm plugin uninstall dashboard
  • 使用插件
 设置服务运行绑定 ipv4 ,否则只能本地访问
export HD_BIND=0.0.0.0
# 设置 web 端口,默认8080
export HD_PORT=9000

# 设置1是不打开浏览器,否则默认打开浏览器
#export HD_NOBROWSER=1
# 后台运行
setsid helm dashboard &

helm安装helm dashboard:Helm Dashboard Chart

实战-自定义chart部署flask应用并推送到harbor

应用代码

#这里使用python基于flask开发一个web服务器,该服务通过读取环境变量 USERNAME 获得用户自己定义的名称,然后监听 80 端口。对于任意 HTTP 请求,返回 Hello ${USERNAME}。比如如果设置USERNAME=world(默认场景),该服务会返回 Hello world。
tee app.py <<'EOF'
from flask import Flask
import os

app = Flask(__name__)

@app.route("/", methods=["GET"])
def hello():
    username = os.getenv("USERNAME", "world")
    return f"Hello {username}!"

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=80)
EOF

构建容器镜像

# 使用官方 Python 基础镜像
FROM python:3.10-slim
# 设置工作目录
WORKDIR /app
# 复制当前目录内容到工作目录
COPY . /app
# 安装依赖
RUN pip install --no-cache-dir Flask -i https://mirrors.aliyun.com/pypi/simple/
# 设置环境变量
ENV USERNAME world
# 暴露应用运行的端口
EXPOSE 80
# 运行 Flask 应用
CMD ["python", "app.py"]
docker build -t my-hello .
#镜像可以推送到harbor

构建helm chart

helm create my-hello
#这个命令会生成一个名为 my-hello 的目录,里面包含了 Helm Chart 的基本结构。
#需要注意的是,Chart 里面的 my-hello名称需要和生成的 Chart 文件夹名称一致。如果修改 my-hello,则需要做一致的修改。
  • 在根目录下的 Chart.yaml 文件内,声明了当前 Chart 的名称、版本等基本信息,这些信息会在该 Chart 被放入仓库后,供用户浏览检索。
apiVersionv2
namemy-hello
descriptionMy hello app Helm chart for Kubernetes      # helm chart描述信息

# A chart can be either an 'application' or a 'library' chart.
#
# Application charts are a collection of templates that can be packaged into versioned archives
# to be deployed.
#
# Library charts provide useful utilities or functions for the chart developer. They're included as
# a dependency of application charts to inject those utilities and functions into the rendering
# pipeline. Library charts do not define any templates and therefore cannot be deployed.
typeapplication

# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version1.0   #Chart 的版本

# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
# It is recommended to use it with quotes.
appVersion"1.16.0"   # 应用的版本
  • 编辑values.yaml
#根目录下有一个values.yaml文件,这个文件提供了应用在安装时的默认参数。编辑 values.yaml 文件,定义 Chart 的默认值:
#这里主要修改values.yaml内的 image.repository,image.tag,并添加Username: helm。其他保持默认。
replicaCount1

image:
  repositoryharbor.test.com/library/my-hello
  pullPolicyIfNotPresent
  tag"v1.0"

service:
  typeClusterIP
  port80
...
Usernamehelm
  • 编辑模板文件templates/deployment.yaml
#在templates文件夹内存放了应用部署所需要使用的YAML文件,比如Deployment 和 Service。在我当前的应用内,只需要一个 deployment,而有的应用可能包含不同组件,需要多个deployment,就需要在 templates 文件夹下放置不同deployment的YAML文件。
#增加env部分:
...
      containers:
        - name: {{ .Chart.Name }}
          securityContext:
            {{- toYaml .Values.securityContext | nindent 12 }}
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
          imagePullPolicy: {{ .Values.image.pullPolicy }}
          env:
            - name: USERNAME
              value: {{ .Values.Username }}
...
  • 编辑 templates/service.yaml
apiVersionv1
kindService
metadata:
  name{{ include "my-hello.fullname" . }}
  labels:
    {{- include "my-hello.labels" . | nindent 4 }}
spec:
  type{{ .Values.service.type }}
  ports:
    - port{{ .Values.service.port }}
      targetPorthttp
      protocolTCP
      namehttp
  selector:
    {{- include "my-hello.selectorLabels" . | nindent 4 }}

打包应用

#使用Helm lint校验Chart有无语法问题。
helm lint
==> Linting .
[ERROR] Chart.yaml: version should be of type string but it's of type float64
[INFO] Chart.yaml: icon is recommended
Error: 1 chart(s) linted, 1 chart(s) failed
# 上面提示,version应该为string,而不是float64。将Chart.yaml中的version字段改为字符串,version: "1.0"。重新校验通过:

helm lint
==> Linting .
[INFO] Chart.yaml: icon is recommended
1 chart(s) linted, 0 chart(s) failed
#使用helm package对已经创建好的chart应用进行打包,即得到我们厂家的tgz格式的chart包。
helm package ./my-hello/

部署应用

#部署 Chart进行测试使用以下命令部署你创建的 Helm Chart
helm install my-hello my-hello-1.0.tgz
#也可以根据部署后的提示,配置端口转发到宿主机的8080端口进行测试:
export POD_NAME=$(kubectl get pods --namespace default -l "app.kubernetes.io/name=my-hello,app.kubernetes.io/instance=my-hello" -o jsonpath="{.items[0].metadata.name}")
export CONTAINER_PORT=$(kubectl get pod --namespace default $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}")
echo "Visit http://127.0.0.1:8080 to use your application"
kubectl --namespace default port-forward $POD_NAME 8080:$CONTAINER_PORT
#此时节点处于监听8080端口状态,任何访问8080端口的流量都会转发到my-hello容器的80端口 :
#新开终端
curl localhost:8080

参数重载

#应用开发者在 values 配置中只是提供了默认的安装参数,用户也可以在安装时指定自己的配置,通过set参数传递参数。如果应用已经部署,可以用upgrade命令替代install,实现在原有部署好的应用的基础上变更配置。
# 全新安装
helm install my-hello my-hello-1.0.tgz --set Username="K8S"
# 也可以通过配置文件进行传参
helm install my-hello2 my-hello-1.0.tgz -f my-values.yaml
# 升级更新。基于新的value.yaml或者set更新参数
helm upgrade my-hello my-hello-1.0.tgz -f my-new-values.yaml
helm upgrade my-hello my-hello-1.0.tgz --set Username="K8S"

修改提示信息

#修改提示信息部署chart后的提示信息来自templates目录下的NOTES.txt文件:
#根据需要可以自定义输出。
cat my-hello/templates/NOTES.txt
1. Get the application URL by running these commands:
{{- if .Values.ingress.enabled }}
{{- range $host := .Values.ingress.hosts }}
  {{- range .paths }}
  http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }}
  {{- end }}
{{- end }}
{{- else if contains "NodePort" .Values.service.type }}
  export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "my-hello.fullname" . }})
  export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
  echo http://$NODE_IP:$NODE_PORT
{{- else if contains "LoadBalancer" .Values.service.type }}
     NOTE: It may take a few minutes for the LoadBalancer IP to be available.
           You can watch its status by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "my-hello.fullname" . }}'
  export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "my-hello.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}")
  echo http://$SERVICE_IP:{{ .Values.service.port }}
{{- else if contains "ClusterIP" .Values.service.type }}
  export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "my-hello.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
  export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}")
  echo "Visit http://127.0.0.1:8080 to use your application"
  kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT
{{- end }}

清理部署

helm ls
helm uninstall my-hello