1. 介绍
Helm 是 Kubernetes 的包管理工具,其部署单元是 Chart。与大多数包管理器类似,Helm 也支持 Chart 之间的依赖管理。虽然 Helm 支持手动列出依赖关系,但它 没有提供直接查看已安装 Chart(即 Release)依赖树的功能。
在本教程中,我们将探索 Helm 中依赖项的枚举与解析机制:
- 首先回顾 Chart 依赖的基本概念
- 接着使用 Helm 原生命令列出 Chart 依赖
- 然后通过 Shell 脚本实现列出已安装 Release 的依赖
- 最后演示一个支持递归列出依赖的脚本
本文的代码在 Debian 12(Bookworm)系统中测试,使用 GNU Bash 5.2.15 和 Helm 3.14。除非特别说明,这些命令也适用于大多数 POSIX 兼容环境。
2. Chart 依赖简介
即使是最基础的 Kubernetes 部署,也由多个组件构成。
例如,一个空的 Kubernetes 集群 依然运行多个 Pod:
$ kubectl get all --namespace=kube-system
NAME READY STATUS RESTARTS AGE
pod/coredns-5dd0666b68-lp7b5 1/1 Running 1 9d
pod/etcd-xost 1/1 Running 1 9d
pod/kube-apiserver-xost 1/1 Running 1 9d
pod/kube-controller-manager-xost 1/1 Running 1 9d
pod/kube-proxy-tldfh 1/1 Running 1 9d
pod/kube-scheduler-xost 1/1 Running 1 9d
pod/storage-provisioner 1/1 Running 1 (6d22h ago) 9d
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,9153/TCP 9d
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
daemonset.apps/kube-proxy 1 1 1 1 1 kubernetes.io/os=linux 9d
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/coredns 1/1 1 1 9d
NAME DESIRED CURRENT READY AGE
replicaset.apps/coredns-5dd0666b68 1 1 1 9d
同样,Helm 安装的 Chart 通常也会生成包含多个 Pod 和资源的 Release:
$ helm install gabe565/nightscout --generate-name --create-namespace --namespace nightscout
[...]
$ kubectl get all --namespace nightscout
NAME READY STATUS RESTARTS AGE
pod/nightscout-1709766626-f7d430108-tzp8j 1/1 Running 0 49s
pod/nightscout-1709766626-mongodb-0 1/1 Running 0 49s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/nightscout-1709766626 ClusterIP 10.105.224.56 <none> 1337/TCP 49s
service/nightscout-1709766626-mongodb ClusterIP 10.101.52.236 <none> 27017/TCP 49s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/nightscout-1709766626 1/1 1 1 49s
NAME DESIRED CURRENT READY AGE
replicaset.apps/nightscout-1709766626-f7d430108 1 1 1 49s
NAME READY AGE
statefulset.apps/nightscout-1709766626-mongodb 1/1 49s
由于这些自然的资源树结构,Helm 官方支持依赖管理机制。例如,一个依赖 Chart 可以通过名称、版本和 URL 被嵌入到主 Chart 的元数据中。
需要注意的是,语法在 Helm 不同版本中略有不同:
- Helm 2 使用
requirements.yaml
- Helm 3 将依赖信息整合进
Chart.yaml
但无论哪种方式,依赖解析机制是相同的。
3. 列出 Chart 依赖
Helm 提供了 dependency
子命令用于列出 Chart 的依赖。
不过,不同于其他包管理器,Helm 并不支持直接列出已安装或远程 Chart 的依赖树。
要使用该功能,我们需要先下载并解压 Chart:
$ helm pull gabe565/ascii-movie --untar
也可以指定版本:
$ helm pull gabe565/ascii-movie --version 0.0.3 --untar
进入解压目录后,可以看到 Chart.yaml
和 charts/
目录:
$ cd ascii-movie
$ ls
Chart.lock charts Chart.yaml README.md templates values.yaml
然后运行 Helm 命令列出依赖:
$ helm dependency list
NAME VERSION REPOSITORY STATUS
common 1.5.1 https://bjw-s.github.io/helm-charts unpacked
说明该 Chart 依赖一个名为 common
的 Chart。
我们可以将这个过程封装成一条命令:
$ helm pull <CHART> --untar && helm dependency list ./<CHART_NAME> && rm -rf <CHART_NAME>
其中:
<CHART>
可以是任何支持的 Chart 源格式(如 repo 名、OCI 地址等)<CHART_NAME>
是 Chart 名,通常与解压后的目录名一致
4. 查看已安装 Chart 的依赖
虽然 Helm 本身不支持查看已安装 Chart 的依赖,但我们可以通过 Release 信息反推出来。
先查看目标 Release 的信息:
$ helm list nightscout-1709766626
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
nightscout-1709766626 nightscout 1 2024-03-08 03:08:24.619666646 -0500 EST deployed nightscout-0.10.0 15.0.2
得知该 Release 是由 nightscout-0.10.0
Chart 安装而来。
接下来通过 Helm 命令列出所有匹配的 Chart:
$ helm list --filter nightscout --all-namespaces
NAME CHART VERSION APP VERSION DESCRIPTION
gabe565/nightscout 0.10.0 15.0.2 Web-based CGM (Continuous Glucose Monitor) to a...
这时,我们可以使用之前的方法:
$ helm pull gabe565/nightscout --untar && helm dependency list ./nightscout && rm -rf nightscout
NAME VERSION REPOSITORY STATUS
common 1.5.1 https://bjw-s.github.io/helm-charts unpacked
mongodb 14.5.1 https://charts.bitnami.com/bitnami unpacked
如果本地没有配置该仓库,也可以使用 OCI 地址:
$ helm pull oci://ghcr.io/gabe565/charts/nightscout --untar && helm dependency list ./nightscout && rm -rf nightscout
⚠️ 注意:这种方式只能列出一级依赖,无法展示完整的依赖树。
5. 自动化列出已安装 Chart 的依赖
如果我们满足以下前提条件,就可以实现自动化列出依赖:
- Chart 仓库已配置或 Chart 来自 Artifact Hub
- Chart 标识符格式为
name-version
- Chart 依赖无循环
5.1 初始化脚本
#!/usr/bin/env bash
release_filter=$1
multilevel=$2
# 全局数组,用于保存待处理的 Chart 标识符
charts=()
5.2 Chart 依赖处理函数
function chart_deps() {
[ ${#charts[@]} -eq 0 ] && return
local chart_identifier="${charts[0]}"
local chart_name chart_version repo_url
local deps
IFS=- read chart_name chart_version repo_url <<< "$chart_identifier"
printf 'Processing %s from %s ...\n' $chart_name $repo_url
if [[ $repo_url =~ 'oci://' ]]; then
helm pull $repo_url --version $chart_version --untar >/dev/null 2>&1
else
helm pull $chart_name --repo $repo_url --version $chart_version --untar >/dev/null 2>&1
fi
if [ $? -ne 0 ]; then
printf 'Unable to pull %s from %s.\n\n' $chart_name $repo_url
return
fi
deps="$(helm dependency list ./$chart_name)"
printf '%s deps:\n%s\n\n' "$chart_name-$chart_version" "$deps"
if [ -n "$deps" ] && [ -n "$multilevel" ]; then
charts+=($(echo "$deps" | awk 'NR > 1 { print $1"-"$2"-"$3; }'))
fi
rm -rf $chart_name
rm -rf $chart_name-$chart_version.tgz
}
5.3 主流程
# 获取匹配的 Release 数量
releases="$(helm list --filter $release_filter --all-namespaces --no-headers | wc --lines)"
if [ $releases -ne 1 ]; then
>&2 printf 'No or multiple release matches: --filter %s.' $release_filter
exit 1
fi
# 获取 Chart 标识符
chart_identifier="$(helm list --filter $release_filter --all-namespaces --output=yaml | awk '/chart:/ { print $2; }')"
IFS=- read chart_name chart_version <<< "$chart_identifier"
# 获取仓库 URL
chart_path="$(helm search repo $chart_name --version $chart_version --output yaml | grep 'version: '$chart_version -B 1 | awk '/name:/ { print $2; }')"
if [ -n "$chart_path" ]; then
IFS=/ read repo_name chart_name <<< "$chart_path"
repo_url="$(helm repo list | awk '/'$repo_name'/ { print $2; }')"
else
repo_url="$(helm search hub $chart_name --output yaml | grep 'version: '$chart_version -B 2 | awk 'NR == 1 && /url:/ { print $2; }')"
fi
if [ -z "$repo_url" ]; then
>&2 printf 'Repository not found for release chart %s version %s.' $chart_name $chart_version
exit 1
fi
chart_identifier=$chart_identifier-$repo_url
charts+=("$chart_identifier")
# 开始处理依赖队列
while [ ${#charts[@]} -ne 0 ]; do
chart_deps
charts=("${charts[@]:1}")
done
✅ 该脚本可以递归列出所有依赖项,适用于 Release 或任意 Chart。
6. 总结
本文介绍了如何使用 Helm 命令和 Shell 脚本查看已安装 Chart 的依赖。
虽然 Helm 没有原生支持查看 Release 的依赖树,但我们可以通过下载 Chart 并结合脚本实现这一功能。
关键点如下:
- Helm 依赖信息存储在
Chart.yaml
中 - 使用
helm dependency list
可查看本地 Chart 的依赖 - 通过
helm pull
+ Shell 脚本可实现查看已安装 Chart 的依赖 - 使用队列机制可实现递归依赖解析
如果你需要管理复杂的 Helm Chart 依赖关系,这个脚本将是一个非常实用的工具。