Helm 插件开发与使用全解析
1. Helm 插件概述
Helm 插件具有诸多实用特性,可与现有的 Helm 用户体验实现无缝集成。其中,最显著的特性是每个插件都能为 Helm 提供一个自定义的顶级子命令,这些子命令还能利用 shell 补全功能。
在 Helm 2 中,插件的一个原始特性是会提供连接 Tiller(已弃用的 Helm 服务器端组件)的环境设置。因为涉及 Helm 版本发布的操作都需通过 Tiller 进行,所以这对于需要与 Helm 紧密集成的插件子命令来说至关重要。而在 Helm 3 中,Tiller 已被移除,所有与 Kubernetes API 的通信都由 Helm 客户端自身完成,但插件系统得以保留。
插件安装后,会基于插件名称提供一个新命令,该命令可直接与 Helm 集成,甚至会显示在
helm help
中。例如,安装名为
inspect-templates
的插件后,会提供额外的 Helm 命令
helm inspect-templates [args]
,执行该命令时,会将提供的任何参数或标志传递给插件执行的底层工具。
2. 构建 Helm 插件
构建 Helm 插件是一个相对直接的过程,不过根据插件的要求和整体复杂度,可能需要一些编程知识,不过许多插件仅运行基本的 shell 命令。
2.1 底层实现
以
inspect-templates
插件为例,其底层实现是一个 Bash 脚本
inspect-templates.sh
,代码如下:
#!/usr/bin/env bash
set -e
# First argument on the command line, a relative path to a chart directory
CHART_DIRECTORY="${1}"
# Fail if no chart directory provided or is invalid
if [[ "${CHART_DIRECTORY}" == "" ]]; then
echo "Usage: helm inspect-templates <chart_directory>"
exit 1
elif [[ ! -d "${CHART_DIRECTORY}" ]]; then
echo "Invalid chart directory provided: ${CHART_DIRECTORY}"
exit 1
fi
# Print a summary of the chart's templates
cd "${CHART_DIRECTORY}"
cd templates/
echo "----------------------"
echo "Chart template summary"
echo "----------------------"
echo ""
total="$(find . -type f -name '*.yaml' -maxdepth 1 | wc -l | tr -d '[:space:]')"
echo " Total number: ${total}"
echo ""
echo " List of templates:"
for filename in $(find . -type f -name '*.yaml' -maxdepth 1 | sed 's|^\./||'); do
kind=$(cat "${filename}" | grep kind: | head -1 | awk '{print $2}')
echo " - ${filename} (${kind})"
done
echo ""
当用户运行
helm inspect-templates
时,Helm 会在后台执行此脚本。需要注意的是,插件的底层实现不要求使用特定的编程语言,对于插件的最终用户来说,它应看起来就像是 Helm CLI 的另一部分。
2.2 插件清单
每个插件由一个名为
plugin.yaml
的 YAML 文件定义,该文件包含插件元数据以及插件调用时要运行的命令信息。以下是
inspect-templates
插件的基本
plugin.yaml
示例:
name: inspect-templates
version: 0.1.0
description: get a summary of a chart's templates
command: "${HELM_PLUGIN_DIR}/inspect-templates.sh"
各字段含义如下:
-
name
:插件名称。
-
version
:插件版本。
-
description
:插件的基本描述。
-
command
:插件调用时要运行的命令。
2.3 手动安装
手动安装插件的步骤如下:
1. 检查插件存储根目录的配置路径:
$ HELM_PLUGINS="$(helm env HELM_PLUGINS)"
$ echo "${HELM_PLUGINS}"
/home/myuser/.local/share/helm/plugins
可以通过在当前环境中为
HELM_PLUGINS
环境变量提供自定义路径来覆盖插件的根目录。
2. 在插件存储根目录内创建与插件名称匹配的目录:
$ PLUGIN_ROOT="${HELM_PLUGINS}/inspect-templates"
$ mkdir -p "${PLUGIN_ROOT}"
-
将
plugin.yaml和inspect-templates.sh复制到新目录,并确保脚本可执行:
$ cp plugin.yaml "${PLUGIN_ROOT}"
$ cp inspect-templates.sh "${PLUGIN_ROOT}"
$ chmod +x "${PLUGIN_ROOT}/inspect-templates.sh"
2.4 插件运行示例
以下是
inspect-templates
插件的运行示例:
$ helm inspect-templates
Usage: helm inspect-templates <chart_directory>
Error: plugin "inspect-templates" exited with error
$ helm inspect-templates nonexistant/
Invalid chart directory provided: nonexistant/
Error: plugin "inspect-templates" exited with error
$ helm create mychart
Creating mychart
$ helm inspect-templates mychart/
----------------------
Chart template summary
----------------------
Total number: 5
List of templates:
- serviceaccount.yaml (ServiceAccount)
- deployment.yaml (Deployment)
- service.yaml (Service)
- hpa.yaml (HorizontalPodAutoscaler)
- ingress.yaml (Ingress)
可以看到,提供的命令行参数(如
mychart/
)会直接传递给脚本,这使得插件作者可以轻松构建接受任意数量参数或自定义标志的独立工具。
3. plugin.yaml 详解
plugin.yaml
是描述插件、其调用命令和其他重要细节的插件清单文件。以下是一个包含所有可能选项的
plugin.yaml
示例:
name: myplugin
version: 0.3.0
usage: "helm myplugin --help"
description: "a plugin that belongs to me"
platformCommand:
- os: windows
arch: amd64
command: "bin/myplugin.exe"
command: "bin/myplugin"
ignoreFlags: false
hooks:
install: "scripts/install-hook.sh"
update: "scripts/update-hook.sh"
delete: "scripts/delete-hook.sh"
downloaders:
- command: "bin/myplugin-myp-downloader"
protocols:
- "myp"
- "myps"
各字段含义如下:
| 字段 | 含义 |
| ---- | ---- |
|
name
| 插件名称,将作为从 Helm CLI 调用此插件的子命令,不能与现有的 Helm 子命令(如
install
、
repo
等)匹配,只能包含字符
a–z
、
A–Z
、
0–9
、
_
和
-
。 |
|
version
| 插件版本,应为有效的 SemVer 2 版本。 |
|
usage
| 此插件的使用说明。 |
|
description
| 插件的描述。 |
|
platformCommand
| 特定平台的命令,如果客户端的
os/arch
组合匹配,则运行该命令而不是默认命令。 |
|
command
| 插件调用时要运行的命令。 |
|
ignoreFlags
| 是否抑制传递给插件的 Helm 全局标志(如
--debug
)。 |
|
hooks
| 插件钩子,包括安装、更新和删除时要运行的脚本。 |
|
downloaders
| 下载器及其关联的协议。 |
Helm 根据
plugin.yaml
的内容和运行时环境确定插件调用时要运行的命令的顺序如下:
1. 如果存在
platformCommand
,则首先搜索它。
2. 如果
os
和
arch
都与当前平台匹配,则停止搜索并执行特定平台的命令。
3. 如果
os
匹配但没有更精确的匹配,则执行特定平台的命令。
4. 如果未找到
os/arch
匹配,则执行默认的顶级命令。
5. 如果没有顶级命令且在
platformCommand
中未找到匹配项,Helm 将报错退出。
4. 插件钩子
插件钩子允许在插件安装、更新或删除时执行额外操作。例如,插件的底层实现可能是一个需要从互联网下载的特定平台二进制文件,其下载 URL 会根据用户的操作系统而变化。以下是一个根据操作系统处理此逻辑的脚本示例:
#!/usr/bin/env bash
set -e
URL=""
EXTRACT_TO=""
if [[ "$(uname)" = "Darwin" ]]; then
URL="https://example.com/releases/myplugin-mac"
EXTRACT_TO="myplugin"
elif [[ "$(uname)" = "Linux" ]]; then
URL="https://example.com/releases/myplugin-linux"
EXTRACT_TO="myplugin"
else
URL="https://example.com/releases/myplugin-windows"
EXTRACT_TO="myplugin.exe"
fi
mkdir -p bin/
curl -sSL "${URL}" -o "bin/${EXTRACT_TO}"
要定义钩子,可在
plugin.yaml
中添加
hooks
部分,为每个要响应的事件定义命令:
...
hooks:
install: "scripts/install-hook.sh"
update: "scripts/update-hook.sh"
delete: "scripts/delete-hook.sh"
5. 下载器插件
有些插件具有特殊功能,可作为下载图表的替代方法。这在以不同于纯图表仓库的方式存储图表,或者图表仓库实现有额外要求时非常有用。
下载器插件定义一个或多个协议,如果在命令行中检测到这些协议,Helm 将使用该插件而不是其内部下载机制来下载
index.yaml
或图表
.tgz
包。以下是一个名为 “super-secure” 的下载器插件的
plugin.yaml
示例,它注册了
ss://
协议:
name: super-secure
version: 0.1.0
description: a super secure chart downloader
command: "${HELM_PLUGIN_DIR}/super-secure.sh"
downloaders:
- command: "super-secure-downloader.sh"
protocols:
- "ss"
下载器命令始终使用以下参数调用:
<command> certFile keyFile caFile full-URL
,其中
certFile
、
keyFile
和
caFile
参数来自 YAML 配置文件中的条目,该文件的路径由
$(helm env HELM_REPOSITORY_CONFIG)
返回,在使用
helm repo add
添加仓库时设置;
full-URL
参数是要下载的资源的完整 URL,可能是
index.yaml
或图表
.tgz/.prov
文件。
以下是 “super-secure” 插件定义的
ss://
协议下载器的实现:
#!/usr/bin/env bash
set -e
# The fourth argument is the URL to the resource to download from the repo
URL="${4}"
# Replace "ss://" with "https://"
URL="$(echo ${URL} | sed 's/ss:/https:/')"
# Request the resource using the token, outputting contents to stdout
echo "Downloading $(basename ${URL}) using super-secure plugin..." 1>&2
curl -sL -H "Authorization: Bearer ${SUPER_SECURE_TOKEN}" "${URL}"
该下载器允许使用受令牌/持有者身份验证保护的图表仓库,它期望设置环境变量
SUPER_SECURE_TOKEN
,该变量将用于在从图表仓库请求资源时构造
Authorization: Bearer <token>
头。
安装此插件后,添加受令牌身份验证保护的图表仓库的步骤如下:
$ export SUPER_SECURE_TOKEN="abc123"
$ helm repo add my-secure-repo ss://secure.example.com
Downloading index.yaml using super-secure plugin...
"my-secure-repo" has been added to your repositories
此时,该仓库 URL 将显示在本地仓库列表中:
$ helm repo list
NAME URL
my-secure-repo ss://secure.example.com
然后可以像使用其他仓库一样使用该仓库下载远程图表包:
$ export SUPER_SECURE_TOKEN="abc123"
$ helm pull my-secure-repo/superapp
Downloading superapp-0.1.0.tgz using super-secure plugin...
$ ls
superapp-0.1.0.tgz
6. 执行环境
由于插件旨在扩展 Helm 的功能,它们可能需要访问 Helm 的一些内部配置文件或命令行上提供的全局标志。为了让插件能够访问此类信息,在运行时会为插件提供一系列已知的环境变量,按字母顺序列出如下:
| 环境变量 | 含义 |
| ---- | ---- |
|
HELM_BIN
| 正在执行的 Helm 命令的路径 |
|
HELM_DEBUG
| 全局布尔
--debug
选项的值(“true” 或 “false”) |
|
HELM_KUBECONTEXT
| 全局
--kube-context <context>
选项的值 |
|
HELM_NAMESPACE
| 全局
--namespace <namespace>
选项的值 |
|
HELM_PLUGIN_DIR
| 当前插件的根目录 |
|
HELM_PLUGIN_NAME
| 当前插件的名称 |
|
HELM_PLUGINS
| 包含所有插件的顶级目录 |
|
HELM_REGISTRY_CONFIG
| 注册表配置的根目录 |
|
HELM_REPOSITORY_CACHE
| 仓库缓存的根目录 |
|
HELM_REPOSITORY_CONFIG
| 仓库配置的根目录 |
7. 外壳补全
Helm 为 Bash 和 Z shell(Zsh)提供了内置的 shell 自动补全支持(可查看
helm completion --help
),这在记不起要使用的子命令或标志名称时非常有用。插件也可以通过两种方法提供自己的自定义 shell 补全:静态自动补全和动态补全。
7.1 静态自动补全
通过在插件目录的根目录中包含一个名为
completion.yaml
的文件,Helm 插件可以静态指定插件的所有预期标志和命令。以下是一个虚构的 “zoo” 插件的
completion.yaml
示例:
name: zoo
flags:
- disable-smells
- disable-snacks
commands:
- name: price
flags:
- kids-discount
- name: animals
commands:
- name: list
validArgs:
- birds
- reptiles
- cats
- name: describe
flags:
- format-json
validArgs:
- birds
- reptiles
- cats
各字段含义如下:
| 字段 | 含义 |
| ---- | ---- |
|
name
| 此补全文件所属的插件名称 |
|
flags
| 可用标志列表(注意:不应包含
-
或
--
前缀) |
|
commands
| 可用子命令列表 |
|
name
(子命令下) | 单个子命令的名称 |
|
validArgs
| 子命令后面第一个参数的有效选项列表 |
在顶级
commands
部分下,可以为嵌套子命令指定另一个
commands
部分(可根据需要递归指定多次)。
commands
部分中的每个命令都可以包含自己的标志和
validArgs
列表。Helm 的全局标志(如
--debug
或
--namespace
)已由 Helm 的内置 shell 补全处理,因此无需在
flags
下列出。
例如,尝试运行 “zoo” 插件,按下 Tab 键,将显示所有可用的子命令:
$ helm zoo # (click tab)
animals price
如果在按下 Tab 键之前添加
--disable-s
后缀,则会显示相应的标志:
$ helm zoo --disables-s # (click tab)
--disable-smells --disable-snacks
使用静态补全,我们可以实现与 Helm 现有 shell 补全相同的效果,使插件与 Helm 用户体验更加紧密集成。
如果正在开发插件,需要打开一个新的终端窗口才能刷新静态 shell 补全。或者,可以运行以下命令之一在当前终端中获取最新的补全:
source <(helm completion bash) # for Bash
source <(helm completion zsh) # for Z shell
7.2 动态补全
在某些情况下,给定命令的有效参数可能事先未知。例如,可能希望将集群中的 Helm 版本名称列表作为插件的有效参数。这可以通过动态补全来实现。
要启用动态补全,需在插件目录的根目录中包含一个名为
plugin.complete
的可执行文件,该文件可以是任何类型的可执行文件,如 shell 脚本或二进制文件。
对于包含
plugin.complete
文件的插件,当请求补全时(即按下 Tab 键),Helm 将运行此可执行文件,并将需要补全的文本作为第一个参数传递。该程序应返回一个可能结果的列表,每个结果用换行符分隔,并成功退出(即返回代码为 0)。
例如,可以将此补全功能作为主插件程序的一部分提供,使用一个简单的包装脚本通过标志(如
--complete
)触发它。以下是一个基本的
plugin.complete
可执行文件示例:
#!/usr/bin/env sh
$HELM_PLUGIN_DIR/my-plugin-program --complete "$@"
继续以 “zoo” 插件为例,假设可用动物类别的列表不断变化,并存储在用户主目录中的
animals.txt
文件中,文件内容可能如下:
birds
reptiles
cats
以下是一个可用于提供动态补全的
plugin.complete
可执行文件(Bash 脚本)示例:
#!/usr/bin/env bash
set -e
INPUT="${@}"
if [[ "${INPUT}" == "animals list"* ]]; then
INPUT="$(echo "${INPUT}" | sed -e 's/^animals list //')"
for flag in $(cat "${HOME}/animals.txt"); do
# 后续代码可根据需求添加
done
fi
综上所述,Helm 插件为扩展 Helm 功能提供了强大而灵活的方式,通过合理利用插件的各种特性,可以大大提升 Helm 的使用效率和功能扩展性。无论是静态补全还是动态补全,都能为用户提供更好的操作体验,而下载器插件则为处理特殊的图表仓库提供了有效的解决方案。在开发和使用 Helm 插件时,需要深入理解各个组件的作用和配置方法,以充分发挥其优势。
Helm 插件开发与使用全解析
8. 总结与实践建议
Helm 插件为 Helm 用户提供了强大的扩展能力,通过自定义子命令、下载器插件、钩子等功能,可以满足各种复杂的使用场景。以下是一些实践建议:
-
插件开发
:在开发插件时,要充分考虑插件的通用性和可维护性。尽量使用标准的编程语言和工具,确保插件在不同环境下都能正常运行。同时,要详细编写
plugin.yaml
文件,明确插件的各项配置和使用说明。
-
插件安装与管理
:手动安装插件时,要严格按照步骤操作,确保插件文件的正确复制和权限设置。在使用下载器插件时,要注意环境变量的设置和协议的匹配。
-
补全功能
:合理利用静态补全和动态补全功能,提高命令输入的效率。在开发插件时,根据插件的特点选择合适的补全方式。
9. Helm 插件开发流程总结
为了更清晰地展示 Helm 插件的开发流程,下面用 mermaid 流程图进行说明:
graph LR
classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px;
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
classDef decision fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px;
A([开始开发]):::startend --> B(确定插件功能):::process
B --> C(编写底层实现代码):::process
C --> D(创建 plugin.yaml 文件):::process
D --> E{是否需要钩子?}:::decision
E -->|是| F(编写钩子脚本):::process
E -->|否| G{是否为下载器插件?}:::decision
F --> G
G -->|是| H(编写下载器脚本):::process
G -->|否| I(考虑补全功能):::process
H --> I
I --> J{选择补全方式}:::decision
J -->|静态补全| K(编写 completion.yaml 文件):::process
J -->|动态补全| L(编写 plugin.complete 文件):::process
K --> M(手动安装插件):::process
L --> M
M --> N([测试插件功能]):::startend
10. 常见问题及解决方案
在开发和使用 Helm 插件过程中,可能会遇到一些常见问题,以下是部分问题及解决方案:
| 问题描述 | 可能原因 | 解决方案 |
| ---- | ---- | ---- |
| 插件无法执行 | 脚本权限不足或
plugin.yaml
配置错误 | 检查脚本权限,使用
chmod +x
命令添加执行权限;检查
plugin.yaml
中的命令配置是否正确。 |
| 下载器插件无法下载资源 | 环境变量未设置或协议不匹配 | 确保环境变量正确设置,检查
plugin.yaml
中定义的协议是否与实际使用的协议一致。 |
| 补全功能不生效 | 静态补全文件未正确配置或动态补全脚本有错误 | 检查
completion.yaml
文件是否正确编写,或检查
plugin.complete
脚本的逻辑和返回值。 |
11. Helms 插件的未来展望
随着 Kubernetes 和 Helm 的不断发展,Helm 插件也将迎来更多的发展机遇。未来,Helm 插件可能会在以下方面得到进一步提升:
-
安全性增强
:提供更完善的安全机制,确保插件在运行过程中的安全性,防止恶意插件的攻击。
-
性能优化
:优化插件的执行效率,减少插件运行时的资源消耗,提高 Helm 的整体性能。
-
生态系统丰富
:更多的开发者将参与到 Helm 插件的开发中,丰富插件的种类和功能,满足更多用户的需求。
12. 结语
Helm 插件为 Helm 用户提供了丰富的扩展能力,通过自定义子命令、下载器插件、钩子和补全功能等,可以实现各种复杂的操作和功能。在开发和使用 Helm 插件时,要深入理解插件的各个组成部分,严格按照操作步骤进行,同时关注常见问题的解决方案。希望本文能帮助你更好地掌握 Helm 插件的开发和使用,提升 Kubernetes 应用部署和管理的效率。
如果你在实际使用过程中遇到任何问题,欢迎在相关社区进行交流和讨论,共同推动 Helm 插件生态的发展。
超级会员免费看
19

被折叠的 条评论
为什么被折叠?



