Webhook receivers
By default, Flux polls each GitRepository on its configured interval: to detect new commits. If you want changes to be applied fast - typically for an actively developed repo - you set the interval to a low value at the cost of Flux hitting your repo every minute.
You can also use a push based system using Flux' webhook receiver: the Git provider POSTs to a URL on push, Flux verifies the payload, and reconciliation starts within a second or two.
The Haven+ FluxCD reference implementation provides HTTPRoutes for the webhooks as well as example Receiver objects for GitLab and GitHub.
Setting up a Receiver for a new tenant
Copy the Receiver (GitLab or GitHub) and the token Secret from tenants/tenant-demo/ in the gitops-flux repo.
Generating the webhook token
The token is a shared secret between the Git provider and the Flux Receiver. You can create it using:
TOKEN=$(openssl rand -hex 16)
echo "$TOKEN" # e.g. 8f3c2a1b9d4e5f6a7b8c9d0e1f2a3b4c
Keep $TOKEN around — you will paste it into the Git provider's webhook configuration (raw, unencrypted) and into the Kubernetes Secret (encrypted, see below).
Encrypting the token with Sealed Secrets
The token Secret lives in flux-system (alongside the Receivers). It must be encrypted before it is committed to Git. The Haven+ reference implementation uses Sealed Secrets for this.
Use the $TOKEN from the previous step to create a secret.yaml:
apiVersion: v1
kind: Secret
metadata:
name: webhook-token
namespace: flux-system
type: Opaque
stringData:
token: <TOKEN>
Next, use kubeseal to generate a sealed-secret based on the secret above:
kubeseal -f secret.yaml -w flux-webhook-token.sealed.yaml --controller-namespace sealed-secrets -n flux-system
Registering the webhook with the Git provider
After Flux has applied the Receivers, each one publishes a unique webhook path under .status.webhookPath. Combine that with the cluster's flux.<cluster-domain> hostname (configured in infrastructure/flux-webhook-receiver/overlays/<cluster>/patches/http-route.yaml) to get the full URL:
GITLAB_PATH=$(kubectl get receiver [receiver]-gitlab -n flux-system -o jsonpath='{.status.webhookPath}')
GITHUB_PATH=$(kubectl get receiver [receiver]-github -n flux-system -o jsonpath='{.status.webhookPath}')
echo "GitLab webhook URL: https://flux.<cluster-domain>${GITLAB_PATH}"
echo "GitHub webhook URL: https://flux.<cluster-domain>${GITHUB_PATH}"
Then register the webhook at the provider:
- GitLab — Project → Settings → Webhooks. Paste the URL, set "Secret token" to the raw
$TOKEN, enable Push events and Tag push events, leave SSL verification on. See the GitLab webhook documentation for the full set of options and event types. - GitHub — Repository → Settings → Webhooks → Add webhook. Paste the URL as Payload URL, content type
application/json, set Secret to the raw$TOKEN, and at minimum enable Pushes. See the GitHub webhooks documentation for an overview and Creating webhooks for the step-by-step.
Increase reconciliation intervals
Once the webhooks are working, polling intervals become less important and can be increased to on the following resources:
GitRepository— the source the Receiver reconciles. With a webhook firing on every push, the pollinginterval:can comfortably move from the default1mto e.g.1h.Kustomization— when itssourceRefpoints at the webhook-drivenGitRepository, the Kustomization re-applies as soon as the source changes, regardless of its own interval.ImageUpdateAutomation— webhooks from a container registry can drive image automation the same way through a registry-specific Receiver type. With that wired up the IUAinterval:becomes a fallback too. Provider support varies, though: GitHub fires apackagewebhook event on every push to GHCR, so image-push events are available end-to-end. GitLab does not emit project webhooks for its Container Registry — pushes to the GitLab Container Registry don't fire any event in the project webhook event list, so on GitLab-only setups the IUA must keep polling at itsinterval:.