7 min read

Gitops w/ FluxCD: Configuring FluxCD for Push-Based Reconciliation.

FluxCD, by default, does a pull-based reconciliation (or we have to wait for their configured intervals to pass). However, there is a remedy to this situation and we will discuss that in this article.

FluxCD employs a Pull-Based Reconciliation. After changes are made, manifests have to be checked into a repo, from where Kustomizations, periodically, find out what to update in the K8s infrastructure. Sometimes a check-i

💡
Manual reconciliation is triggered using:
flux reconcile kustomization <name of kustomization>
flux reconcile sources <type of source> <name of source>

FluxCD: Not A One-Trick Pony.

Fortunately, FluxCD can be configured for Push-Based Reconciliation as well.

  • The code will be checked in
  • The 'code-check-in event' will push (or trigger) the GitOps flow, and reconcile the infrastructure (without waiting for the documented intervals to elapse)

What would a Push-Based Reconciliation look like?

  • GitHub sends git events and an authentication token to a Reciever Service
  • GitHub sends the git push event to the webhook-receiver Service (which we will configure)
  • Notification Controller validates the authenticity of the payload using a token (which we will create)
  • Source Controller pulls the changes into the cluster and updates the instavote GitRepository object
  • The Kustomize Controller is notified about the revision change
  • Kustomize Controller reconciles all the Kustomizations that reference the GitRepository object

Demo: Configure a Push-Based Reconciliation GitOps Flow

This demo introduces the GitRepository Receiver object. This object contains the list of git events, the token used for authenticating messages from GitHub and a reference to the GitRepository Source Object (which for our series has been instavote).

As part of this demo, we will create 2 new objects (a token, shared between GitHub and the Push-Enabling FluxCD components, and a GitRepository Receiver) and edit some of the existing Kustomization manifests (gotk-components.yaml) to expose a public-facing webhook (for GitHub to send messages to).

💡
So far, right through the preceding articles, we have set a maximum of 1 minute for our Controller intervals. To demo a push, we should increase all intervals to 20 mins. All the steps to complete this demo follow.

Edit manifests and increase time intervals

Edit vote-staging-kustomization.yaml

Increase the interval to 20 minutes

Edit instavote-staging-gitrepository.yaml

Increase interval from 30 seconds to 20 minutes
💡
The external event(s) that will trigger the Push Based Reconciliation have to be sent to our

Expose a web service that is publicly accessible for GitHub to send messages to

To receive Git push or Helm chart upload events, you must expose a webhook receiver endpoint outside your Kubernetes cluster on a public address.

Surprisingly, FluxCD installs a Service called webhook-receiver as part of bootstrapping which can be used here.

💡
What is bootstrapping, you ask? Read this article.
kubectl get svc -n flux-system

The webhook-receiver Service is a ClusterIP service, by default, but needs signals from GitHub and, therefore, must be changed to either a LoadBalancer or NodePort Service type.

Since webhook-receiver is installed as a part of FluxCD bootstrapping, it MUST have a manifest in the flux-infra repo. Browsing through the flux-infra/clusters/staging/flux-system folders, we will find a webhook-receiver's manifest (gotk-components.yaml) file.

We can use our Kustomize experience (remember this article?) to create an overlay patch turning the webhook-receiver from ClusterIP to NodePort.

Title the patch webhook-receiver-service.yaml (code shown below).

apiVersion: v1
kind: Service
metadata:
 name: webhook-receiver
 namespace: flux-system
spec:
 ports:
 - name: http
   port: 80
   protocol: TCP
   targetPort: http-webhook
   nodePort: 31234
 selector:
   app: notification-controller
 type: NodePort

Kustomize needs to know where to look for the files which will be customized.

Edit the kustomization.yaml file in staging/flux-system/.

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- gotk-components.yaml
- gotk-sync.yaml
patches:
- webhook-receiver-service.yaml

Hold on. What is patchesStrategicMerge? The last time I made a Kustomization file I used patches.

