将 Helm Chart 打包并推送到 OCI Registry

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

我们将使用 Pipeline 来:

  1. 使用 git-clone Task 克隆仓库
  2. 使用 Helm 打包该 Chart
  3. 将生成的 chart 推送到 OCI Registry(例如 Harbor)

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

  1. git-clone:将你的仓库克隆到共享 workspace 中
  2. helm:打包 chart 并将 .tgz 推送到你的 OCI Registry

前提条件

  • 一个 Kubernetes 集群(你可以使用 minikube 进行本地测试)。
  • 集群上已安装 Tekton Pipelines。
  • 一个 Helm 3.8+ 容器镜像(支持 OCI 的 Helm v3)。
  • 一个 OCI Registry 和 repository 路径(例如 oci://registry.example.com/charts)。
  • 用于你的 OCI Registry 的推送凭证,形式为 kubernetes.io/dockerconfigjson 类型的 Secret
    • 创建一个类型为 kubernetes.io/dockerconfigjson 的 Kubernetes Secret(示例如下)。
  • 一个包含有效 Helm Chart 的 Git 仓库(目录中包含 Chart.yamltemplates/values.yaml)。
  • 访问该仓库的 Git 凭证:
    • 公共仓库:无需特殊配置。
    • 私有仓库:创建一个 Git 凭证 Secret(SSH 或 basic-auth)。

为什么使用 kubernetes.io/dockerconfigjson 类型的 Secret?我们将通过 HELM_REGISTRY_CONFIG 将 Helm 指向 distribution registry。

分步说明

步骤 1:创建 Registry 凭证 Secret

你需要为你的 OCI Registry 准备一个 kubernetes.io/dockerconfigjson 类型的 Secret 作为 registry 凭证。

你可以参考 准备 Registry 凭证

步骤 2:准备 helm 镜像

你需要一个 Helm 3.8+ 容器镜像(支持 OCI 的 Helm v3)来运行 helm 命令。

你可以参考 发现工具镜像

按标签搜索时,请将镜像指定为 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 运行

绑定 workspace 并传入你的参数。

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 已设置为该路径。

下一步