Helm Installation Guide

Complete guide to install the KFP Operator using Helm with production-ready configuration

Installing the KFP Operator

This guide provides comprehensive instructions for installing the Kubeflow Pipelines Operator in your Kubernetes cluster. We recommend using Helm for a declarative approach to managing Kubernetes resources.

Overview

The KFP Operator installation consists of three main components:

  1. Prerequisites: Required dependencies (Argo Workflows, Argo Events)
  2. KFP Operator: The core operator and controllers
  3. Providers: ML orchestration platform integrations (KFP, Vertex AI)

Prerequisites

Before installing the KFP Operator, ensure your cluster meets these requirements:

Cluster Requirements

  • Kubernetes: v1.21 or later (tested up to v1.28)
  • Cluster Admin Access: Required for installing CRDs and cluster-wide resources
  • Storage: Persistent storage for pipeline artifacts and metadata
  • Network: Outbound internet access for downloading container images

Required Dependencies

1. Argo Workflows

Version: 3.1.6 - 3.4.x Purpose: Workflow execution engine for pipeline orchestration

# Install Argo Workflows (cluster-wide)
kubectl create namespace argo
kubectl apply -n argo -f https://github.com/argoproj/argo-workflows/releases/download/v3.4.4/install.yaml

Verification:

kubectl get pods -n argo
# Should show argo-server and workflow-controller pods running

Version: 1.7.4 or later Purpose: Event-driven pipeline automation

# Install Argo Events (cluster-wide)
kubectl create namespace argo-events
kubectl apply -f https://raw.githubusercontent.com/argoproj/argo-events/stable/manifests/install.yaml

Verification:

kubectl get pods -n argo-events
# Should show eventbus-controller and eventsource-controller pods running

Optional Dependencies

Purpose: Automatic TLS certificate management for webhooks

# Install cert-manager
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.13.0/cert-manager.yaml

Prometheus Operator (For Monitoring)

Purpose: Metrics collection and monitoring

# Install Prometheus Operator
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm install prometheus prometheus-community/kube-prometheus-stack

Helm Installation

This guide assumes you have Helm 3.x installed:

# Verify Helm installation
helm version
# Should show version 3.x

Installing the KFP Operator

The KFP Operator installation consists of the core operator and at least one provider for ML orchestration.

Quick Installation

For a basic installation with default settings:

# Add the KFP Operator Helm repository
helm repo add kfp-operator https://sky-uk.github.io/kfp-operator/
helm repo update

# Install with default values
helm install kfp-operator kfp-operator/kfp-operator

Custom Installation

For production deployments, create a custom values.yaml file:

# values.yaml - Basic configuration
namespace:
  create: true
  name: kfp-operator-system

manager:
  replicas: 2  # High availability
  resources:
    requests:
      cpu: 100m
      memory: 128Mi
    limits:
      cpu: 500m
      memory: 512Mi

  # Monitoring configuration
  monitoring:
    create: true
    serviceMonitor:
      create: true  # For Prometheus Operator

# Enable event-driven workflows
statusFeedback:
  enabled: true

# Logging configuration
logging:
  verbosity: 1  # 0=error, 1=info, 2=debug

Install with custom configuration:

helm install kfp-operator kfp-operator/kfp-operator -f values.yaml

Installation Methods

# Add repository and install
helm repo add kfp-operator https://sky-uk.github.io/kfp-operator/
helm install kfp-operator kfp-operator/kfp-operator -f values.yaml

Method 2: Local Development (Requires local kubernetes cluster)

# Clone repository and install from source
git clone https://github.com/sky-uk/kfp-operator.git
cd kfp-operator
helm install kfp-operator ./helm/kfp-operator -f values.yaml

Verification

Verify the installation was successful:

# Check operator pods
kubectl get pods -n kfp-operator-system

# Check CRDs were installed
kubectl get crd | grep pipelines.kubeflow.org

# Check operator logs
kubectl logs -n kfp-operator-system deployment/kfp-operator-controller-manager

Expected output:

NAME                                           READY   STATUS    RESTARTS   AGE
kfp-operator-controller-manager-xxx-xxx        2/2     Running   0          2m

