Sending Flux CD notifications to Slack
Section 7, Lecture 2, from the Flux CD course by DevCloudLab.
What you’ll learn
- Create a Slack app with a bot token and an incoming webhook for Flux CD notifications
- Configure a Provider resource that tells Flux CD how to reach your Slack channel
- Configure an Alert resource that triggers on Kustomization, GitRepository, and HelmRelease events
- Filter notifications by event severity, and by event message using inclusion and exclusion lists
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:
- Provider: Defines how notifications are sent (Slack in this case), including the webhook URL and authentication.
- Alert: Defines what events trigger notifications (Kustomization, GitRepository, HelmRelease) and at what severity level.
Flux CD supports many notification platforms out of the box (Slack, Microsoft Teams, Telegram) and generic webhooks for custom integrations.
Prerequisites
- A working Kubernetes cluster with Flux CD installed (v2.2 or later, the first release with the
v1beta3notification API used here) - A Slack workspace where you have permission to create apps and webhooks
kubectlconfigured to access your clusterfluxCLI installed locally- A Git repository connected to your Flux cluster
Step-by-Step Instructions
1. Create a Slack App and Webhook
- 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. - Go to api.slack.com/apps
- Click Create an App → Blank app (earlier versions of this dialog called it From scratch)
- Name your app (e.g.,
fluxcd) - Select your Slack workspace
- Navigate to OAuth & Permissions in the left sidebar
- Under Bot Token Scopes, click Add an OAuth Scope and select
chat:write - Go to Incoming Webhooks in the left sidebar
- Toggle Activate Incoming Webhooks to On
- Click Add New Webhook to Workspace
- 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.
- Select the
#flux-cd-notificationschannel as the destination - Copy the Webhook URL from the new row on the Incoming Webhooks page
- 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:
type: slack: tells Flux to use Slack as the notification platformchannel: flux-cd-notifications: the Slack channel to send messages toaddress: the incoming webhook URL from Step 1 (anyone who can read it can post to your channel, so treat the file as sensitive)secretRef: references the Kubernetes secret containing the OAuth token
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:
eventSeverity: info: the default, which sends all updates. Set it toerrorto receive messages only when things go wrong.summary: optional short description included in Slack messages (max 255 characters). Note that.spec.summaryis deprecated atv1beta3: it still works, but the notification controller logsspecifying an alert summary with '.spec.summary' is deprecated, use '.spec.eventMetadata.summary' insteadon every event it sends. In new manifests, prefer asummarykey insideeventMetadataeventMetadata: key-value pairs sent with each notification (useful for filtering or routing). They are rendered as fields on the Slack messageeventSources: which resources to monitor. The*(wildcard) means all instances of that kindproviderRef: links to the Slack provider created above
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:
- GitRepository sync event (detecting the new files pushed)
- Kustomization reconciliation event, whose body reports the nginx deployment being created (
Deployment/default/nginx created)
Each message includes:
- The event source (e.g., GitRepository, Kustomization)
- The timestamp
- The event severity
- Any custom metadata you defined
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:
- Check the alert status:
flux get alerts -n flux-system - Review notification controller logs:
kubectl logs -n flux-system deployment/notification-controller -f - Verify the webhook URL is accessible and correct
- Ensure the secret contains the correct token:
kubectl get secret slack-secret -n flux-system -o jsonpath='{.data.token}' | base64 -d - Check that the Slack app is still installed in your workspace and the webhook is active
Alert not reconciling:
- Check for YAML syntax errors:
kubectl apply -f slack-provider.yaml --dry-run=client - Verify the provider name matches the
providerRefin the alert - Review Flux events:
flux logs --all-namespaces --follow
Too many notifications:
- Adjust
eventSeverityfrominfotoerrorto only alert on failures - Use
inclusionListandexclusionListto filter events by their message
Further Reading
- Flux CD Notification Controller Documentation
- Slack Incoming Webhooks API
- Flux CD Event Sources
- Notification Providers
- Flux CD: Setting Up Alerts (Notifications)
Built by DevCloudLab
Hands-on cloud-native courses: Kubernetes, GitOps, CI/CD and the cloud.
Visit DevCloudLab.com →
