1、什么是Helm
在没使用helm之前,部署k8s应用,需要依次部署deployment、svc等,步骤比较繁琐。(尤其是我们初学者,各种资源清单的编写太过复杂)况且随着很多项目的微服务化,复杂的应用在容器中部署以及管理显得较为复杂,可能存在几十个资源清单。所以helm通过打包的方式,支持发布的版本管理和控制,很大程度简化了k8s应用的部署和管理
Helm本质就是让k8s的应用管理(deployment、service等)可配置,能动态生成。通过动态生成k8s资源清单文件(deployment.yaml、service.yaml等)。然后调用kubectl自动执行k8s资源部署。通俗的说就是更加的方便对资源清单的修改
2、helm重要概念
Helm是官方提供的类似于yum的包管理器,是部署环境的流程封装。helm有几个重要的概念:
- Chart:是创建一个应用的信息集合,包括各种k8s对象的配置模板、参数定义、依赖关系、文档说明等、chart是应用部署的自包含逻辑单元,可以将chart理解为yum中的软件安装包
- Release:是chart的运行实例,代表了一个正在运行的应用。当chart被安装到k8s集群,就生成一个release。chart能够多次安装到同一个集群,每次安装都是一个release
- Helm cli:helm客户端组件,负责和k8s apiserver通信
- Repository:用于发布和存储Chart的仓库(就像镜像仓库)
3、helm组件结构
Helm v2是C/S架构,主要分为客户端helm和服务店tiller。而由于RBAC等权限控制体系的逐渐完善,多租户和安全的需求日益兴起,tiller变得越来越不安全,社区在权限控制领域遇到了极大的阻碍。所以在helm v3版本中,直接将这一组件移除,helm直接和kubernetes API进行通信。直接带来的好处如下:
- Helm的架构变得更为简单和灵活
- 不需要在创建ServiceAccount,直接使用当前环境中的kubeconfig配置,因为kubeconfig是和用户权限绑定的,所以发起helm实例部署的时候,用的就是当前的kubeconfig文件权限,不会有权限溢出的问题
- 可以直接和kubernetes API交互(https协议),更为安全
- 不需要使用helm init来进行初始化(v2版本需要)
我们学习的是v3
4、helm的安装及演示
helm安装
#安装helm
wget https://get.helm.sh/helm-v3.12.3-linux-amd64.tar.gz
tar -xf helm-v3.12.3-linux-amd64.tar.gz
cp -a linux-amd64/helm /usr/local/bin/
chmod a+x /usr/local/bin/helm
helm version
helm初始化
#添加Helm仓库,就像yum仓库,这个动作叫初始化。可以添加多个
helm repo add bitnami https://charts.bitnami.com/bitnami #helm官方仓库,各位可以找国内的
#初始化结束可以查一下仓库是否添加
helm repo ls
# 仓库的缓存路径,路径下.txt文件,是chart包的列表;.yaml文件是该仓库的元数据索引,记录了仓库中所有 Chart 的信息,包括版本、名称、描述等。
/root/.cache/helm/repository
#helm仓库地址修改
~/.config/helm #修改url部分,即可还可以修改name仓库名称,
helm增删改查命令示例
#列出当前所有仓库
helm repo list
#移除仓库
helm repo remove baseName
#添加仓库
helm repo add dev URL
#更新仓库内chart包的信息
helm repo update
#列出当前的release,输出release信息
helm list
helm list --all
#查看chart包哪里能够更改
helm show values bitnami/apache
#安装chart包,会将chart生成release,并形成pod部署在k8s中
helm install apache-1612624192 bitnami/apache #安装chart包,自定义release名称,名称不能重复
helm install bitnami/apache --generate-name #随机生成release名称
#chart包的基本信息
helm show chart bitnami/apache
#chart包的所有信息
helm show all bitnami/apache
#卸载chart包,删除和该版本相关的所有相关资源(deployment、svc、pod等)甚至版本历史
helm uninstall releaseName
--keep-history #选项,helm删除实例,但是会保存历史版本
#查看release版本信息
helm status releaseName
#查找chart包,helm搜索使用模糊字符串匹配算法,所以可以只输入名字的一部分,比如word
helm search repo bitnami #查看仓库内所有的chart包
hele search repo wordpress #指定仓库查找wordpress包
helm search bhub wordpress #在Helm Hub上搜索chart包,不局限于当前的仓库列表
#安装前自定义chart有两种方式,并且要配合helm install values bitnami/apache使用
第一种:--values(或-f)使用yaml文件覆盖配置,可以指定多次,最优先使用右边的文件
vi values.yaml(新建文件,将需要修改的项写入即可)
service:
type: NodePort
helm install -f values.yaml bitnami/apache --generate-name
第二种:通过命令行方式对指定项进行覆盖
helm install bitnami/apache --set service.type=NodePort --generate-name
--set的格式和限制,每个格式下面对标了yaml格式
--set name=value #最简单的用法
name: value
--set a=b,c=d #多个值使用逗号分割
a: b
c: d
--set outer.inner=value #对象下的子对象用.连接指定就像第二个例子
service:
type: NodePort
--set name={a,b,c} #列表或数组使用花括号来表示
name:
- a
- b
- c
--set name=[],a=null #某些name/key可以设置为null或者空数组
name: []
a: null
--set servers[0].port=80 #用数组下标的方法来访问列表中的元素
servers:
- port: 80
--set servers[0].port=80,servers[0].host=example #多个值也可通过这种方式设置
servers:
- port: 80
host: example
--set name=value1\,value2 #使用特殊字符,用反斜线进行转义
name: "value1,value2"
--set nodeSelector."kubernetes.io/role"=master #又或者使用双引号,不用反斜线
nodeSelector:
kubernetes.io/role: master
修改参数多或选项太长的话推荐第一种,个别需要修改推荐第二种
如果同时使用两种方式,则 --set 中的值会被合并到 --values 中,但是 --set 中的值优先级更高。
在 --set 中覆盖的内容会被被保存在 ConfigMap 中。可以通过 helm get values <release-name> 来
查看指定 release 中 --set 设置的值。也可以通过运行 helm upgrade 并指定 --reset-values 字段来
清除 --set 中设置的值
#更多的安装方式
本地chart压缩包: helm install mynginx ./nginx-1.2.3.tgz
解压后的chart目录: helm install mynginx ./nginx
完整的URL: helm install mynginx https://example.com/charts/nginx-1.2.3.tgz
helm升级/回滚命令示例
#release升级/更新配置,升级时会尝试执行最小侵入式升级。即它只会更新自上次发布以来发生了更改的内容
helm upgrade -f values2.yaml apache-1736252965 bitnami/apache
helm upgrade --set service.type=NodePort apache-1736252965 bitnami/apache
#查看更新是否生效,感觉用处不大,因为修改后k8s也会有变化,直接看k8s就行
helm get values releaseName
#helm rollback,更新回滚。每发生一次安装、升级、回滚操作,revision的值会加1,第一次reversion的值永远是1。可以用helm history releaseName查看特定release的修订版本号
helm rollback releaseName 1
#安装、升级、回滚时的有用选项
--timeout:
一个Go duration类型的值,用来表示等待k8s命令完成的超时时间,默认值5m0s,可修改
--wait:(不推荐)
表示必须要等到所有的Pods都处于ready状态,PVC都被绑定,Deployments斗至少拥有最小ready状态Pods个数(Desired减去maxUnavailable),并且Services都具有IP地址(如果是LoadBalancer,则为Ingress),才会标记该release为成功。最长等待时间由--timeout指定,但其滚动升级策略中的manxUnavailable没有没设置为0时,--wait将返回就绪,因为已经满足了最小ready Pod数
--no-hooks:
不运行当前命令的钩子,即为安装此chart时的已定义的安装前或安装后的动作
--recreate-pods:(仅适用于upgrade和rollback)
这个参数会导致重建所有的Pod(deployment中的Pod除外)。(在helm v3中被废弃)
5、创建一个自己的Chart
#创建一个模板,创建后会生成一个目录,进入目录中
helm create myapp
目录中有4个文件,
- Chart.yaml:定义 Helm Chart 的元数据,如名称、版本和描述
- values.yaml:默认的可配置参数,用户可以在安装时覆盖这些值,一般会删掉
- charts:用于存放 Chart 的依赖,就像yum安装时候的依赖
- templates:目录下是资源清单模板,要编写的部分,Helm 会根据这些模板生成最终的资源配置,一般会删掉,自己写
编写template下的service和deployment资源清单
vim myapp/templates/svc-nodeport.yaml
apiVersion: v1
kind: Service
metadata:
name: myapp-test
labels:
app: myapp-test
spec:
ports:
- name: 80-80
port: 80
protocol: TCP
targetPort: 80
nodePort: 32123
selector:
app: myapp-test
type: NodePort
vim myapp/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: myapp-test
name: deploy-test
spec:
replicas: 5
selector:
matchLabels:
app: myapp-test
template:
metadata:
labels:
app: myapp-test
spec:
containers:
- image: nginx
name: nginx
#进行安装
helm install myapp myapp/
从上面的操作步骤来看,不用helm install安装,使用kubectl apply -f也是可以的。但是!helm的核心用法还没有展现出来,那就是动态生成资源清单!
动态生成资源清单
还是上面的代码,但是稍微做些改动
#先写一个helm安装后的通知模板,随便写。{
{}}中的是go语言的函数
vim myapp/templates/NOTES.txt
1、这是一个测试的 myapp chart
2、myapp release 名字:myapp-test-{
{ now |date "200601021504"}}-deploy
3、service 名字:myapp-test-{
{ now |date "200601021504" }} -svc
#再写deployment清单
vim myapp/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: myapp-test
name: myapp-test-{
{ now |date "200601021504"}}-deploy
spec:
replicas: {
{ .Values.replicaCount }}
selector:
matchLabels:
app: myapp-test
template:
metadata:
labels:
app: myapp-test
spec:
containers:
- image: {
{ .Values.image.repository }}:{
{ .Values.image.tag }}
name: nginx
#再写svc
vim myapp/templates/svc-nodeport.yaml
apiVersion: v1
kind: Service
metadata:
name: myapp-test-{
{ now |date "200601021504" }} -svc
labels:
app: myapp-test
spec:
ports:
- name: 80-80
port: 80
protocol: TCP
targetPort: 80
{
{- if eq .Values.service.type "NodePort" }}
nodePort: {
{ .Valuses.service.nodePort }}
{
{- end }}
selector:
app: myapp-test
type: {
{ .Values.service.type |quote }}
#在写个values.yaml,用于提取变量,这个文件和template目录是平级的
vim values.yaml
# Default values for myapp.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
replicaCount: 5
image:
repository: nginx
tag: "latest"
service:
type: NodePort
nodeport: 32321
涉及到go语言的语法和函数,不是很明白。但是原理是将关键信息提取出来作为变量,然后在values文件中定义变量