Namespace Configuration

The operator can be installed in any namespace. Common patterns:

namespace:
  create: true
  name: kfp-operator-system

Existing Namespace

namespace:
  create: false
  name: ml-platform

Multi-tenant Setup

# Install operator in system namespace
namespace:
  name: kfp-operator-system

# Configure RBAC for multiple tenant namespaces
manager:
  rbac:
    create: true
    # Additional cluster roles will be created

Configuration Values

Valid configuration options to override the Default values.yaml are:

ParameterDescriptionDefault
containerRegistryContainer Registry base path for all container images"ghcr.io/kfp-operator"
crds.createInstall the operator’s Custom Resource Definitionstrue
crds.keepRetain the Custom Resource Definitions when the chart is uninstalledtrue
fullnameOverrideOverride the fully qualified name of chart resources""
kfp-provider-workflows.enabledEnable the kfp-provider-workflows subchart. Disabled by default; install the subchart separately, one release per provider namespacefalse
logging.verbosityLogging verbosity for all components - see the logging documentation for valid valuesnil
manager.configurationManager configuration as defined in Configuration (note that you can omit compilerImage and kfpSdkImage when specifying containerRegistry as default values will be applied){}
manager.leaderElection.enabledToggle leader election - defaults to truetrue
manager.leaderElection.idLeader election Lease resource name - defaults to kfp-operator-lock"kfp-operator-lock"
manager.metadataObject Metadata for the manager’s pods{}
manager.monitoring.createCreate the manager’s monitoring resourcesfalse
manager.monitoring.rbacSecuredEnable additional RBAC-based securityfalse
manager.monitoring.serviceMonitor.createCreate a ServiceMonitor for the Prometheus Operatorfalse
manager.monitoring.serviceMonitor.endpointConfigurationAdditional configuration to be used in the service monitor endpoint (path, port and scheme are provided){}
manager.multiversion.enabledEnable multiversion API. Should be used in production to allow version migration, disable for simplified installationfalse
manager.multiversion.storedVersionSpecifies which CRD version should be set as the stored version. Only takes effect if manager.multiversion.enabled is set to true. Defaults to the latest version."v1beta1"
manager.rbac.createCreate roles and rolebindings for the operatortrue
manager.replicasNumber of replicas for the manager deployment1
manager.resourcesManager resources as per k8s documentation{"limits":{"cpu":"100m","memory":"300Mi"},"requests":{"cpu":"100m","memory":"200Mi"}}
manager.runcompletionWebhook.endpointsArray of endpoints for the run completion event handlers to be called when a run completion event is passed[]
manager.runcompletionWebhook.servicePortPort for the run completion event webhook service to listen on - defaults to 80828082
manager.serviceAccount.createCreate the manager’s service account or expect it to be created externallytrue
manager.serviceAccount.nameManager service account’s name"kfp-operator-controller-manager"
manager.webhookCertificates.caBundleCA bundle of the certificate authority that has signed the webhook’s certificate, required if the custom provider is chosen""
manager.webhookCertificates.providerK8s conversion webhook TLS certificate provider - choose cert-manager for Helm to deploy certificates if cert-manager is available or custom otherwise (see below)"cert-manager"
manager.webhookCertificates.secretNameName of a K8s secret deployed into the operator namespace to secure the webhook endpoint with, required if the custom provider is chosen""
manager.webhookServicePortPort for the webhook service to listen on - defaults to 94439443
namespace.createCreate the namespace for the operatortrue
namespace.metadataObject Metadata for the operator namespace{}
namespace.nameOperator namespace name"kfp-operator-system"
provider.envAdditional environment variables for provider containers[]
provider.labelsAdditional labels applied to provider resources{}
provider.metricsPortPort for provider metrics endpoints8081
provider.podTemplateLabelsAdditional labels applied to provider pod templates{}
provider.replicasNumber of replicas for provider deployments1
provider.resourcesProvider resources as per k8s documentation{"limits":{"cpu":"500m","memory":"256Mi"},"requests":{"cpu":"250m","memory":"128Mi"}}
provider.servicePortPort for provider services to listen on8080
provider.volumeMountsAdditional volume mounts for provider containers[]
provider.volumesAdditional volumes to mount into provider pods[]
runcompletionEventTrigger.enabledWhether the run completion event trigger should be installed - defaults to falsefalse
runcompletionEventTrigger.metadataObject Metadata for the run completion event trigger’s pods{}
runcompletionEventTrigger.metrics.portPort for the run completion event trigger metrics endpoint8081
runcompletionEventTrigger.monitoringWhether monitoring resources should be created for the run completion event trigger - defaults to falsefalse
runcompletionEventTrigger.nats.server.portPort of the NATS server the run completion event trigger connects to4222
runcompletionEventTrigger.nats.subjectNATS subject the run completion event trigger publishes events to"events"
runcompletionEventTrigger.replicasNumber of replicas for the run completion event trigger deployment1
runcompletionEventTrigger.server.portPort for the run completion event trigger gRPC server to listen on50051
statusFeedback.enabledWhether run completion eventing and status update feedback loop should be installed - defaults to falsefalse

