The Application Catalog Manager is a new feature that allows KKP administrators to manage application definitions dynamically through Kubernetes custom resources. This replaces the previous approach where application definitions were embedded in the KKP binary.
This feature is in beta in KKP 2.30. As it continues to evolve, you may encounter breaking changes in future releases.
The main key benefits of the new manager are as follows:
The Application Catalog Manager uses a custom resource called ApplicationCatalog.
When you create or modify an ApplicationCatalog, the controllers automatically create or update the corresponding ApplicationDefinition resources.
To enable the Application Catalog Manager, add the feature gate to your KubermaticConfiguration:
apiVersion: kubermatic.k8c.io/v1
kind: KubermaticConfiguration
metadata:
name: kubermatic
namespace: kubermatic
spec:
featureGates:
ExternalApplicationCatalogManager: true
When enabled, KKP automatically:
application-catalog-manager and webhook componentsApplicationCatalog named default-catalogApplicationDefinition resourcesapiVersion: applicationcatalog.k8c.io/v1alpha1
kind: ApplicationCatalog
metadata:
name: my-catalog
spec:
helm:
charts:
- chartName: "nginx-ingress"
metadata:
displayName: "NGINX Ingress Controller"
description: "Ingress controller for Kubernetes"
documentationURL: "https://kubernetes.github.io/ingress-nginx/"
sourceURL: "https://github.com/kubernetes/ingress-nginx"
defaultValuesBlock: |
controller:
service:
type: LoadBalancer
chartVersions:
- chartVersion: "4.9.1"
appVersion: "1.9.1"
- chartVersion: "4.12.2"
appVersion: "1.10.0"
You can specify a default Helm repository for all charts in a catalog:
apiVersion: applicationcatalog.k8c.io/v1alpha1
kind: ApplicationCatalog
metadata:
name: custom-repo-catalog
spec:
helm:
repositorySettings:
baseURL: "oci://quay.io/kubermatic-mirror/helm-charts"
credentials:
registryConfigFile:
secretName: helm-registry-secret
key: .dockerconfigjson
charts:
- chartName: "my-app"
chartVersions:
- chartVersion: "1.0.0"
appVersion: "1.0.0"
Override the repository for a specific chart:
apiVersion: applicationcatalog.k8c.io/v1alpha1
kind: ApplicationCatalog
metadata:
name: mixed-repo-catalog
spec:
helm:
repositorySettings:
baseURL: "oci://quay.io/kubermatic-mirror/helm-charts"
charts:
- chartName: "nginx-ingress"
repositorySettings:
baseURL: "https://charts.bitnami.com/bitnami"
chartVersions:
- chartVersion: "4.9.1"
appVersion: "1.9.1"
Override the repository for a specific chart version:
apiVersion: applicationcatalog.k8c.io/v1alpha1
kind: ApplicationCatalog
metadata:
name: version-specific-catalog
spec:
helm:
charts:
- chartName: "nginx-ingress"
chartVersions:
- chartVersion: "4.9.1"
repositorySettings:
baseURL: "oci://internal-mirror/nginx-ingress"
- chartVersion: "4.12.2"
The system resolves Helm chart URLs in this order (first match wins):
charts[].chartVersions[].repositorySettings.baseURLcharts[].repositorySettings.baseURLhelm.repositorySettings.baseURLoci://quay.io/kubermatic-mirror/helm-charts/{chartName}This allows you to use a default repository while overriding specific charts or versions to use internal mirrors.
This section explains how to configure credentials for accessing private Helm repositories or OCI registries.
For OCI registries (like quay.io, ghcr.io, or internal registries):
apiVersion: applicationcatalog.k8c.io/v1alpha1
kind: ApplicationCatalog
metadata:
name: my-catalog
spec:
helm:
repositorySettings:
baseURL: "oci://quay.io/kubermatic-mirror/helm-charts"
credentials:
registryConfigFile:
secretName: oci-credentials
key: .dockerconfigjson
charts:
- chartName: "my-app"
chartVersions:
- chartVersion: "1.0.0"
appVersion: "1.0.0"
Create the secret:
kubectl create secret generic oci-credentials \
--from-file=.dockerconfigjson=path/to/config.json \
-n kubermatic
For traditional Helm chart repositories over HTTP/HTTPS:
apiVersion: applicationcatalog.k8c.io/v1alpha1
kind: ApplicationCatalog
metadata:
name: my-catalog
spec:
helm:
repositorySettings:
baseURL: "https://charts.internal.example.com"
credentials:
username:
secretName: helm-credentials
key: username
password:
secretName: helm-credentials
key: password
charts:
- chartName: "my-app"
chartVersions:
- chartVersion: "1.0.0"
appVersion: "1.0.0"
Create the secret:
kubectl create secret generic helm-credentials \
--from-literal username=myuser \
--from-literal password=mypassword \
-n kubermatic
KKP includes the following enterprise applications by default:
| Application | Description |
|---|---|
| argocd | GitOps continuous delivery tool |
| cert-manager | Certificate management |
| falco | Runtime security |
| flux2 | GitOps operator |
| k8sgpt-operator | AI-powered Kubernetes assistant |
| kube-vip | Virtual IP management |
| kubevirt | Virtualization platform |
| local-ai | Local AI inference |
| metallb | Load balancer for bare-metal |
| mcp-server-kubernetes | Model Context Protocol server |
| nvidia-gpu-operator | GPU management |
| nginx-ingress | Ingress controller |
| trivy | Vulnerability scanner |
| trivy-operator | Security scanner |
| kueue | Job queue management |
In air-gapped environments or when you need to use custom Helm registries, you can override the default application definitions by modifying the default-catalog ApplicationCatalog.
You can add custom applications alongside the default KKP applications:
apiVersion: applicationcatalog.k8c.io/v1alpha1
kind: ApplicationCatalog
metadata:
name: default-catalog
namespace: kubermatic
spec:
helm:
includeDefaults: true
# Add custom charts here
charts:
- chartName: "my-custom-app"
metadata:
displayName: "My Custom Application"
description: "Internal application for our team"
chartVersions:
- chartVersion: "1.0.0"
appVersion: "1.0.0"
When includeDefaults: true, the webhook merges the default KKP applications with your custom charts.
To use a different Helm registry for default applications (e.g., for air-gapped environments), create a custom catalog that references the same application names with different repository settings:
apiVersion: applicationcatalog.k8c.io/v1alpha1
kind: ApplicationCatalog
metadata:
name: air-gapped-catalog
namespace: kubermatic
spec:
helm:
repositorySettings:
baseURL: "https://internal-registry.example.com/charts"
charts:
- chartName: "cert-manager"
chartVersions:
- chartVersion: "1.13.0"
appVersion: "1.13.0"
- chartName: "nginx-ingress"
chartVersions:
- chartVersion: "4.9.1"
appVersion: "1.9.1"
Alternatively, you can modify the default-catalog directly by adding a repositorySettings block:
apiVersion: applicationcatalog.k8c.io/v1alpha1
kind: ApplicationCatalog
metadata:
name: default-catalog
namespace: kubermatic
spec:
helm:
includeDefaults: true
repositorySettings:
baseURL: "https://internal-registry.example.com/charts"
credentials:
username:
secretName: internal-registry-creds
key: username
password:
secretName: internal-registry-creds
key: password
When you set spec.helm.repositorySettings.baseURL, that URL applies to all charts in the catalog. However, you can override this URL for specific charts or versions. For example, if most of your charts are in an internal registry but one chart needs to come from a different location:
apiVersion: applicationcatalog.k8c.io/v1alpha1
kind: ApplicationCatalog
metadata:
name: default-catalog
namespace: kubermatic
spec:
helm:
includeDefaults: true
# Default repository for most charts
repositorySettings:
baseURL: "https://internal-registry.example.com/charts"
charts:
# Override repository for this specific chart
- chartName: "cert-manager"
repositorySettings:
baseURL: "https://charts.jetstack.io"
chartVersions:
- chartVersion: "1.13.0"
appVersion: "1.13.0"
# This chart uses the catalog-level baseURL
- chartName: "nginx-ingress"
chartVersions:
- chartVersion: "4.9.1"
appVersion: "1.9.1"
The system resolves Helm chart URLs in this order:
charts[].chartVersions[].repositorySettings.baseURLcharts[].repositorySettings.baseURLhelm.repositorySettings.baseURLoci://quay.io/kubermatic-mirror/helm-charts/{chartName}This allows you to override specific charts or versions to point to internal mirrors while using the default registry for others.
Create multiple catalogs for different purposes:
apiVersion: applicationcatalog.k8c.io/v1alpha1
kind: ApplicationCatalog
metadata:
name: internal-tools
namespace: kubermatic
spec:
helm:
repositorySettings:
baseURL: "https://charts.internal.example.com"
charts:
- chartName: "monitoring-stack"
metadata:
displayName: "Internal Monitoring Stack"
description: "Company monitoring tools"
chartVersions:
- chartVersion: "2.0.0"
appVersion: "2.0.0"
When using multiple catalogs, keep these considerations in mind:
Webhook Validation Prevents Duplicates
Error Message Example
ApplicationCatalog conflicts detected:
- ApplicationDefinition "nginx" is already managed by catalog "other-catalog"
To resolve this conflict, either:
1. Remove the conflicting chart from this catalog
2. Use a different appName in metadata.appName for the chart
3. Delete the other catalog or remove the chart from it first
ApplicationDefinitions created by the catalog manager are labeled with:
applicationcatalog.k8c.io/managed-by: "true"applicationcatalog.k8c.io/catalog-name: "<catalog-name>"These labels help track catalog ownership.
Note that when you remove a chart from an ApplicationCatalog or delete the catalog entirely, the controller does NOT automatically delete the corresponding ApplicationDefinition resources. This is intentional to prevent disruption of running workloads that may be using these applications.
If you need to remove an ApplicationDefinition, you must delete it manually after removing ApplicationDefinition from the catalog or removing labels from it:
kubectl delete applicationdefinition <definition-name> -n kubermatic
Before deleting an ApplicationDefinition, ensure no running workloads depend on it.
You can modify certain fields on managed ApplicationDefinitions without the controller overwriting your changes.
Customize the Application Catalog Manager through KubermaticConfiguration:
apiVersion: kubermatic.k8c.io/v1
kind: KubermaticConfiguration
metadata:
name: kubermatic
spec:
applications:
catalogManager:
image:
repository: quay.io/kubermatic/application-catalog-manager
tag: v0.2.0
managerSettings:
resources:
requests:
cpu: 100m
memory: 256Mi
limits:
cpu: 500m
memory: 500Mi
logLevel: info
reconciliationInterval: 10m
webhookSettings:
resources:
requests:
cpu: 50m
memory: 64Mi
limits:
cpu: 200m
memory: 128Mi
apps:
- cert-manager
- nginx
- argocd
The apps field filters which default applications are included in the default catalog
When apps is empty or not set, all default applications are included.
When specified, only the listed applications are included.
This is useful when you want to provide a curated subset of default KKP applications to your users.
The apps field filters default applications in the default catalog.
To revert to the embedded catalog approach, remove the feature gate:
kubectl patch kubermaticconfiguration kubermatic -n kubermatic --type=json -p='[
{"op": "remove", "path": "/spec/featureGates/ExternalApplicationCatalogManager"}
]'
KKP will automatically:
ApplicationCatalog resourcesWhen you enable the feature gate:
applicationcatalog.k8c.io/managed-by labels are applied