Flux Notification Controller: commit status, Telegram, and Mattermost

Published: 2026-03-01

Flux ships with a Notification Controller that turns reconciliation events into webhooks. Two primitives: Provider (where to send) and Alert (what to send and when). This covers commit status badges in GitLab, Telegram via generic webhook, and organizing notifications per environment.


Providers

GitLab commit status

Sets a pipeline status on the commit that triggered a Flux reconcile. Engineers see a green/red badge directly in the GitLab MR:

yamlapiVersion: notification.toolkit.fluxcd.io/v1beta3
kind: Provider
metadata:
  name: gitlab-status
  namespace: flux-system
spec:
  type: gitlab
  address: https://gitlab.example.com
  secretRef:
    name: gitlab-token
---
apiVersion: v1
kind: Secret
metadata:
  name: gitlab-token
  namespace: flux-system
stringData:
  token: "${GITLAB_TOKEN}"

The token needs api scope on the account that owns the repo. Store it in Vault and use External Secrets Operator to create the Secret.

Telegram via generic webhook

Flux doesn't have a native Telegram provider, but generic sends a JSON POST to any URL. Combine it with abot:

yamlapiVersion: notification.toolkit.fluxcd.io/v1beta3
kind: Provider
metadata:
  name: telegram
  namespace: flux-system
spec:
  type: generic
  address: http://abot.observability.svc.cluster.local:9444/flux

abot needs a /flux endpoint that accepts Flux's event JSON and reformats it into Telegram HTML. Alternatively, use the telegram provider type with a bot token directly if you don't need proxy support:

yamlspec:
  type: telegram
  address: https://t.me/bot_token
  channel: "-100123456789"
  secretRef:
    name: telegram-bot-token

Mattermost

yamlapiVersion: notification.toolkit.fluxcd.io/v1beta3
kind: Provider
metadata:
  name: mattermost
  namespace: flux-system
spec:
  type: mattermost
  address: https://chat.example.com/hooks/infra-flux-hook

Alerts

An Alert selects which objects to watch, filters by event severity, and routes to a Provider.

Notify on HelmRelease failures

yamlapiVersion: notification.toolkit.fluxcd.io/v1beta3
kind: Alert
metadata:
  name: helmrelease-failures
  namespace: flux-system
spec:
  summary: "HelmRelease failed in dev"
  providerRef:
    name: telegram
  eventSeverity: error
  eventSources:
    - kind: HelmRelease
      namespace: dev
      name: "*"

name: "*" matches all HelmRelease objects in the dev namespace. eventSeverity: error means only failed reconciles trigger a notification — successful ones are silent.

Notify on any Kustomization change

yamlapiVersion: notification.toolkit.fluxcd.io/v1beta3
kind: Alert
metadata:
  name: kustomization-applied
  namespace: flux-system
spec:
  summary: "Kustomization applied"
  providerRef:
    name: gitlab-status
  eventSeverity: info
  eventSources:
    - kind: Kustomization
      namespace: "*"
      name: "*"

This creates a GitLab commit status for every Kustomization reconcile — success or failure. Engineers see which cluster layer applied successfully from the MR view.

Notify on image updates

yamlapiVersion: notification.toolkit.fluxcd.io/v1beta3
kind: Alert
metadata:
  name: image-update
  namespace: flux-system
spec:
  summary: "Image auto-update"
  providerRef:
    name: telegram
  eventSeverity: info
  eventSources:
    - kind: ImageUpdateAutomation
      namespace: "*"
      name: "*"

Notifies when Flux automatically bumps an image tag after a new CI build.


Event payload

The generic provider sends:

json{
  "involvedObject": {
    "kind": "HelmRelease",
    "name": "elasticsearch",
    "namespace": "dev"
  },
  "severity": "error",
  "reason": "UpgradeFailed",
  "message": "Helm upgrade failed: rendered manifests contain a resource...",
  "timestamp": "2026-03-01T12:34:56Z"
}

The message field has the full Flux error — the same text you'd see in flux get helmreleases.


Structuring Alerts per cluster

All Alerts live in spoke/notifications/ and are applied by the spoke Kustomization. Each environment has its own Alerts pointing to its own namespace:

spoke/
  notifications/
    provider-telegram.yaml
    provider-gitlab.yaml
    alert-helmrelease-errors.yaml
    alert-kustomization-status.yaml

This way, a failure in dev only fires the dev channel, not the production channel.


Debugging

bash# Check notification controller logs
kubectl logs -n flux-system deploy/notification-controller -f

# Check Provider health
kubectl get provider -n flux-system

# Check Alert status
kubectl describe alert helmrelease-failures -n flux-system

# Force a test event (trigger reconcile on a HelmRelease)
flux reconcile helmrelease my-app -n dev

If notifications aren't arriving, check:

  1. kubectl get provider -n flux-system — should be Ready
  2. Controller logs for HTTP errors when posting to the webhook URL
  3. The Alert's eventSeverity — ensure it matches the event type you expect