Examples for these values can be found in the test configuration

Providers

Please refer to your chosen provider instructions before proceeding. Supported providers are:

To install your chosen provider, create a Provider resource in a namespace that the operator can access (see the rbac setup below for reference). Once it is applied the Provider controller will reconcile and create the Provider Deployment and Provider Service within the same namespace that the Provider resource was applied.

Provider workflows

The operator runs resource-management Argo Workflows in the same namespace as the Provider they belong to, so that each provider is isolated from the others. Argo cannot reference a WorkflowTemplate across namespaces, therefore every provider namespace must contain its own copy of the WorkflowTemplates and the execution RBAC (ServiceAccount, Role and RoleBinding) the workflows run with.

These per-namespace resources are provisioned by the kfp-provider-workflows chart, which is installed once per provider namespace. Install one release for each namespace in which you create a Provider:

helm install <release-name> ./helm/kfp-operator/charts/kfp-provider-workflows \
  --namespace <provider-namespace> \
  --set namespace=<provider-namespace>

By default the chart also creates the Provider resource. Provide its required spec fields, or set provider.create=false to manage the Provider yourself:

helm install <release-name> ./helm/kfp-operator/charts/kfp-provider-workflows \
  --namespace <provider-namespace> \
  --set namespace=<provider-namespace> \
  --set provider.name=<provider-name> \
  --set provider.serviceImage=<provider-service-image> \
  --set provider.pipelineRootStorage=<pipeline-root-storage>

Valid configuration options to override the Default values.yaml are:

ParameterDescriptionDefault
argo.containerDefaultsContainer spec defaults applied to the Argo workflow pods{}
argo.metadataMetadata (labels/annotations) applied to the Argo workflow pods{}
argo.rbac.createCreate the namespace-scoped workflow-executor Role and its RoleBinding. Set to false to manage these resources externallytrue
argo.securityContextSecurity Context applied to the Argo workflow pods. Set to null or runAsNonRoot to false to run as root{"fsGroup":1000,"runAsNonRoot":true,"runAsUser":1000}
argo.serviceAccount.createCreate the Argo workflow ServiceAccount. Set to false to reuse an existing onetrue
argo.serviceAccount.metadataObject Metadata for the Argo workflow ServiceAccount{}
argo.serviceAccount.nameServiceAccount the Argo workflows run as, created in the provider namespace"kfp-operator-argo"
argo.stepTimeoutSeconds.compileTimeout in seconds for compiler steps1800
argo.stepTimeoutSeconds.defaultDefault timeout in seconds for workflow steps300
argo.ttlStrategy.secondsAfterCompletionTTL Strategy - seconds to retain completed Argo Workflows before cleanup3600
namespaceNamespace the WorkflowTemplates, RBAC and Provider resource are created in. Must match the namespace the Provider runs in. Defaults to the release namespace when left empty""
provider.allowedNamespacesNamespaces allowed to reference this provider. An empty list allows all namespaces[]
provider.createWhen true, the chart also renders the Provider custom resourcetrue
provider.frameworksPipeline frameworks the provider supports (see the Provider CRD reference)[]
provider.metadataObject Metadata for the Provider resource{}
provider.nameProvider resource name. Defaults to the release name when left empty""
provider.parametersFree-form provider parameters (map of name to value){}
provider.pipelineRootStoragePipeline root storage location. Required when provider.create is true""
provider.podTemplateEnvEnvironment variables applied to the generated provider-service container, merged over the operator’s defaultProviderValues env; per-provider values take precedence on name collision[]
provider.podTemplateVolumeMountsVolume mounts applied to the generated provider-service container, merged over the operator’s defaultProviderValues volume mounts; per-provider values take precedence on mount-path collision[]
provider.podTemplateVolumesVolumes applied to the generated provider-service pod, merged over the operator’s defaultProviderValues volumes; per-provider values take precedence on name collision[]
provider.serviceAccount.createCreate the provider service ServiceAccount. Set to false to reuse an existing onetrue
provider.serviceAccount.metadataObject Metadata for the provider service ServiceAccount{}
provider.serviceAccount.nameProvider service ServiceAccount name, created in the provider namespace and referenced by the Provider spec. Defaults to kfp-provider-<provider-name> when left empty. Its cluster-scoped viewer/eventing bindings are managed externally by the platform""
provider.serviceImageProvider service image. Required when provider.create is true""