The patches take the contents of the webhook-receiver-service.yaml file, find the exact sections in gotk-components.yaml and gotk-sync.yaml and replace them with the contents of the webhook-receiver-service.yaml manifest.

Still unclear? Let's look at the image below to appreciate the magic of patches.

First, list the files in the clusters/staging/flux-system folder.

When we execute the kustomize build command at the root of flux-system folder, Kustomize gets busy generating an edited manifest for gotk-*.yaml.

We can save the generated YAML into a temporary file using

kustomize build -o temp.yaml

Search for 'webhook-service' in temp.yaml and you should be able to see that webhook-service has been turned into a NodePort.

💡
Delete the temp.yaml file. It was created to confirm that Kustomize did what was expected of it.

Git-check new code/manifests

git add *
git commit -m 'comment'
git push origin main

Either manually reconcile the infrastructure or let the set interval elapse before checking the state of reconciliation.

flux get kustomizations
All's fine in the kustomization world

However, the real proof that kustomization worked is to confirm webhook-receiver was converted to a NodePort service.

kubectl get svc -n flux-system
🚰
Let's take a break and assess our progress.

So far, we have ONLY generated a NodePort Service that will listen for traffic and event information from GitHub.

Any traffic sent from GitHub to webhook-receiver Service must be authenticated for security any traffic sent from GitHub to webhook-receiver Service. After all, some malicious man-in-the-middle could corrupt the payload from Git to our cluster.

Generate a new K8s Secret to hold the shared token

# Generate a token
TOKEN=$(head -c 12 /dev/urandom | shasum | cut -d ' ' -f1)

# Save token. It will be used later.
echo $TOKEN

# Turn it into a Secret
kubectl -n flux-system create secret generic webhook-token \	
--from-literal=token=$TOKEN

Create a GitRepository Receiver

This Receiver will accept GitHub events, filter out those required and ignore those that are not.

flux create receiver instavote \
--type github \
--event ping \
--event push \
--secret-ref webhook-token \
--resource GitRepository/instavote \
The CLI command produces this YAML
  • 1: git events in scope (ping, push).
  • 2: The GitHub repo from where these events are originating.
  • 3: The shared token we just generated. This token is validated by the Notification Controller before letting any traffic pass through.
  • 4: The type of code repository the receiver is being made for.

At the end of this step, we have FluxCD components alive and ready.

Our focus now shifts towards GitHub.

Set up a webhook on GitHub

Remember that shared token made earlier? We do have to share it with GitHub.

To get the token, echo the value of $TOKEN.

echo $TOKEN

# The token should resemble this:
# e83d76derar7a85f44aabcgdaaea180b1e8c3

We also need the URL of the webhook-receiver Service. This URL will be saved as part of the webhook that will reside in GitHub.

flux get receivers
The Receiver URL starts at /hook.

Using the URL from the image and appending it to the Node IP and NodePort Port Number will give us the Payload URL.

Payload URL = http://<Node IP>:<NodePort Port>/hook.....

Load the instavote GitHub repository page.

  • Go to Settings --> Webhooks.
  • Click on Add Webhook.
  • Paste the Payload URL in its text box.
  • Paste the token in the Secret text box.
  • Select the Just the Push event radio button.

Check the Recent Deliveries tab to confirm everything worked.

Test the integration

It's time to put FluxCD's money where its mouth is. We can make a minor modification in the vote app by increasing the replica count from 2 to 5.

Before editing the vote-deployment.yaml file, make sure you know how many replicas are currently running.

Change the replicas in instavote/deploy/vote/staging/vote-deployment.yaml file from 2 to 5.

After code is checked in, check the replicas count.

Another check is to compare the SHA for the commit (in GitHub) and make sure it's the same for the vote-staging Kustomization.

If it walks like a duck and talks like a duck, can it be a hippo?

I write to remember, and if, in the process, I can help someone learn about Containers, Orchestration (Docker Compose, Kubernetes), GitOps, DevSecOps, VR/AR, Architecture, and Data Management, that is just icing on the cake.