打包并推送 Helm Chart 到 OCI 仓库
本指南将引导你完成一个实际的 CI 场景:你的 Git 仓库已经包含了一个 Helm chart(Chart.yaml、templates/、values.yaml 等)。
我们将使用 Pipeline 来:
- 使用
git-clone
Task 克隆仓库
- 使用 Helm 打包 chart
- 将构建好的 chart 推送到 OCI 仓库(例如 Harbor)
你将创建一个包含两个 Task 的 Pipeline:
git-clone
:将你的仓库克隆到共享工作空间
helm
:打包 chart 并将 .tgz
推送到你的 OCI 仓库
目录
前提条件
- 一个 Kubernetes 集群(你可以使用 minikube 进行本地测试)。
- 在集群上安装了 Tekton Pipelines。
- 一个 Helm 3.8+ 容器镜像(支持 OCI 的 Helm v3)。
- 一个 OCI 仓库及仓库路径(例如 oci://registry.example.com/charts)。
- 用于 OCI 仓库的推送凭证,格式为 Docker config JSON:
- 创建一个类型为
kubernetes.io/dockerconfigjson
的 Kubernetes Secret(示例如下)。
- 一个包含有效 Helm chart 的 Git 仓库(目录中包含
Chart.yaml
、templates/
、values.yaml
)。
- 访问该 Git 仓库的权限:
- 公共仓库:无需特殊操作。
- 私有仓库:创建 Git 凭证 Secret(SSH 或基本认证)。
为什么使用 Docker config JSON?Helm 使用与 Docker 相同的认证配置。我们将通过 HELM_REGISTRY_CONFIG
指向该配置。
逐步操作指南
第 1 步:创建仓库凭证 Secret
你需要为你的 OCI 仓库准备一个 Docker config JSON 格式的仓库凭证。
你可以参考 Prepare Registry Credential。
第 2 步:准备 helm 镜像
你需要一个 Helm 3.8+ 容器镜像(支持 OCI 的 Helm v3)来运行 helm
命令。
你可以参考 Discover Tool Image。
搜索时通过标签指定镜像为 helm
,例如:-l operator.tekton.dev/tool-image=helm
。
第 3 步:定义 Pipeline
该 Pipeline 使用 git-clone
拉取你的仓库,然后调用 helm
打包并推送 chart。
请将 <helm-image>
替换为你的 Helm 镜像。
apiVersion: tekton.dev/v1
kind: Pipeline
metadata:
name: package-and-push-helm-oci
spec:
description: Clone repo, package Helm chart, and push to an OCI registry.
params:
- name: repo_url
type: string
description: Git URL of your repository
- name: revision
type: string
description: Git revision (branch, tag, or SHA)
default: main
- name: chart_dir
type: string
description: Path to the Helm chart in the repo
default: "."
- name: oci_repo
type: string
description: OCI repo, e.g., oci://registry.example.com/charts
- name: package_flags
type: string
description: Extra flags for `helm package`
default: ""
workspaces:
- name: source
- name: registry-creds
optional: true
- name: basic-auth
optional: true
tasks:
- name: git-clone
taskRef:
resolver: hub
params:
- name: catalog
value: catalog
- name: kind
value: task
- name: name
value: git-clone
- name: version
value: "0.9"
workspaces:
- name: output
workspace: source
- name: basic-auth
workspace: basic-auth
params:
- name: url
value: $(params.repo_url)
- name: revision
value: $(params.revision)
- name: helm
runAfter:
- "git-clone"
taskRef:
resolver: hub
params:
- name: catalog
value: catalog
- name: kind
value: task
- name: name
value: run-script
- name: version
value: "0.1"
workspaces:
- name: source
workspace: source
- name: secret
workspace: registry-creds
params:
- name: image
## Replace with your Helm image
value: <helm-image>
- name: script
value: |
if [ "$(workspaces.secret.bound)" = "true" ]; then
echo "Using registry credentials in $(workspaces.secret.path)"
export HELM_REGISTRY_CONFIG=$(workspaces.secret.path)/.dockerconfigjson
fi
echo "Packaging chart from $(params.chart_dir)"
tempDir=$(mktemp -d)
helm package $(params.chart_dir) --destination ${tempDir} $(params.package_flags)
chart_tgz="$(ls ${tempDir}/*.tgz | head -n1)"
if [ -z "${chart_tgz}" ]; then
echo "No packaged chart found!"
exit 1
fi
echo "Packaged: ${chart_tgz}"
echo "Pushing to $(params.oci_repo)..."
helm push "${chart_tgz}" "$(params.oci_repo)"
echo "Done."
第 4 步:通过 PipelineRun 运行
绑定工作空间并传入参数。
apiVersion: tekton.dev/v1
kind: PipelineRun
metadata:
generateName: package-and-push-helm-oci-
spec:
pipelineRef:
name: package-and-push-helm-oci
workspaces:
- name: source
volumeClaimTemplate:
spec:
## Specify StorageClassName (as needed)
# storageClassName: <storage-class-name>
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
- name: registry-creds
secret:
secretName: registry-creds
- name: basic-auth
secret:
secretName: basic-auth
params:
- name: repo_url
value: https://github.com/your-org/your-repo.git
- name: revision
value: main
- name: oci_repo
value: oci://registry.example.com/charts
- name: chart_dir
value: .
故障排除
helm: command not found
:确保你的 image
中确实包含 Helm 二进制文件。
Error: unknown command "push"
:你的 Helm 镜像不支持 OCI push。请使用更新的 Helm(3.8+)镜像。
unauthorized: authentication required
:确保 Secret 正确且挂载到 registry-creds。确认 HELM_REGISTRY_CONFIG
设置为该路径。
后续步骤