The argo.* execution values (argo.ttlStrategy, argo.stepTimeoutSeconds, argo.securityContext, argo.containerDefaults and argo.metadata) control how the provider’s Argo Workflows run. Override them per release if a provider namespace needs different workflow behaviour.

Note: because workflows now run in the provider namespace, the artifact-repository credentials Secret that your Argo workflow-controller references (the accessKeySecret/secretKeySecret in its artifactRepository configuration — for example the MinIO/S3 secret) must exist in each provider namespace. Argo resolves that Secret in the namespace the workflow pods run in, so a copy that only lives in the Argo or operator namespace is not sufficient. The kfp-provider-workflows chart does not manage this Secret — it holds credentials owned by the platform team — so you must create it in every provider namespace yourself.

What the chart provisions

The kfp-provider-workflows chart provisions only namespace-scoped resources — everything a provider needs to operate inside its own namespace. Cluster-scoped resources are deliberately left to the platform team (see Cluster-scoped RBAC below). A single release renders:

ResourceKindGated byPurpose
common-steps, create-simple, update-simple, create-compiled, update-compiled, compiled-workflow-steps, deleteWorkflowTemplatealwaysThe resource-management workflow definitions the operator invokes.
kfp-operator-argoServiceAccountargo.serviceAccount.createThe account the Argo Workflow pods run as.
workflow-executorRole + RoleBindingargo.rbac.createGrants the Argo workflow account the in-namespace permissions its steps need (pods get/patch, workflowtaskresults create/patch). Bound to the Argo workflow ServiceAccount.
kfp-provider-<provider-name>ServiceAccountprovider.create and provider.serviceAccount.createThe account the provider service runs as; referenced by the Provider spec.
<provider-name>Providerprovider.createThe Provider custom resource itself.

Role-based access control (RBAC) for providers

The namespace-scoped RBAC above is handled by the chart. The resources in this section are cluster-scoped and are therefore not created by the chart — you must create them once (they are shared across provider namespaces). If you are not using the chart at all, see Deploying without Helm for the complete list including the namespace-scoped resources.

In order for Event Source Servers and the Controller to read the Providers you must configure their service accounts to have read permissions of Provider resources. e.g:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: kfp-operator-kfp-providers-viewer-rolebinding
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: kfp-operator-providers-viewer-role
subjects:
- kind: ServiceAccount
  name: kfp-operator-kfp #Used by Event Source Server
  namespace: kfp-operator-system
- kind: ServiceAccount
  name: kfp-operator-controller-manager #Used by KFP Controller
  namespace: kfp-operator-system

