你将在本文学到什么?
-
Helm是什么? -
如何使用以及调试Helm? -
helm原理相关技术分析
涵盖的技术概念
-
kubernetes -
Chart -
go/template库
为什么需要使用helm
要弄懂这个问题,我们需要了解kubernetes上如何部署一个应用,如下图所示:当用户要求 Kubernetes 使用 kubectl 创建部署时,如下所示,
-
该过程是这样的kubectl apply -f k8s-deployment.yml; -
kubectl 将 yaml 资源转换为 JSON 并将其发送到主节点或控制平面内的 API Server; -
API Server 接收请求并将部署详细信息或对象定义保存到数据库中(etcd)。 -
etcd 是 Kubernetes 用于存储数据的高可用键值存储。 -
etcd 是 Kubernetes 的重要组件,因为它存储集群的整个状态:其配置、规格和正在运行的工作负载的状态。 -
当新的deployment资源存储在 etcd 存储中时,**控制器管理器(contoller manager)**会收到通知,并创建足够的 Pod 资源来匹配 Deployment 中的副本。 -
此时etcd中部署(deployment)的状态为Pending状态。 -
Scheduler 查看 Pending 状态并检查基础设施的状态,对节点进行过滤和排序,以决定将 Pod 调度到哪里,然后执行其业务逻辑,用可调度节点的名称填写 Pod 规范中的 nodeName 字段,将调度的 Pods 对象以 Scheduled 状态持久保存在 etcd 中; -
在此阶段,尚未创建 Pod,只是创建、更新对象并将其存储在 etcd 中。 -
在每个工作节点上,都有一个 kubelet 负责与主节点或控制平面通信。它提供了 Kubernetes 控制平面和集群中每台服务器上的容器运行时之间的接口。 -
kubelet 确保容器在 Pod 中运行。当控制平面需要在节点中发生某些事情时,kubelet 就会执行该操作。如果我们的部署规范有创建 3 个副本的说明。在此阶段,每一项都将按计划在 etcd 中进行标记。Kubelet 检索 Pod 的模板并将创建容器委托给 Docker 守护进程。 -
当 Docker 守护进程完成任务时,kubelet 会检查就绪情况和活性探测器,Pod 最终被标记为正在运行。
在这个过程中,最为关键的就是manifest文件,即告诉k8s,如何编排我们的部署单元。 一开始这么使用,当然是最快,最方便的,但是在开发整个生命周期的,除了部署,还需要升级,回滚,历史版本记录,配置修改等操作,那么原生的kubectl就无法支撑整个周期。这时候就祭出了helm。
介绍
helm官方定义:kubernetes包管理器,在学习过程中,可以与现有的技术进行类比,如:centos的yum, python->pip, go->go mod,rust -> cargo等。目的是为了在某个位置引用已有的包来使用。那么对应,helm即是在kubernetes中,引用我们所需的包,通过helm install即可安装。 这里的包:可以是中间件(prometheus),可以是服务程序等。 helm包含了三大概念,详情可查看:使用Helm, 这里我说说我的理解:Chart:英文:图表,谱。这里我更喜欢谱这个解释, 告诉kubernetes如何演奏这个乐谱,而不离谱。在谱中,我们可以加入一些根据演奏环境而变化的歌词,但不修改谱。也就是说:**在chart中,提供一组manifests的模板文件,根据环境的不同,可以自定义一些变量。 **如果之前使用过python,可以用jinja来理解。 go的话,则是template。当然helm使用的是golang,那么在这猜也能猜得到,他使用了template库。Repository:有了chart,肯定需要存放的位置,repository则是存在charts的地方。Release:英文:发布;则是chart的部署状态,我们真正使用到的,也是kubernetes使用的到的。一个chart可以部署成多个release。根据变量的不同,release内部的字段也有不同的展示形式。
快速使用
前置条件:
-
安装kubernets;(可以使用kind快速部署) -
安装helm二进制文件, 直接进入 https://github.com/helm/helm/releases 下载最新版本即可。 -
将helm二进制文件拷贝到所有kubernetes操作权限的主机上(默认master主机)。
升级操作步骤如下:
-
添加对应仓库:告诉helm客户端,去哪里可以找到这个包。
helm repo add <别名> <地址>
★
注意点:当需要访问私有仓库时,使用helm repo add –help,查看用户名/密码如何使用; 如果私有仓库为自签名https时,需要添加 –insecure-skip-tls-verify 来忽略证书校验,当然也可以将自签名证书拷贝到当前机器下。
”
-
执行仓库更新操作:更新对应仓库的索引文件,告诉helm客户端,有哪些版本可以升级。
helm repo update
# 通过以上命令完成对所有仓库索引的更新
-
安装对应包;
helm install <releaseName> <repoName>/<packageName> --version <版本号>
-
等待安装完成。
详细步骤可参考官方文档,已经很细节了:快速入门指南详细原因以及实战在原理章节说明。
如何开发一个helm包
首先,通过以下命令创建一个helm文件:
helm create mychart
helm包具体包含了以下目录:
mychart/
├── charts // 子chart目录
├── Chart.yaml // chart申明文件
├── templates // 模板文件
│ ├── deployment.yaml
│ ├── _helpers.tpl
│ ├── hpa.yaml
│ ├── ingress.yaml
│ ├── NOTES.txt
│ ├── serviceaccount.yaml
│ ├── service.yaml
│ └── tests
│ └── test-connection.yaml
└── values.yaml // 动态值的声明文件,这个文件包含template文件下模板字段的默认值。
我们要理解helm包具体是什么?既然helm包是为了完成kubernetes一组manifests的部署,那么这即是它的最终状态—-一组manifests文件,即使用values.yaml覆盖templates中所有文件后产生的一组文件。具体其中文件该怎么写,可以查看从这里开始吧。
实战中使用到的命令
安装并更新:
# 等待资源全部执行成功,并设置超时时间
helm upgrade --install <release> <repo>/<chart> --wait --timeout 10m
回滚操作:
helm rollback <Release> <revision>
这里注意: revision为helm自管理版本号,非chart版本号;如何测试chart:
helm tempalte --debug ./mychart
如何模拟安装,发现错误:
helm install --dry-run <releaseName> ./mychart
Helm的FAQ
another operation (install/upgrade/rollback) is in progress
英文原意:当前对应的Release下已经有一个正在进行中的操作了。 产生这种情况的原因: 在先前执行helm 操作时,没有等待操作完成,即关闭了进程,如当使用helm install –wait时,未完成的情况下,直接Ctrl+C 。 那么在下一次操作就会产生这个错误; 如果使用helm list ,发现没有看见对应的release, 其原因是:release的状态已变成 pending-install 或者pending-upgrade了。 而helm list 源码,在初始化的时候,只会展示 deployd 以及 faild。 所以需要使用helm list -a 来查看当前release的状态。 解决方式: 将前一个执行的secret给删除, 命令如下:
kubectl get secret |grep <release>
# 找到对应最后一个版本删除
kubectl delete secret <release>_<版本号>
Error: rendered manifests contain a resource that already exists. Unable to continue with install: existing resource conflict
helm 在首次安装过程中,会去判断chart中的资源类型是否存在,如果存在则报错。有以下两种方式解决:删除现有资源通过kubectl delete循环删除冲突资源选项。 缺点: 如果资源涉及到service,deployment等关键资源时,会造成短时间内系统的崩溃。
欺骗helm,声明资源被helm纳管原理:使用helm部署的服务,分别在资源annotation以及label中新增加了字段:
annotation:
meta.helm.sh/release-name: <relaseName>
meta.helm.sh/release-namespace: <namespace>
label:
app.kubernetes.io/managed-by: Helm
那么,就简单了,可以使用命令完成欺骗:
helm template --debug <repoName>/<chartName> -n <namespace> --version <version> | kubectl annotate -f - meta.helm.sh/release-name=<releaseName> meta.helm.sh/release-namespace=<namespace> -o yaml --field-selector=metadata.namespace=<namespace> || true
helm template --debug <repoName>/<chartName> -n <namespace> --version <version> | kubectl label -f - app.kubernetes.io/managed-by=Helm -o yaml --field-selector=metadata.namespace=<namespace>
helm-SDK的使用
官方实例如下:
package main
import (
"log"
"os"
"helm.sh/helm/v3/pkg/action"
"helm.sh/helm/v3/pkg/cli"
)
func main() {
// 创建客户端配置
settings := cli.New()
// 创建action配置, action为各种helm可执行操作的配置,这里是创建基础配置,
// 所有的action内部配置都会引用这个对象
actionConfig := new(action.Configuration)
if err := actionConfig.Init(settings.RESTClientGetter(), settings.Namespace(), os.Getenv("HELM_DRIVER"), log.Printf); err != nil {
log.Printf("%+v", err)
os.Exit(1)
}
// 创建list action 对象,来执行helm list中相关的操作
client := action.NewList(actionConfig)
// Only list deployed
client.Deployed = true
results, err := client.Run()
if err != nil {
log.Printf("%+v", err)
os.Exit(1)
}
for _, rel := range results {
log.Printf("%+v", rel)
}
}
Helm原理分析
helm repo具体做了什么
repo的功能:
-
告诉helm客户端,我有哪些仓库可以连接(仓库url,证书,账号密码,别名)。 -
仓库中有哪些chart包可以获取,对应的版本号是什么。
在settings中存在两个字段:RepositoryCache, RepositoryConfig。RepositoryConfig:解决上述第一个问题,设置一个文件,用于管理配置。RepositoryCache:解决第二个问题,设置一个目录,用来缓存数据。缓存数据包括:
-
安装时,下载的chart.tgz包; -
仓库的索引文件,以index.yaml结尾。
具体可查看自己集群,helm的存储文件。
问题: helm客户端的数据文件使用的是文件进行管理的,并发时势必会产生数据竞争,如何处理?在源码中,helm做的比较简单,在每次操作文件时,先进行文件锁定。这里可以学习到一个新库:github.com/gofrs/flock 。
helm install 具体做了什么
在helm v3时,helm操作的执行全都改成直接操作k8s完成。install的流程如下:
-->i.cfg.KubeClient.IsReachable() // 判断是否能够访问到k8s集群。
--> client, err := c.getKubeClient() // 获取kube client
--> client.ServerVersion() // 通过获取k8s服务端版本来判断是否能够连接
-->i.availableName() // 判断ReleaseName是否有效
--> chartutil.ValidateReleaseName() // 判断字符是否有效
--> i.cfg.Releases.History(start) // 判断是否存在发布历史,!!!这里通过secret进行判断
--> 存在即报错:cannot re-use a name that is still in use
-->chartutil.ProcessDependencies() // 检查chart依赖项。
-->crds := chrt.CRDObjects() // 检查crd对象。
-->i.cfg.getCapabilities() // 获取当前k8s中的GVK,这里的获取,在安装时会产生一个熟悉的报错:
-->chartutil.ToRenderValues() // 通过values 来渲染,得到Values对象,
//后面渲染资源会用到,并且在这会将chart内部的values.yaml与传入的map[string]interface{}进行合并。
-->i.createRelease() // 创建Release对象。
-->i.cfg.renderResources() // 渲染资源,会返回manifest对象
...
--> releaseutil.SortManifests() // 对资源类型进行排序, 所以在安装时候,会按照这个顺序执行。
-->rel.SetStatus(release.StatusPendingInstall, "Initial install underway") // 设置当前状态
-->resources, err := i.cfg.KubeClient.Build() // 创建k8s中的资源对象列表
-->resources.Visit(setMetadataVisitor(rel.Name, rel.Namespace, true)) // 循环遍历,对资源对象进行label,以及annotation的赋值。
-->existingResourceConflict() //是否存在冲突,这里就是上面FAQ中的资源声明错误
-->i.CreateNamespace --> i.cfg.KubeClient.Create() // 创建命名空间,就算存在也不会报错。
-->i.cfg.Releases.Create(rel) // 创建secret, sh.helm.release.v1.releasename.version
...
-->newSecretsObject(key, rls, lbs) // 当我们查看secrets时,base64后也无法查看,是因为这里的压缩设置。
// 会将整个release对象进行json后,再压缩保存。
rChan := make(chan resultMessage)
ctxChan := make(chan resultMessage)
doneChan := make(chan struct{})
defer close(doneChan)
go i.performInstall(rChan, rel, toBeAdopted, resources) // 执行安装协程
go i.handleContext(ctx, ctxChan, doneChan, rel) // 如果超时,则进行结束操作。
select {
case result := <-rChan:
return result.r, result.e
case result := <-ctxChan:
return result.r, result.e
}
i.performInstall执行流程:
-->i.cfg.execHook() // 执行pre-install hook
--> i.cfg.KubeClient.Create() // 执行创建操作
--> i.Wait
--> i.cfg.KubeClient.WaitWithJobs()
--> i.cfg.KubeClient.Wait()
// 以上两个最终调用的是 helm.sh/helm/v3/pkg/kube waiter
--> wait.PollImmediateUntil(2*time.Second, func() (bool, error) {
for _, v := range created {
ready, err := w.c.IsReady(ctx, v)
if !ready || err != nil {
return false, err
}
}
return true, nil
}, ctx.Done())
--> 设置状态
--> i.recordRelease(rel) // 更新secret中的状态
--> i.reportToRun(c, rel, nil) // 报告结束
HELM的不足
helm在使用实际情况下,还是无法适配整个开发周期流程,有以下2个点:
-
无法通过chart的版本号进行版本的回滚。 -
无法使用chart包中其他的values.yaml文件,对于配置管理是十分致命的。 -
每次上传新的chart包,都需要支持helm repo update操作。
所以在此继续上,结合helm进行了2次开发,并运用到部门的升级平台中。
原文始发于微信公众号(小唐云原生):如何理解Helm
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/247535.html