打包并推送 Helm Chart 到 OCI 仓库

本指南将引导你完成一个实际的 CI 场景:你的 Git 仓库已经包含了一个 Helm chart(Chart.yaml、templates/、values.yaml 等)。

我们将使用 Pipeline 来:

  1. 使用 git-clone Task 克隆仓库
  2. 使用 Helm 打包 chart
  3. 将构建好的 chart 推送到 OCI 仓库(例如 Harbor)

你将创建一个包含两个 Task 的 Pipeline:

  1. git-clone:将你的仓库克隆到共享工作空间
  2. 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.yamltemplates/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 设置为该路径。

后续步骤