玩转 Helm


0. 前言

在 kubernetes 的系列文章中,我们介绍了 kubernetes 的种种概念,特性。不过对于如何部署并没有介绍,想象下如果 kubernetes 中 pod 的数量达到成百,上千,上万的话,如何对 pod 进行有效管理就成了迫在眉睫的大事。

因此,Helm 应运而生,Helm 是 Kubernetes 的包管理器,它以 chart 的方式组织,部署 pod,达到统一管理的目的。

1. Helm 架构

在 Helm3 中,Helm 结构分为 client 和 library。client 是命令行客户端,负责:

  • 本地 chart 开发
  • 管理仓库
  • 管理发布
  • 和 library 建立接口:发送安装的 chart 和发送升级或卸载现有 release 请求。

library 提供执行所有 Helm 操作的逻辑,与 Kubernetes API 服务交互提供以下功能:

  • 结合 chart 和配置构建 release
  • 将 chart 安装到 Kubernetes 中,并提供后续 Release 对象
  • 与 Kubernetes 交互升级和卸载 Release

注:这是 Helm3 的架构,在 Helm2 中还有 Tiller 组件,为何在 Helm3 中移除 Tiller 可参考 这里

2. 使用 Helm

2.1 Helm 三大概念

Chart 代表着 Helm 包。它包含在 Kubernetes 集群内部运行应用程序,工具或服务所需的所有资源定义。

Repository 是用来存放和共享 charts 的地方。

Release 是运行在 Kubernetes 集群中的 chart 的实例。一个 chart 通常可以在同一个集群中安装多次。每一次安装都会创建一个新的 release。

可以这样解释 Helm:Helm 安装 charts 到 Kubernetes 集群中,每次安装都会创建一个新的 release。

2.2 快速实践 Helm

2.2.1 安装 helm chart

Helm 的 charts 有两个来源,一个是官方自带的 Artifact Hub, 一个是用户自建 repo。

可以通过 search 命令从这两个来源搜索 charts:

// helm search hub
$ helm search hub wordpress
URL                                                     CHART VERSION   APP VERSION             DESCRIPTION                                 
https://artifacthub.io/packages/helm/kube-wordp...      0.1.0           1.1                     this is my wordpress package                
...

// helm search repo
$ helm repo list
Error: no repositories to show

$ helm repo add kube-wordpress https://harsh-del.github.io/wordpress-charts/charts/
"kube-wordpress" has been added to your repositories

$ helm repo list
NAME            URL
kube-wordpress  https://harsh-del.github.io/wordpress-charts/charts/

$ helm search repo wordpress
NAME                            CHART VERSION   APP VERSION     DESCRIPTION
kube-wordpress/wordpress        0.1             1.1             this is my wordpress package

helm search 基于模糊匹配识别字符串,因此不需要指定全名。

search 到 charts 后,通过 helm install 安装 charts:

helm install my-wordpress kube-wordpress/wordpress --version 0.1.0

