从 OCI 托管的 Helm Chart 进行部署/升级

本指南展示了一条实用的 CD 路径,其中你的 Helm Chart 已经推送到 OCI registry(例如 Harbor)。

你将使用 Tekton Pipeline 将该 chart 拉取/安装到 Kubernetes 集群中。

你将创建一个名为 helm-oci-deploy 的可复用 Pipeline,它将:

  1. 对 OCI registry 进行身份验证
  2. 直接基于 OCI chart 引用运行 helm upgrade --install
  3. 可选地应用额外的 values 文件和 --set 覆盖项
  4. 可与 Kubeconfig Secret 或 ServiceAccount 一起使用

前提条件

  • 一个 Kubernetes 集群(你可以使用 minikube 进行本地测试)。
  • 已在集群中安装 Tekton Pipelines。
  • 一个支持 OCI 的 Helm 3.8+ 容器镜像(Helm v3,支持 OCI)。
  • 一个包含你要部署的 OCI chart 引用和版本的 OCI registry,例如:
    • oci://registry.example.com/charts/myapp
    • 版本如 1.2.3(必须存在于 registry 中)
  • 你的 OCI registry 的 registry 凭证,使用 kubernetes.io/dockerconfigjson 类型的 Secret 保存:
    • 创建一个类型为 kubernetes.io/dockerconfigjson 的 Kubernetes Secret(示例如下)。
  • Helm 的集群访问权限(选择其一):
    • 挂载一个 Kubeconfig Secret,
    • 或在具有足够 RBAC 权限的 ServiceAccount 下运行该 Task。

分步说明

步骤 1:创建 registry 凭证 Secret

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

你可以参考 Prepare Registry Credential

步骤 2:创建集群访问凭证

你需要为 Helm 准备一个集群访问凭证。

你可以参考 Prepare Cluster Access Credential

步骤 3:准备 helm 镜像

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

你可以参考 Discover Tool Image

通过 label 搜索时,请将镜像指定为 helm,例如:-l operator.tekton.dev/tool-image=helm

步骤 4:定义 Pipeline

这个 Pipeline 使用 helm upgrade --install 直接基于 OCI chart 引用进行安装/升级。

Helm 3.8+ 支持通过 oci://... 并结合 --version 引用 chart。这使得该步骤保持无状态且执行更快。 如果你更倾向于先预拉取 chart,也可以先执行 helm pull 到临时目录,然后从 .tgz 路径进行安装。

你可以使用 --wait,让其阻塞直到 Kubernetes 报告 release 的资源就绪(或直到操作超时)。 将其与 --timeout 搭配使用,以控制 Helm 等待的时长。

通常还会结合使用 --atomic;如果等待失败或超时,它会自动回滚——这样就不会留下一个半升级状态的 release。

请将 <helm-image> 替换为你的 Helm 镜像。

apiVersion: tekton.dev/v1
kind: Pipeline
metadata:
  name: helm-oci-deploy
spec:
  description: Clone repo, package Helm chart, and push to an OCI registry.
  params:
    - name: oci_chart
      type: string
      description: OCI chart ref, e.g. oci://registry.example.com/charts/myapp
    - name: version
      type: string
      description: Chart version to install/upgrade to (must exist in the registry)
    - name: release_name
      type: string
      description: Helm release name
    - name: namespace
      type: string
      description: Target namespace
      default: default
    - name: extra_args
      type: string
      description: Extra helm args (e.g., "--atomic --timeout 5m --set key=val -f values.yaml")
      default: ""
  workspaces:
    - name: registry-creds
      description: Workspace with distribution registry config at config.json (for OCI auth)
      optional: true
    - name: kubeconfig
      description: Workspace containing kubeconfig file at ./kubeconfig
      optional: true
  tasks:
    - name: helm
      taskRef:
        resolver: hub
        params:
          - name: catalog
            value: catalog
          - name: kind
            value: task
          - name: name
            value: run-script
          - name: version
            value: "0.1"
      workspaces:
        - name: config
          workspace: kubeconfig
        - 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

            if [ "$(workspaces.config.bound)" = "true" ]; then
              echo "Using kubeconfig in $(workspaces.config.path)"
              export KUBECONFIG=$(workspaces.config.path)/kubeconfig
            fi

            echo "Upgrading/Installing release..."
            echo "  Release:   $(params.release_name)"
            echo "  Namespace: $(params.namespace)"
            echo "  Chart:     $(params.oci_chart):$(params.version)"

            # Direct install from OCI (no need to helm pull first)
            helm upgrade --install "$(params.release_name)" "$(params.oci_chart)" \
              --version "$(params.version)" \
              --namespace "$(params.namespace)" --create-namespace \
              $(params.extra_args)

            echo "Done."

步骤 5:使用 PipelineRun 运行它

  • Helm 的集群访问权限(选择其一):
    • 挂载一个 Kubeconfig Secret,
    • 或在具有足够 RBAC 权限的 ServiceAccount 下运行该 Task。

请选择一种集群访问凭证。

apiVersion: tekton.dev/v1
kind: PipelineRun
metadata:
  generateName: helm-oci-deploy-
spec:
  workspaces:
    - name: registry-creds
      secret:
        secretName: registry-creds

    ## If you choose to use the kubeconfig Secret
    # - name: kubeconfig
    #   secret:
    #     secretName: <kubeconfig-secret-name>

  params:
    - name: oci_chart
      value: oci://registry.example.com/charts/myapp
    - name: version
      value: "1.1.0"
    - name: release_name
      value: myapp
    - name: namespace
      value: my-namespace
  pipelineRef:
    name: helm-oci-deploy

  ## If you choose to use the ServiceAccount
  # taskRunTemplate:
  #   serviceAccountName: <service-account-name>

故障排除

  • helm: command not found:确保你的 image 中确实包含 Helm 二进制文件。
  • unauthorized: authentication required:确保 Secret 正确,并已挂载到 registry-creds。确认 HELM_REGISTRY_CONFIG 已设置为该路径。
  • Error: chart "myapp" version "x.y.z" not found:该版本不存在于 OCI repo 中,或者 oci_chart 路径错误。请验证已推送的 tag/version 和路径。
  • failed to create resource: (…RBAC…) forbidden:kubeconfig/ServiceAccount 没有足够权限。请授予该 chart 所管理资源所需的创建/更新角色权限。

下一步