A Kubernetes controller that automatically triggers HelmRelease reconciliation when associated ConfigMaps are updated, enabling seamless configuration-driven GitOps workflows.
Important: This project is not affiliated with FluxCD or ControlPlaneIO-FluxCD. It is an independent operator designed to simplify deployments with FluxCD, specifically when using the valuesFrom
feature in HelmRelease configurations. The HelmRelease Trigger Operator provides additional functionality for triggering HelmRelease reconciliations based on ConfigMap updates, but it is not officially supported or endorsed by the FluxCD project or its maintainers.
The HelmRelease Trigger Operator monitors ConfigMaps with specific labels and annotations, automatically triggering FluxCD HelmRelease reconciliation when configuration changes are detected. This enables dynamic configuration management where ConfigMap updates can immediately trigger application redeployments without manual intervention.
The operator watches for ConfigMaps labeled with nebius.ai/helmrelease-trigger-operator: "true"
and:
- Monitors ConfigMap Changes: Detects create, update, and generic events on labeled ConfigMaps
- Extracts HelmRelease References: Uses annotations to identify the target HelmRelease
- Compares Digests: Checks if the HelmRelease digest has changed since last reconciliation
- Triggers Reconciliation: Patches the HelmRelease with force reconciliation annotations when changes are detected
- Autodiscovery: Dynamically identifies HelmReleases with matching labels and annotations to include them in the reconciliation process
- Automatic Triggering: No manual intervention required for configuration-driven deployments
- Autodiscovery: Dynamically detects and includes HelmReleases based on labels and annotations
- Digest-based Change Detection: Prevents unnecessary reconciliations by comparing digests
- FluxCD Integration: Seamlessly works with existing FluxCD HelmRelease resources
- Namespace Flexibility: Supports cross-namespace ConfigMap to HelmRelease references
- Configurable Concurrency: Adjustable reconciliation performance settings
The HelmRelease Trigger Operator implements autodiscovery by scanning all HelmReleases in the cluster and automatically labeling those that use the valuesFrom
feature. This ensures that HelmReleases relying on external ConfigMaps or Secrets for their values are dynamically included in the operator's reconciliation workflow.
-
HelmRelease Scanning: The operator scans all HelmReleases in the cluster.
-
valuesFrom
Detection: It checks if the HelmRelease configuration includes thevaluesFrom
field, which indicates dependency on external resources like ConfigMaps or Secrets. -
Automatic Labeling: For HelmReleases using
valuesFrom
, the operator adds the following labels:"nebius.ai/helmrelease-trigger-operator": "true"
: Marks the HelmRelease as managed by the operator."nebius.ai/helmreleases-namespace": "<namespace>"
: Specifies the namespace of the HelmRelease."nebius.ai/helmreleases-name": "<name>"
: Specifies the name of the HelmRelease.
-
Continuous Monitoring: The operator continuously monitors the cluster for changes to HelmReleases and updates labels dynamically as needed.
- Kubernetes cluster (version 1.19+)
- FluxCD v2 with Helm Controller installed
- kubectl CLI tool
- Appropriate RBAC permissions
Install the HelmRelease Trigger Operator using the Helm chart from Nebius Container Registry:
# Add the Nebius Helm repository (OCI-based)
helm install helmrelease-trigger-operator \
oci://cr.eu-north1.nebius.cloud/soperator/helm-helmrelease-trigger-operator \
--version <version> \
--namespace helmrelease-trigger-operator-system \
--create-namespace
To install the latest version:
helm install helmrelease-trigger-operator \
oci://cr.eu-north1.nebius.cloud/soperator/helm-helmrelease-trigger-operator \
--namespace helmrelease-trigger-operator-system \
--create-namespace
You can customize the installation by providing your own values:
# Create values file
cat <<EOF > values.yaml
controllerManager:
manager:
args:
- --metrics-bind-address=:8443
- --leader-elect
- --health-probe-bind-address=:8081
- --enable-hr-autodiscovery=true
- --log-format=json
- --log-level=debug
resources:
limits:
memory: 256Mi
requests:
cpu: 200m
memory: 128Mi
replicas: 2
EOF
# Install with custom values
helm install helmrelease-trigger-operator \
oci://cr.eu-north1.nebius.cloud/soperator/helm-helmrelease-trigger-operator \
--values values.yaml \
--namespace helmrelease-trigger-operator-system \
--create-namespace
kustomize build config/default | kubectl apply -f -
### Verify Installation
```bash
# Check if the operator pod is running
kubectl get pods -n helmrelease-trigger-operator-system
# View operator logs
kubectl logs -n helmrelease-trigger-operator-system deployment/helmrelease-trigger-operator-controller-manager
# Check the Helm release status
helm list -n helmrelease-trigger-operator-system
To upgrade to a newer version:
# Upgrade to specific version
helm upgrade helmrelease-trigger-operator \
oci://cr.eu-north1.nebius.cloud/soperator/helm-helmrelease-trigger-operator \
--version <new-version> \
--namespace helmrelease-trigger-operator-system
# Upgrade to latest version
helm upgrade helmrelease-trigger-operator \
oci://cr.eu-north1.nebius.cloud/soperator/helm-helmrelease-trigger-operator \
--namespace helmrelease-trigger-operator-system
# Uninstall the Helm release
helm uninstall helmrelease-trigger-operator \
--namespace helmrelease-trigger-operator-system
# Optionally, delete the namespace
kubectl delete namespace helmrelease-trigger-operator-system
ConfigMaps must have the following label to be monitored by the operator:
metadata:
labels:
nebius.ai/helmrelease-trigger-operator: "true"
ConfigMaps must include annotations to specify the target HelmRelease:
metadata:
annotations:
# Required: Name of the target HelmRelease
nebius.ai/helmreleases-name: "my-app"
# Optional: Namespace of the target HelmRelease (defaults to flux-system)
nebius.ai/helmreleases-namespace: "production"
Variable | Description | Default |
---|---|---|
MAX_CONCURRENCY |
Maximum concurrent reconciliations | 10 |
CACHE_SYNC_TIMEOUT |
Controller cache sync timeout | 2m |
LOG_LEVEL |
Logging level (debug, info, warn, error) | info |
- Create a HelmRelease (if not already exists):
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: my-app
namespace: flux-system
spec:
chart:
spec:
chart: my-app
sourceRef:
kind: HelmRepository
name: my-repo
version: "1.0.0"
values:
valuesFrom:
- kind: ConfigMap
name: prod-env-values
valuesKey: values.yaml
- kind: Secret
name: prod-tls-values
valuesKey: crt
targetPath: tls.crt
optional: true
- Create a monitored ConfigMap:
apiVersion: v1
kind: ConfigMap
metadata:
name: my-app-config
namespace: default
labels:
nebius.ai/helmrelease-trigger-operator: "true"
annotations:
nebius.ai/helmreleases-name: "my-app"
nebius.ai/helmreleases-namespace: "flux-system"
data:
config.yaml: |
database:
host: "db.example.com"
port: 5432
features:
enableAuth: true
maxConnections: 100
- Update the ConfigMap to trigger reconciliation:
kubectl patch configmap my-app-config -n default \
--type='merge' -p='{"data":{"config.yaml":"database:\n host: \"new-db.example.com\"\n port: 5432\nfeatures:\n enableAuth: true\n maxConnections: 200"}}'
The operator will automatically detect the change and trigger HelmRelease reconciliation.
ConfigMap in app-configs
namespace triggering HelmRelease in production
namespace:
apiVersion: v1
kind: ConfigMap
metadata:
name: production-config
namespace: app-configs
labels:
nebius.ai/helmrelease-trigger-operator: "true"
annotations:
nebius.ai/helmreleases-name: "production-app"
nebius.ai/helmreleases-namespace: "production"
data:
values.yaml: |
environment=production
replica.count=3
resources.limits.memory=2Gi
The operator requires the following Kubernetes permissions:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: helmrelease-trigger-operator
rules:
# ConfigMap permissions
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "list", "watch", "patch"]
# HelmRelease permissions
- apiGroups: ["helm.toolkit.fluxcd.io"]
resources: ["helmreleases"]
verbs: ["get", "list", "watch", "patch"]
# View operator logs
kubectl logs -n helmrelease-trigger-operator-system deployment/helmrelease-trigger-operator
# Check if ConfigMaps are being watched
kubectl get configmaps -l nebius.ai/helmrelease-trigger-operator=true -A
# Verify HelmRelease reconciliation
kubectl get helmreleases -A
kubectl describe helmrelease my-app -n flux-system
-
ConfigMap changes not triggering reconciliation
- Verify the ConfigMap has the required label:
nebius.ai/helmrelease-trigger-operator: "true"
- Check annotations for correct HelmRelease name and namespace
- Ensure the target HelmRelease exists
- Verify the ConfigMap has the required label:
-
RBAC permission errors
- Verify the operator has proper ClusterRole permissions
- Check if ServiceAccount is correctly bound to ClusterRoleBinding
-
Cross-namespace access issues
- Ensure the operator has permissions to access resources in target namespaces
- Verify namespace names in annotations are correct
# Check ConfigMap annotations and labels
kubectl get configmap my-app-config -o yaml
# View HelmRelease status and history
kubectl get helmrelease my-app -o jsonpath='{.status.history[0]}'
# Monitor operator events
kubectl get events -n helmrelease-trigger-operator-system
# Check if reconciliation was triggered
kubectl get helmrelease my-app -o jsonpath='{.metadata.annotations.reconcile\.fluxcd\.io/forceAt}'
┌─────────────────┐ watches ┌─────────────────┐
│ ConfigMap │──────────────▶│ Controller │
│ (labeled) │ │ │
└─────────────────┘ └─────────────────┘
│
│ patches
▼
┌─────────────────┐
│ HelmRelease │
│ │
└─────────────────┘
│
│ triggers
▼
┌─────────────────┐
│ FluxCD Helm │
│ Controller │
└─────────────────┘
Annotation | Required | Description | Example |
---|---|---|---|
nebius.ai/helmreleases-name |
Yes | Target HelmRelease name | my-hr1,my-hr2 |
nebius.ai/helmreleases-namespace |
No | Target HelmRelease namespace | production |
nebius.ai/config-digest |
No | Last processed digest (auto-managed) | sha256:abc123... |
Constant | Value | Description |
---|---|---|
LabelReconcilerNameSourceKey |
nebius.ai/helmrelease-trigger-operator |
Required label for monitoring |
HRNameAnnotation |
nebius.ai/helmreleases-name |
HelmRelease name annotation |
HRNSAnnotation |
nebius.ai/helmreleases-namespace |
HelmRelease namespace annotation |
HashAnnotation |
nebius.ai/config-digest |
Digest tracking annotation |
DefaultFluxcdNamespace |
flux-system |
Default namespace for HelmReleases |
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests for new functionality
- Submit a pull request
Copyright 2025 Nebius B.V.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.