Flux Notification Controller: Alerting On GitOps Drift And Sync Failures
Flux Notification Controller: Alerting on GitOps Drift and Sync Failures
When your GitOps pipeline breaks silently, you find out the worst way — during an incident. The Flux Notification Controller is your early warning system. Here's everything you need to configure it and stop flying blind.
What the Notification Controller Does
The Notification Controller handles two directions of communication:
- Inbound: Receives webhook events from Git providers to trigger reconciliation
- Outbound: Sends alerts to Slack, Teams, PagerDuty, etc. when Flux events occur
We're focused on outbound alerting here — drift detection and sync failures.
Core Resources: The Three-Object Pattern
Every alert setup requires exactly three Kubernetes resources:
Provider → Alert → EventSource (Kustomization/HelmRelease/etc.)
Step 1: Create a Provider
Slack:
apiVersion: notification.toolkit.fluxcd.io/v1beta3
kind: Provider
metadata:
name: slack-alerts
namespace: flux-system
spec:
type: slack
channel: "#gitops-alerts"
secretRef:
name: slack-webhook-url
kubectl create secret generic slack-webhook-url \
--from-literal=address=https://hooks.slack.com/services/YOUR/WEBHOOK/URL \
-n flux-system
PagerDuty:
apiVersion: notification.toolkit.fluxcd.io/v1beta3
kind: Provider
metadata:
name: pagerduty-alerts
namespace: flux-system
spec:
type: pagerduty
secretRef:
name: pagerduty-token
Generic Webhook (for custom integrations):
apiVersion: notification.toolkit.fluxcd.io/v1beta3
kind: Provider
metadata:
name: custom-webhook
namespace: flux-system
spec:
type: generic
address: https://your-endpoint.example.com/flux-events
secretRef:
name: webhook-hmac-token
Step 2: Create an Alert
apiVersion: notification.toolkit.fluxcd.io/v1beta3
kind: Alert
metadata:
name: gitops-failures
namespace: flux-system
spec:
providerRef:
name: slack-alerts
eventSeverity: error # Only fire on errors, not info
eventSources:
- kind: Kustomization
name: "*" # Wildcard catches all Kustomizations
- kind: HelmRelease
name: "*"
- kind: GitRepository
name: "*"
exclusionList:
- ".*validated.*" # Suppress noisy validation messages
Opinion: Use
eventSeverity: errorin production.infofloods your channel and you'll start ignoring it — defeating the whole point.
Alert on Drift Specifically
Flux detects drift when live cluster state diverges from Git. To catch this:
apiVersion: notification.toolkit.fluxcd.io/v1beta3
kind: Alert
metadata:
name: drift-detection
namespace: flux-system
spec:
providerRef:
name: slack-alerts
eventSeverity: error
eventSources:
- kind: Kustomization
name: "*"
summary: "Drift detected in cluster — manual change may have occurred"
Drift events surface as ReconciliationFailed or ValidationFailed in the event stream.
Quick Debugging Commands
# Check if your Alert is ready
kubectl get alerts -n flux-system
# Describe for error details
kubectl describe alert gitops-failures -n flux-system
# Check Provider status
kubectl get providers -n flux-system
# View raw Flux events (your alert source)
kubectl get events -n flux-system --sort-by='.lastTimestamp'
# Check notification controller logs
kubectl logs -n flux-system deployment/notification-controller -f
# Manually trigger a reconciliation to test alerting
flux reconcile kustomization flux-system --with-source
Common Event Sources Reference
| Kind | What it monitors |
|---|---|
GitRepository | Git fetch failures, auth issues |
Kustomization | Apply failures, drift, validation errors |
HelmRelease | Chart failures, upgrade rollbacks |
HelmRepository | Index fetch failures |
ImageRepository | Image scan failures |
ImagePolicy | Policy evaluation failures |
Multi-Environment Alert Routing
Route critical namespaces to PagerDuty, everything else to Slack:
# Production → PagerDuty
apiVersion: notification.toolkit.fluxcd.io/v1beta3
kind: Alert
metadata:
name: prod-critical
namespace: flux-system
spec:
providerRef:
name: pagerduty-alerts
eventSeverity: error
eventSources:
- kind: Kustomization
name: "production-*" # Name prefix matching
---
# Non-prod → Slack
apiVersion: notification.toolkit.fluxcd.io/v1beta3
kind: Alert
metadata:
name: nonprod-alerts
namespace: flux-system
spec:
providerRef:
name: slack-alerts
eventSeverity: error
eventSources:
- kind: Kustomization
name: "staging-*"
- kind: Kustomization
name: "dev-*"
Test Your Alert Pipeline
Don't wait for a real failure. Break something intentionally:
# Reference a non-existent image to trigger a HelmRelease failure
flux suspend helmrelease my-app -n default
# Or corrupt a configmap reference in your repo, push it, and watch
# The alert should fire within one reconciliation interval
Check alert delivery:
kubectl get alerts -n flux-system -o wide
# Look for "Ready: True" — if False, your Provider config is broken
Gotchas to Know
- Wildcard
"*"only matches within the Alert's own namespace — cross-namespace alerting requires separate Alert objects per namespace - Secrets must use the
addresskey for webhook providers — noturl, notwebhook - Provider health isn't validated until an event fires — always run a test reconciliation after setup
eventSeverity: infoincludes successful syncs — your Slack will look like a firehose
TL;DR Checklist
- Create
Providerwith correct secret key (address) - Create
Alertpointing to that Provider - Set
eventSeverity: errorunless you want noise - Use
name: "*"wildcards to catch all resources of a type - Trigger a test reconciliation to verify delivery
- Check
kubectl get alerts -n flux-system— all should beReady: True
Silent GitOps failures are the worst kind. Five minutes of setup here saves hours of incident response later.
Was this article helpful?
Senior Cloud Architect
AWS, GCP, and Azure — I've built production workloads on all three. From landing zone design to multi-region failover, I architect cloud infrastructure that scales without surprises. Well-Architected Framework isn't a checklist, it's a mindset.
Related Articles
GitOps in Practice: ArgoCD vs Flux for Kubernetes Deployments
Side-by-side comparison of ArgoCD and Flux for GitOps on Kubernetes — architecture differences, sync behavior, multi-cluster, and when to choose each.
Sealed Secrets In GitOps: Managing Kubernetes Secrets Safely In Git Repositories
Managing Kubernetes secrets in Git is one of those problems that sounds simple until you accidentally push a base64-encoded password to a public repo. Seal...
ArgoCD Image Updater for Automated Container Deployments
Configure ArgoCD Image Updater to automatically detect and deploy new container images to Kubernetes without manual manifest changes or CI triggers.
ArgoCD Application Patterns: App of Apps, ApplicationSets, and Beyond
Practical ArgoCD patterns for managing dozens of applications — from App of Apps to ApplicationSets to multi-cluster rollouts. All in code, obviously.
Mozilla SOPS: Encrypted Secrets in Git for GitOps Workflows That Don't Leak
Use Mozilla SOPS to encrypt secrets in Git for secure GitOps workflows. Covers AGE, AWS KMS, and ArgoCD integration with real examples.
Grafana Alerting: Contact Points, Silences, and Escalation
Set up Grafana unified alerting with contact points, notification policies, silences, and on-call escalation that works in production.