helm install 可以从多个来源安装 charts:

  • chart 的仓库(如上所述)
  • 本地 chart 压缩包(helm install foo foo-0.1.1.tgz)
  • 解压后的 chart 目录(helm install foo path/to/foo)
  • 完整的 URL(helm install foo https://example.com/charts/foo-1.2.3.tgz)

需要注意的是,helm install 安装的资源是有顺序的,顺序定义在 InstallOrder

当然,也可以直接使用 helm create 创建一个模板 chart,通常开发人员会基于模板 chart 自定义应用 charts:

$ helm create demo
Creating demo

$ ls
demo

2.2.2 验证 helm chart

在安装 chart 部署应用的时候往往会验证 chart 是否完整可用。

使用 helm lint 验证 chart 是否可用:

$ ls
Chart.yaml  charts  templates  values.yaml

$ helm lint
==> Linting .
[INFO] Chart.yaml: icon is recommended

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

使用 helm template 可对 chart 模板进行渲染,并且查看渲染结果:

$ helm template demo -f ./values.yaml --dry-run --debug
install.go:173: [debug] Original chart version: ""
Error: non-absolute URLs should be in form of repo_name/path_to_chart, got: demo

使用 helm install 的 --dry-run 和 --debug 选项可查看预安装情况:

$ helm install my-wordpress kube-wordpress/wordpress --version 0.1.0 --dry-run --debug
install.go:173: [debug] Original chart version: "0.1.0"
install.go:190: [debug] CHART PATH: /var/home/core/.cache/helm/repository/wordpress-0.1.tgz

NAME: my-wordpress
LAST DEPLOYED: Sun Apr 24 08:36:04 2022
NAMESPACE: ci1
STATUS: pending-install
REVISION: 1
TEST SUITE: None
USER-SUPPLIED VALUES:
...

除了上述验证 chart 命令外,也可以通过 helm unittest 验证 helm chart 文件是否符合 ut 要求,更多信息可参考这里

2.2.3 测试 Release

helm install 安装完,Helm 会以 Release 的形式呈现整个资源部署情况。

可以通过 helm status [Release name] 查看资源部署情况:

$ helm status demo
NAME: demo
LAST DEPLOYED: Sun Apr 24 08:47:14 2022
NAMESPACE: ci1
STATUS: deployed
REVISION: 1
TEST SUITE:     demo-test-connection
Last Started:   Sun Apr 24 08:47:59 2022
Last Completed: Mon Jan  1 00:00:00 0001
Phase:          Running
NOTES:
...

可以看到资源是 deployed 状态,注意 deployed 状态并不表示 pod 是 running 的(只表示消息发给 Kubernetes 正确执行了)。

值得一提的是 TEST SUITE,这里的 test suite 定义是轻量级的测试单元,负责测试部署应用的运行状态,连通性等等。可通过 helm test 执行该测试单元:

$ helm test demo
helmNAME: demo
LAST DEPLOYED: Sun Apr 24 08:47:14 2022
NAMESPACE: ci1
STATUS: deployed
REVISION: 1
TEST SUITE:     demo-test-connection
Last Started:   Sun Apr 24 08:47:59 2022
Last Completed: Sun Apr 24 08:52:59 2022
...

注意,该测试单元在 helm install 时并不会执行。

2.2.4 show chart 和 Release 信息

通过 helm show 和 helm get 命令可获取 chart 和 Release 的信息。这在获取配置文件时是有用的。

仅以 Release 举例:

$ helm get values demo
USER-SUPPLIED VALUES:
null

$ helm get manifest demo
---
# Source: demo/templates/serviceaccount.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: demo
  labels:
    helm.sh/chart: demo-0.1.0
    app.kubernetes.io/name: demo
    app.kubernetes.io/instance: demo
    app.kubernetes.io/version: "1.16.0"
    app.kubernetes.io/managed-by: Helm
---
...

2.3 helm 升降级

除了 helm install 安装 Release 外,还有 helm ugprade 和 helm rollback 可对 Release 进行升降级。

其中,helm upgrade 使用 三路策略 保证升降级的完整性。

在升级过程中使用的是最小侵入式升级策略,保证只升级改动资源。

3. helm client 简要实现

由前描述可知,helm client 调用 helm library 实现 chart 资源的创建。在应用开发过程中,可调用 helm 接口实现 helm client 的简要实现。

这里使用 helm 的 action 接口实现 2.2.4 节 helm get Release 信息的功能。

3.1 解析 kubeconfig 实现 Helm 到 Kubernetes 认证鉴权

func TransferKubeConfigToBase64(kubeconfigPath string) (string, error) {
	if _, err := os.Stat(kubeconfigPath); os.IsNotExist(err) {
		return "", err
	}

	kubeconfigBytes, err := ioutil.ReadFile(kubeconfigPath)
	if err != nil {
		return "", err
	}

	return base64.StdEncoding.EncodeToString(kubeconfigBytes), nil
}

定义 TransferKubeConfigToBase64 函数实现 kubeconfig 文件的解析。kubeconfig 包含 kubernetes 的认证,鉴权信息,如 API server,用户名,密码,namespace 等。

3.2 根据 kubeconfig 创建 helm client

options := helmclient.NewOptions(kubeConfig)
client, err := helmclient.NewHelmClient(&options)
if err != nil {
	return err
}

其中 NewOptions 函数和 Options 结构体定义如下:

func NewOptions(kubeConfig string) Options {
	return Options{
		KubeConfig: kubeConfig,
		Log:        logging.NewLogger().Infof,
		Namespace:  config.ResourceConfig.Namespace,
	}
}

// Options defines the options for helm client's configuration
type Options struct {
	RepositoryConfigPath string
	RepositoryCachePath  string
	Debug                bool
	KubeConfig           string
	Namespace            string
	Log                  action.DebugLog
}

重点在于 NewHelmClient

// New returns a new Helm client with the provided options
func NewHelmClient(options *Options) (Client, error) {

	kubeConfig, err := base64.StdEncoding.DecodeString(options.KubeConfig)
	if err != nil {
		return nil, fmt.Errorf("decode kubeconfig failed: %w", err)
	}

	clientGetter, err := NewRESTClientGetter(kubeConfig)
	if err != nil {
		return nil, fmt.Errorf("new rest client getter failed: %w", err)
	}

	ns, _, err := clientGetter.ToRawKubeConfigLoader().Namespace()
	if err != nil {
		return nil, fmt.Errorf("get namespace from KubeConfig fail: %w", err)
	}

	// Helm does not expose Namespace property, it has to be configured in this
	// environment way.
	ns = options.Namespace

	if err := os.Setenv("HELM_NAMESPACE", ns); err != nil {
		return nil, fmt.Errorf("setting namespace fail, %w", err)
	}

	settings := cli.New()
	setEnvSettings(options, settings)

	actionConfig := new(action.Configuration)
	err = actionConfig.Init(
		clientGetter,
		settings.Namespace(),
		os.Getenv("HELM_DRIVER"),
		options.Log,
	)
	if err != nil {
		return nil, err
	}

	return &client{
		Settings:     settings,
		ActionConfig: actionConfig,
	}, nil
}

关于代码详细实现可参考 这里, 具体不再展开。

3.3. 调用 helm library 接口实现 helm client

3.3.1 实现 helm list

client 调用 action 包的 NewList 创建 list 对象,并且调用对象的 Run 方法实现 helm list:

import (
	"helm.sh/helm/v3/pkg/action"
	"helm.sh/helm/v3/pkg/cli"
	"helm.sh/helm/v3/pkg/release"
)

releases, err := client.List()
if err != nil {
	return err
}

// List is to get the release name in specific namespace
// same as "helm list -n [namespace]"
func (c *client) List() ([]*release.Release, error) {
	list := action.NewList(c.ActionConfig)
	return list.Run()
}

3.3.2 实现 helm get values

values, err := client.GetValues(name)
if err != nil {
	return err
}

func (c *client) GetValues(name string) (map[string]interface{}, error) {
	getValues := action.NewGetValues(c.ActionConfig)
	return getValues.Run(name)
}

至此我们开发了 helm client 的简易基本功能。

4. 总结

最大的感受是想玩好 Helm 并不是那么容易的,如果我们想深入理解的话,还是有不少内容可以挖的。比如 Helm 怎么实现 chart 到 manifest 的解析,模糊匹配怎么做到的,怎么实现
最小倾入式升级,都是可以深挖的点。

当然,关于 helm 的使用及日常开发的最佳实践还是 cover 到一点的,详细内容可参考 Helm 官网


posted @ 2022-04-24 23:12  lubanseven  阅读(1286)  评论(0编辑  收藏  举报