The provider service account itself (kfp-provider-<provider-name> by default) is created by the chart in the provider namespace. It still needs cluster-scoped read access to RunConfiguration and Run resources, granted by binding it to the ClusterRoles the operator ships. Create one ClusterRoleBinding per provider service account (replace kfp-provider-example and kfp-namespace with your values):

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: kfp-operator-example-runconfiguration-viewer-rolebinding
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: kfp-operator-runconfiguration-viewer-role
subjects:
- kind: ServiceAccount
  name: kfp-provider-example
  namespace: kfp-namespace
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: kfp-operator-example-run-viewer-rolebinding
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: kfp-operator-run-viewer-role
subjects:
- kind: ServiceAccount
  name: kfp-provider-example
  namespace: kfp-namespace

Note: the workflow-executor Role/RoleBinding and the Argo workflow ServiceAccount are namespace-scoped and are created for you by the kfp-provider-workflows chart. You only need to author them manually when deploying without Helm.

Kubeflow completion eventing required RBACs

If using the Kubeflow Pipelines Provider you will also need a ClusterRole for permission to interact with argo workflows for the eventing system for run completion events.

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: kfp-operator-kfp-eventsource-server-role
rules:
- apiGroups:
  - argoproj.io
  resources:
  - workflows
  verbs:
  - get
  - list
  - patch
  - update
  - watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: kfp-operator-kfp-eventsource-server-rolebinding
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: kfp-operator-kfp-eventsource-server-role
subjects:
- kind: ServiceAccount
  name: kfp-provider-example
  namespace: kfp-namespace

Deploying without Helm

If you do not use the kfp-provider-workflows chart, you are responsible for creating every resource a provider needs yourself. Because Argo cannot reference a WorkflowTemplate across namespaces, the namespace-scoped resources must be recreated once per provider namespace, while the cluster-scoped resources are created once per cluster and shared.

Namespace-scoped resources (once per provider namespace)

These are the resources the chart would otherwise create. All of them live in the provider’s namespace.

ResourceKindPurpose
common-steps, create-simple, update-simple, create-compiled, update-compiled, compiled-workflow-steps, deleteWorkflowTemplateThe resource-management workflow definitions. Copy them from helm/kfp-operator/charts/kfp-provider-workflows/templates into the provider namespace. They must keep these exact names — the operator references them statically.
Argo workflow ServiceAccountServiceAccountThe account the Argo Workflow pods run as.
workflow-executorRoleGrants the Argo workflow account pods (get, patch) and argoproj.io/workflowtaskresults (create, patch).
workflow-executorRoleBindingBinds the workflow-executor Role to the Argo workflow ServiceAccount.
Provider service ServiceAccountServiceAccountThe account the provider service runs as; referenced by the Provider spec.
ProviderProviderThe provider custom resource.
Artifact-repository credentialsSecretThe accessKeySecret/secretKeySecret referenced by the Argo workflow-controller’s artifactRepository configuration (for example the MinIO/S3 secret). Argo resolves it in the namespace the workflow pods run in, so a copy must exist in each provider namespace. Not managed by the chart in the Helm path either.

Example of the namespace-scoped RBAC (replace argo-workflow-sa, kfp-provider-example and kfp-namespace with your values):

---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: argo-workflow-sa
  namespace: kfp-namespace
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: kfp-provider-example
  namespace: kfp-namespace
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: workflow-executor
  namespace: kfp-namespace
rules:
- apiGroups: [""]
  resources: [pods]
  verbs: [get, patch]
- apiGroups: [argoproj.io]
  resources: [workflowtaskresults]
  verbs: [create, patch]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: workflow-executor
  namespace: kfp-namespace
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: workflow-executor
subjects:
- kind: ServiceAccount
  name: argo-workflow-sa
  namespace: kfp-namespace

Cluster-scoped resources (once per cluster)

These are shared across all provider namespaces and are the same resources described in RBAC for providers and Kubeflow completion eventing above:

  • The providers-viewer ClusterRoleBinding for the Event Source Server and Controller service accounts.
  • A run-viewer and a runconfiguration-viewer ClusterRoleBinding per provider service account.
  • For the Kubeflow Pipelines provider only, the eventing ClusterRole and ClusterRoleBinding.

The providers-viewer-role, run-viewer-role and runconfiguration-viewer-role ClusterRoles are installed by the operator chart; when deploying the operator without Helm you must create these too (see helm/kfp-operator/templates/rbac).