什么是 Helm
每个成功的软件平台都有一个优秀的打包系统,比如Debian、Ubuntu 的 apt,RedHat、CentOS 的 yum。Helm 则是 Kubernetes上 的包管理器,方便我们更好的管理应用。在没使用 helm 之前,向 kubernetes 部署应用,我们要依次部署 deployment、svc 等,步骤较繁琐。 况且随着很多项目微服务化,复杂的应用在容器中部署以及管理显得较为复杂,helm 通过打包的方式,支持发布的版本管理和控制, 很大程度上简化了 Kubernetes 应用的部署和管理。
Helm本质就是让K8s的应用管理(Deployment、Service等)可配置,可以通过类似于传递环境变量的方式能动态生成。通过动态生成K8s资源清单文件(deployment.yaml、service.yaml)。 然后调用 Kubectl 自动执行 K8s 资源部署。
Helm 是K8S的软件包(Chart包)管理器
可以实现将软件应用所有所需的资源配置打包在一起,资源配置还能实现高度的可配置化,并可以通过单个helm命令一键管理部署
Helm 是官方提供的类似于 YUM 的包管理器,是部署环境的流程封装。
Helm 有三个重要的概念:Chart 、Repository 和 Release
- Chart(软件包):Helm 的软件包,采用 TAR 格式。是创建一个应用的信息集合,包括各种 Kubernetes 对象的配置模板、参数定义、依赖关系、文档说明等。chart 是应用部署的自包含逻辑单元。 可以将 chart 想象成 apt、yum 中的软件安装包。
- Release(基于Chart运行的实例):是 chart 的运行实例,代表了一个正在运行的应用。当 chart 被安装到 Kubernetes 集群,就生成一个 release。chart 能够多次安装到同一个集群,每次安装都是一个 release。
- Repository(存放Chart的仓库):Charts 仓库,用于集中存储和分发 Charts。Repository 本质上是一个 Web 服务器,该服务器保存了一系列的 Chart 软件包以供用户下载,并且提供了一个该 Repository 的 Chart 包的清单文件以供查询。Helm 可以同时管理多个不同的 Repository。
总结:Helm 安装 charts 到 Kubernetes 集群中,每次安装都会创建一个新的 release。你可以在 Helm 的 chart repositories 中寻找新的 chart。
Helm3 与 Helm2 的区别
Helm2 是 C/S 架构,主要分为客户端 helm 和服务端 Tiller。在 Helm 2 中,Tiller 是作为一个 Deployment 部署在 kube-system 命名空间中,很多情况下,我们会为 Tiller 准备一个 ServiceAccount ,这个 ServiceAccount 通常拥有集群的所有权限。
用户可以使用本地 Helm 命令,自由地连接到 Tiller 中并通过 Tiller 创建、修改、删除任意命名空间下的任意资源。在 Helm 3 中,Tiller 被移除了。新的 Helm 客户端会像 kubectl 命令一样,读取本地的 kubeconfig 文件,使用我们在 kubeconfig 中预先定义好的权限来进行一系列操作。
Helm 的官方网站 https://helm.sh/
Helm 命令总结(详细用法请看下面的示例)
Helm 仓库管理命令
helm repo list ✨#查看chart仓库列表 add <仓库名称> <仓库URL地址> ✨#添加chart仓库 update #更新chart仓库 remove <仓库名称> #删除chart仓库 helm search repo <仓库名称> ✨#查看仓库中可用的chart包列表 helm search repo <仓库名/软件包> -l #查看仓库中此软件包的所有历史版本列表 helm show chart <仓库名/软件包> #查看chart软件包的基本概要信息 helm show all <仓库名/软件包> #查看chart软件包的所有详细信息
Helm 的包安装、卸载命令
helm install <实例名> <仓库名/软件包> -n <命名空间> [--version=
] ✨#根据chart包安装实例 helm ls|list -n <命名空间> #查看指定命名空间下的实例列表 helm status <实例名> -n <命名空间> #查看实例的状态 helm uninstall <实例名> -n <命名空间> ✨#卸载实例 Helm chart软件包管理命令
helm pull <仓库名/软件包> ✨#从仓库拉取chart压缩包 helm create
#创建一个chart目录(生成配置文件模版) helm lint #检查chart配置语法 helm package ✨#打包成chart压缩包 helm upgrade <实例名>
-n <命名空间> ✨#升级实例 helm history <实例名> -n <命名空间> #查看实例的历史版本列表 helm rollback <实例名> <版本序号> -n <命名空间> ✨#回滚实例到指定历史版本 Helm 接入私有harbor仓库
helm repo add <私有仓库名> <私钥仓库地址> --username= --password= #添加chart私钥仓库,harbor私钥仓库地址格式为:http://私钥仓库URL地址/chartrepo/项目名 helm push
<私有仓库名> #推送chart包到私钥仓库
1、安装 helm (本次实验在master节点安装helm)
//下载二进制 Helm client 安装包
https://github.com/helm/helm/tagstar -zxvf helm-v3.6.0-linux-amd64.tar.gz mv linux-amd64/helm /usr/local/bin/helm helm version
//命令补全 写入/etc/bashrc 中完成bash开启自动加载
vim /etc/bashrc source <(helm completion bash)
2、使用 helm 安装 Chart(chart常用命令)
//添加常用的 chart 仓库
helm repo add bitnami https://charts.bitnami.com/bitnami helm repo add stable http://mirror.azure.cn/kubernetes/charts helm repo add aliyun https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts helm repo add incubator https://charts.helm.sh/incubator
//更新 charts 列表
helm repo update helm repo list
//查看 stable 仓库可用的 charts 列表
helm search repo stable
//删除 incubator 仓库
helm repo remove incubator
//查看 chart 信息
helm show chart stable/mysql #查看指定 chart 的基本信息 helm show all stable/mysql #获取指定 chart 的所有信息
//安装 chart
helm install my-redis bitnami/redis [-n default] #指定 release 的名字为 my-redis,-n 指定部署到 k8s 的 namespace --version 指定版本(不是app版本是上传版本) helm install bitnami/redis --generate-name #不指定 release 的名字时,需使用 –generate-name 随机生成一个名字
//查看所有 release
helm ls helm list helm list -n 命名空间
kubectl get all -n 命名空间 查看helm创建了哪些资源
//查看指定的 release 状态
helm status my-redis
//删除指定的 release
helm uninstall my-redis
charts 除了可以在 repo 中下载,还可以自己自定义,创建完成后通过 helm 部署到 k8s。
拉取 chart
mkdir /opt/helm cd /opt/helm helm pull stable/mysql
ls mysql-1.6.9.tgz #拉取的是tgz后缀包
tar xf mysql-1.6.9.tgz #解压查看内容 yum install -y tree tree mysql mysql ├── Chart.yaml ├── README.md ├── templates │ ├── configurationFiles-configmap.yaml │ ├── deployment.yaml │ ├── _helpers.tpl │ ├── initializationFiles-configmap.yaml │ ├── NOTES.txt │ ├── pvc.yaml │ ├── secrets.yaml │ ├── serviceaccount.yaml │ ├── servicemonitor.yaml │ ├── service.yaml │ ├── ingress.yaml │ └── tests │ ├── test-configmap.yaml │ └── test.yaml └── values.yaml
可以看到,一个 chart 包就是一个文件夹的集合,文件夹名称就是 chart 包的名称。
chart包的关键组成
Chart.yaml软件包自描述文件
描述chart的元信息,包括chart名称(name)、chart版本(version)、应用版本(appVersion)、chart api接口(apiVersion)等
templates目录
目录里存放部署应用所需要的各种资源对象的yaml配置模板文件
●NOTES.txt:chart 的“帮助文本”,在用户运行 helm install 时显示给用户
●deployment.yaml:创建 deployment 的资源清单文件
●service.yaml:为 deployment 创建 service 的资源清单文件
●ingress.yaml: 创建 ingress 对象的资源清单文件
●_helpers.tpl:放置模板助手的地方,可以在整个 chart 中重复使用,存放默认值values.yaml
存储 templates目录中yaml配置模板文件中变量的值
(yaml配置模板文件变量 {{ .Values.image.repository }} 即对应着 values.yaml 文件中 image.repository 字段的值)
创建自定义的 chart
helm create nginx tree nginx nginx ├── charts ├── Chart.yaml ├── templates │ ├── deployment.yaml │ ├── _helpers.tpl │ ├── hpa.yaml │ ├── ingress.yaml │ ├── NOTES.txt │ ├── serviceaccount.yaml │ ├── service.yaml │ └── tests │ └── test-connection.yaml └── values.yaml
cat nginx/templates/deployment.yaml 可见已经生成相应模版
#在 templates 目录下 yaml 文件模板中的变量(go语言 template语法)的值默认是在 nginx/values.yaml 中定义的,只需要修改 nginx/values.yaml 的内容,也就完成了 templates 目录下 yaml 文件的配置。
比如在 deployment.yaml 中定义的容器镜像:image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
cat nginx/values.yaml | grep repository repository: nginx
#以上变量值是在 create chart 的时候就自动生成的默认值,你可以根据实际情况进行修改。
修改 chart 配置
vim nginx/Chart.yaml apiVersion: v2 name: nginx #chart名字 description: A Helm chart for Kubernetes type: application #chart类型,application或library version: 0.1.0 #chart版本 appVersion: 1.16.0 #application部署版本
vim nginx/values.yaml replicaCount: 1 image: repository: nginx pullPolicy: IfNotPresent tag: "latest" #设置镜像标签 imagePullSecrets: [] nameOverride: "" fullnameOverride: "" serviceAccount: create: true annotations: {} name: "" podAnnotations: {} podSecurityContext: {} # fsGroup: 2000 securityContext: {} # capabilities: # drop: # - ALL # readOnlyRootFilesystem: true # runAsNonRoot: true # runAsUser: 1000 service: type: ClusterIP port: 80 ingress: enabled: true #开启 ingress className: "" annotations: {} # kubernetes.io/ingress.class: nginx # kubernetes.io/tls-acme: "true" hosts: - host: www.xue.com #指定ingress域名 paths: - path: / pathType: Prefix #指定ingress路径类型 tls: [] # - secretName: chart-example-tls # hosts: # - chart-example.local 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 部署 chart
helm lint nginx
#检查依赖和模版配置是否正确
helm package nginx
#打包 chart,会在当前目录下生成压缩包 nginx-0.1.0.tgz//部署 chart
helm install nginx ./nginx --dry-run --debug #使用 --dry-run 参数验证 Chart 的配置,并不执行安装 helm install nginx ./nginx -n default #部署 chart,release 版本默认为 1 或者 helm install nginx ./nginx-0.1.0.tgz
#可根据不同的配置来 install,默认是 values.yaml
helm install nginx ./nginx -f ./nginx/values-prod.yaml helm ls NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION nginx default 1 2022-01-18 23:43:06.170248683 +0800 CST deployed nginx-0.1.0 1.16.0
kubectl get pod,svc NAME READY STATUS RESTARTS AGE pod/nginx-67779bd969-kq2fm 1/1 Running 0 58m NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/kubernetes ClusterIP 10.96.0.1
443/TCP 37h service/nginx ClusterIP 10.100.0.171 80/TCP 58s #部署 ingress
wget https://gitee.com/mirrors/ingress-nginx/raw/nginx-0.30.0/deploy/static/mandatory.yaml wget https://gitee.com/mirrors/ingress-nginx/raw/nginx-0.30.0/deploy/static/provider/baremetal/service-nodeport.yaml kubectl apply -f mandatory.yaml kubectl apply -f service-nodeport.yaml
kubectl get pod,svc -n ingress-nginx NAME READY STATUS RESTARTS AGE pod/nginx-ingress-controller-54b86f8f7b-jjlnj 1/1 Running 0 79s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/ingress-nginx NodePort 10.101.36.34
80:30665/TCP,443:30363/TCP 6s kubectl get ingress NAME CLASS HOSTS ADDRESS PORTS AGE nginx
www.xue.com 10.101.36.34 80 58m vim /etc/hosts ..... 192.168.80.12 node02 www.xue.com curl http://www.xue.com:30665
修改为 NodePort 访问后,升级
编辑values.yaml
vim nginx/values.yaml service: type: NodePort port: 80 nodePort: 30080 #注意不要与nginx-ingress-controller的配置文件deploy.yaml中已存在的nodeport冲突(例如在deploy.yaml中已经设置了http的nodeport为30080,这里就需要写别的端口号) ingress: enabled: false
此外还需要修改 service.yaml 模版文件,在其中添加上nodePort: {{ .Values.service.nodePort }}引用values.yaml中指定的值
vim nginx/templates/service.yaml apiVersion: v1 kind: Service metadata: name: {{ include "nginx.fullname" . }} labels: {{- include "nginx.labels" . | nindent 4 }} spec: type: {{ .Values.service.type }} ports: - port: {{ .Values.service.port }} targetPort: http protocol: TCP name: http nodePort: {{ .Values.service.nodePort }} #指定 nodePort selector: {{- include "nginx.selectorLabels" . | nindent 4 }}
升级 release,release 版本加 1
helm upgrade nginx nginx #实例 #chart包(此处为/helm/nginx文件夹)
kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.96.0.1
443/TCP 38h nginx NodePort 10.100.0.171 80:30080/TCP 79m helm ls -n 命名空间 查看版本
curl 192.168.80.14:30080
回滚
#根据 release 版本回滚
helm history nginx #查看 release 版本历史 helm rollback nginx 1 #回滚 release 到版本1
helm history nginx #nginx release 已经回滚到版本 1 REVISION UPDATED STATUS CHART APP VERSION DESCRIPTION 1 Tue Jan 18 23:43:06 2022 superseded nginx-0.1.0 1.16.0 Install complete 2 Wed Jan 19 01:02:42 2022 superseded nginx-0.1.0 1.16.0 Upgrade complete 3 Wed Jan 19 01:04:52 2022 deployed nginx-0.1.0 1.16.0 Rollback to 1
#通常情况下,在配置好 templates 目录下的 kubernetes 清单文件后,后续维护一般只需要修改 Chart.yaml 和 values.yaml 即可。
//在命令行使用 --set 指定参数来部署(install,upgrade)release
#注:此参数值会覆盖掉在 values.yaml 中的值,如需了解其它的预定义变量参数,可查看 helm 官方文档。helm upgrade nginx nginx --set image.tag='1.15'
helm 可以使用 harbor 作为本地仓库,将自定义的 chart 推送至 harbor 仓库。
选择一台新主机安装 harbor(192.168.80.105主机)
#上传 harbor-offline-installer-v1.9.1.tgz 和 docker-compose 文件到 /opt 目录
cd /opt cp docker-compose /usr/local/bin/ chmod +x /usr/local/bin/docker-compose
tar zxf harbor-offline-installer-v1.9.1.tgz cd harbor/ vim harbor.yml hostname: 192.168.80.105 harbor_admin_password: Harbor12345 #admin用户初始密码 data_volume: /data #数据存储路径,自动创建 chart: absolute_url: enabled #在chart中启用绝对url log: level: info local: rotate_count: 50 rotate_size: 200M location: /var/log/harbor #日志路径
#安装带有 Clair service 和 chart 仓库服务的 Harbor
./install.sh --with-clair --with-chartmuseum
helm 安装 push 插件
#在线安装 在安装helm的节点(本次实验为master节点)
helm plugin install https://github.com/chartmuseum/helm-push
#离线安装 在安装helm的节点(本次实验为master节点)
wget https://github.com/chartmuseum/helm-push/releases/download/v0.8.1/helm-push_0.8.1_linux_amd64.tar.gz mkdir ~/.local/share/helm/plugins/helm-push tar -zxvf helm-push_0.8.1_linux_amd64.tar.gz -C ~/.local/share/helm/plugins/helm-push helm repo ls
#登录 Harbor WEB UI 界面,创建一个新项目
浏览器访问:http://192.168.80.105 ,默认的管理员用户名和密码是 admin/Harbor12345
点击 “+新建项目” 按钮
填写项目名称为 “chart_repo”,访问级别勾选 “公开”,点击 “确定” 按钮,创建新项目#添加仓库 在安装helm的节点(本次实验为master节点)
helm repo add harbor http://192.168.80.105/chartrepo/chart_repo --username=admin --password=Harbor12345 注:这里的 repo 的地址是
/chartrepo/<项目名称>,Harbor 中每个项目是分开的 repo。如果不提供项目名称, 则默认使用 library 这个项目。 #推送 chart 到 harbor 中 在安装helm的节点(本次实验为master节点)
cd /opt/helm helm push nginx harbor helm push myapp-0.0.3.tgz harbor #helm文件夹下推送包 到harbor仓库
#查看 chart_repo 项目中的 Helm Chars