DevCloudLab More courses at DevCloudLab.com →
FLUX CD · SECTION 7 · LECTURE 2

DevCloudLab

Sending Flux CD notifications to Slack

Section 7, Lecture 2, from the Flux CD course by DevCloudLab.


What you’ll learn

Overview

This lecture demonstrates how to configure Flux CD’s notification controller to send real-time alerts to Slack whenever your cluster state changes. By integrating Flux CD with Slack, you can monitor deployments, Git repository syncs, and Helm releases without constantly checking your cluster manually.

The notification controller works through two key resources:

Flux CD supports many notification platforms out of the box (Slack, Microsoft Teams, Telegram) and generic webhooks for custom integrations.


Prerequisites


Step-by-Step Instructions

1. Create a Slack App and Webhook

  1. In your Slack workspace, create a dedicated channel named flux-cd-notifications (Slack adds the # itself). Every later step points at this channel by name.
  2. Go to api.slack.com/apps
  3. Click Create an App → Blank app (earlier versions of this dialog called it From scratch)
  4. Name your app (e.g., fluxcd)
  5. Select your Slack workspace
  6. Navigate to OAuth & Permissions in the left sidebar
  7. Under Bot Token Scopes, click Add an OAuth Scope and select chat:write
  8. Go to Incoming Webhooks in the left sidebar
  9. Toggle Activate Incoming Webhooks to On
  10. Click Add New Webhook to Workspace
  11. Slack asks for permission to install the app in your workspace: click Allow. This is the click that installs the app, and installing it is what creates the bot token.
  12. Select the #flux-cd-notifications channel as the destination
  13. Copy the Webhook URL from the new row on the Incoming Webhooks page
  14. Go back to OAuth & Permissions and copy the Bot User OAuth Token at the top of the page (it starts with xoxb-). In a brand-new app this token does not exist until the app has been installed, which is why it comes last.

You now have two critical values. Store them in two environment variables in your terminal, so the real values never appear in the commands that follow:

export SLACK_BOT_TOKEN='<paste your Bot User OAuth Token>'
export SLACK_WEBHOOK_URL='<paste your Webhook URL>'

2. Create a Kubernetes Secret

Store the OAuth token as a Kubernetes secret in the flux-system namespace:

kubectl create secret generic slack-secret \
  --from-literal=token="$SLACK_BOT_TOKEN" \
  -n flux-system

Verify the secret was created:

kubectl get secret slack-secret -n flux-system

3. Create the Slack Provider

Create a slack/ directory in your Git repository, then let the flux CLI generate the provider and export it to a YAML file, so it can be committed to Git:

mkdir -p slack
cd slack

flux create alert-provider slack \
  --type slack \
  --channel flux-cd-notifications \
  --address "$SLACK_WEBHOOK_URL" \
  --secret-ref slack-secret \
  --export > slack-provider.yaml

The command prints nothing; slack-provider.yaml now exists. View it with cat slack-provider.yaml:

---
apiVersion: notification.toolkit.fluxcd.io/v1beta3
kind: Provider
metadata:
  name: slack
  namespace: flux-system
spec:
  address: https://hooks.slack.com/services/...
  channel: flux-cd-notifications
  secretRef:
    name: slack-secret
  type: slack

What this does:

No additional changes are needed to the provider.

4. Create the Alert Resource

Define which Flux CD events trigger notifications, again with the CLI:

flux create alert \
  --event-severity info \
  --event-source 'Kustomization/*' \
  --event-source 'GitRepository/*' \
  --event-source 'HelmRelease/*' \
  --provider-ref slack \
  flux-system \
  --export > reconciliation-alert.yaml

The command cannot set every field, so open reconciliation-alert.yaml in your editor and add summary and eventMetadata under spec. The file should end up like this:

---
apiVersion: notification.toolkit.fluxcd.io/v1beta3
kind: Alert
metadata:
  name: flux-system
  namespace: flux-system
spec:
  eventSeverity: info
  summary: "Flux CD notification"
  eventMetadata:
    env: "staging"
    cluster: "flux-cd-notification"
  eventSources:
  - kind: Kustomization
    name: '*'
  - kind: GitRepository
    name: '*'
  - kind: HelmRelease
    name: '*'
  providerRef:
    name: slack

What this does:

Commit both files to your repository:

cd ..
git add slack/
git commit -m "Add Slack notification configuration"
git push

5. Reconcile Flux CD

Apply the new resources to your cluster:

flux reconcile kustomization flux-system --with-source

flux reconcile prints ✔ fetched revision main@sha1:… and then ✔ applied revision main@sha1:…. It does not print a health summary.

One thing to check if nothing arrives: Flux only builds the path it was bootstrapped with. If your cluster was bootstrapped with, say, --path=./clusters/staging, then manifests committed at the repository root are never applied, and the reconcile above still reports success, because the path it does watch is healthy. Confirm with:

kubectl get kustomization flux-system -n flux-system -o jsonpath='{.spec.path}'

Verify the alert was created:

flux get alerts -n flux-system

You should see output similar to:

NAME          SUSPENDED   READY   MESSAGE
flux-system   False       True    Alert is Ready

6. Test the Setup

Create a test Kubernetes resource to trigger a notification:

mkdir -p nginx
cd nginx

Create deployment.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
  namespace: default
  labels:
    app: nginx
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: web
        image: nginx:1.24-alpine
        ports:
        - containerPort: 80

Commit and push:

cd ..
git add nginx/
git commit -m "Add nginx deployment for testing"
git push

Reconcile:

flux reconcile kustomization flux-system --with-source

Check your Slack channel. You should see messages like:

Each message includes:

The metadata arrives as fields under the message body. The title is the source object in lower case with a dot before its namespace, and the body is the event message itself, so the Kustomization event that applies the deployment above looks like this in the channel:

kustomization/flux-system.flux-system

Deployment/default/nginx created

summary   Flux CD notification
revision  main@sha1:8e0895708b160a13da5c112e5f74c239a5f61134
cluster   flux-cd-notification
env       staging

The four fields come from a map, so their order changes from one message to the next. The revision is the full commit sha, not the short one Git printed.

7. Fine-Tune Notifications (Optional)

You can filter notifications using inclusion and exclusion lists. Both are lists of regular expressions that Flux matches against the event message (not the name of the object that raised it). With an exclusionList, any event whose message matches is not sent. With an inclusionList, only events whose message matches are sent. When a message matches both, the exclusion list wins.

In this example both lists match the string “invalid”, so the exclusion rule takes precedence and no event whose message contains “invalid” is sent:

apiVersion: notification.toolkit.fluxcd.io/v1beta3
kind: Alert
metadata:
  name: flux-system
  namespace: flux-system
spec:
  eventSeverity: info
  eventSources:
  - kind: Kustomization
    name: '*'
  - kind: GitRepository
    name: '*'
  providerRef:
    name: slack
  # Only send events whose message matches (inclusion)
  inclusionList:
  - ".*invalid.*"
  # Never send events whose message matches (exclusion takes precedence)
  exclusionList:
  - ".*invalid.*"

Common Commands

Command Purpose
flux get alerts -n flux-system List all alerts in the flux-system namespace
flux get alert-providers -n flux-system List all notification providers
kubectl get secret slack-secret -n flux-system -o yaml View the Slack secret (values are base64-encoded)
flux reconcile alert flux-system -n flux-system Manually trigger an alert reconciliation
kubectl logs -n flux-system deployment/notification-controller -f View notification controller logs

Complete Manifests

slack-provider.yaml

apiVersion: notification.toolkit.fluxcd.io/v1beta3
kind: Provider
metadata:
  name: slack
  namespace: flux-system
spec:
  type: slack
  channel: flux-cd-notifications
  address: https://hooks.slack.com/services/<T-ID>/<B-ID>/<secret>
  secretRef:
    name: slack-secret

reconciliation-alert.yaml

apiVersion: notification.toolkit.fluxcd.io/v1beta3
kind: Alert
metadata:
  name: flux-system
  namespace: flux-system
spec:
  eventSeverity: info
  summary: "Flux CD notification"
  eventMetadata:
    env: "staging"
    cluster: "flux-cd-notification"
  eventSources:
  - kind: Kustomization
    name: '*'
  - kind: GitRepository
    name: '*'
  - kind: HelmRelease
    name: '*'
  providerRef:
    name: slack

API Versions: Important

This lecture uses notification.toolkit.fluxcd.io/v1beta3 for Alert and Provider resources. Note that in the same API group, Receiver is stable at v1. Do not assume all resources in an API group use the same version. If you get an error like “no matches for kind Alert”, run kubectl api-resources --api-group=notification.toolkit.fluxcd.io on your cluster to see which version each resource actually supports.


Troubleshooting

No messages in Slack:

  1. Check the alert status: flux get alerts -n flux-system
  2. Review notification controller logs: kubectl logs -n flux-system deployment/notification-controller -f
  3. Verify the webhook URL is accessible and correct
  4. Ensure the secret contains the correct token: kubectl get secret slack-secret -n flux-system -o jsonpath='{.data.token}' | base64 -d
  5. Check that the Slack app is still installed in your workspace and the webhook is active

Alert not reconciling:

  1. Check for YAML syntax errors: kubectl apply -f slack-provider.yaml --dry-run=client
  2. Verify the provider name matches the providerRef in the alert
  3. Review Flux events: flux logs --all-namespaces --follow

Too many notifications:


Further Reading


DevCloudLab

Built by DevCloudLab
Hands-on cloud-native courses: Kubernetes, GitOps, CI/CD and the cloud.
Visit DevCloudLab.com →