GitOps is an approach to infrastructure management that relies on Git as the single source of truth for the desired state of infrastructure. All infrastructure configurations are typically stored and version-controlled in Git repositories, ensuring that the desired state is always accessible.

At the heart of GitOps lies the concept of continuous reconciliation. This continuous feedback loop ensures that the desired state of the infrastructure defined in Git repositories is reconciled with the actual state of the infrastructure. This automation eliminates the need for manual interventions, reducing errors and improving overall system stability.

This post will explore Flux, a popular open-source continuous delivery tool powered by GitOps

Prerequisites

To follow along, you would need the following installed locally:

Preparing the Git Repository

We'll begin by creating a new local git repository. Within your terminal, run the following commands:

# create a new directory 
mkdir flux-experiments
# change into the new directory 
cd flux-experiments 
# initialize a new git repository 
git init

Once these commands are executed, we'll have a local Git repository ready to store our Kubernetes manifests. Flux will use these manifests to manage and deploy our applications to the target cluster.

Creating a Deployment and Service

Now that we have our Git repository prepared, let's create the necessary files to deploy the application to Kubernetes using Flux. The application in question is Pong, a simple HTTP server that replies to requests on specific endpoints.

Creating the Manifests Directory

Within the flux-experiments directory we created, let's create a new subfolder named manifests to store our Kubernetes manifests:

mkdir manifests

This directory will contain all the necessary files for Flux to deploy and manage the Pong application.

Defining the Deployment Manifest

Within the manifests directory, create a file named pong-deployment.yaml. This file will define the deployment for the application. Add the following code:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: pong-server-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: pong-server
  template:
    metadata:
      labels:
        app: pong-server
    spec:
      containers:
      - name: pong-server
        image:  ghcr.io/s1ntaxe770r/pong:e0fb83f27536836d1420cffd0724360a7a650c13
        ports:
        - containerPort: 8080

Defining the Service Manifest

Next, create another file within the manifests directory named pong-service.yaml. This file defines the service for the application:

apiVersion: v1
kind: Service
metadata:
  name: pong-server-service
spec:
  selector:
    app: pong-server
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080

With these two manifests defined in the manifests directory, we have the necessary files to deploy and manage the Pong application using Flux.

Continue by adding and committing the files to git:

git add . 
git commit -m"add deployment manifests"

Next, let's create the repository on Github and push:

gh repo create flux-experiments --source=. --remote=upstream --public

This would create a new public repo called flux-experiments under your Github account. Finally, you can push the manifests:

git push

Bootstrapping Flux

Bootstrapping Flux involves deploying the necessary Flux components (controllers and associated resources) to your Kubernetes cluster. Flux installs the following four core components:

  • Source Controller:Watches the defined Git repository for changes in manifests.
  • Kustomization Controller:Applies Kustomize configurations to the manifests before deployment.
  • Helm Controller:Deploys applications packaged as Helm charts.
  • Notification Controller:Sends notifications about deployments and other events.

Before installing Flux, we can run pre-installation checks, which would verify our cluster is compatible with the version of Flux about to be installed. Within your terminal, run the following command:

flux check --pre

Upon success, your output should look like this:

Bootstrapping Flux

Export your Github Credentials: As part of the bootstrap process, Flux would require information about your GitHub account, export your Github username and personal access token you created earlier using the following commands:

# Your GitHub Personal Access Token
export GITHUB_TOKEN=<your-token>

# Your GitHub username
export GITHUB_USER=<your-username>

Run the Bootstrap Command:

flux bootstrap github \\                                                          
  --owner=$GITHUB_USER \\
  --repository=flux-experiments \\
  --branch=main \\
  --path=clusters/my-cluster

This command will:

  • Use the provided GitHub username and token to authenticate with your repository.
  • Install the Flux components in your Kubernetes cluster.
  • Configure Flux to watch your Git repository for changes and automatically deploy your applications.

Explanation of the Flags:

  • -owner: Specifies the owner of the GitHub repository containing your manifests.
  • -repository: Specifies the name of the GitHub repository.
  • -branch: Specifies the branch in the repository to watch for changes.
  • -path: Specifies the path within the repository where your manifests are located.

You should see the following output upon success:

Run the Bootstrap Command

To verify flux was successfully installed in our cluster, run the following command:

kubectl get pods -n flux-system

Verify flux was successfully installed

As part of the bootstrap process, Flux will push the deployment files used for the installation to the target repo. To get the latest changes run the following command:

git pull

Automating Deployments with Flux

So far, we have deployed and configured Flux to monitor a Git repository for changes, next, let's take a look at how we can configure Flux to monitor and deploy the manifests we created earlier.

Defining a GitRepository

The GitRepository is a custom resource provided by Flux that allows us to point to the Git repository containing our deployment manifests. This resource specifies the repository's location, branch, and interval at which Flux should check for changes.

To define a GitRepository for our app, we can utilize the Flux CLI and execute the following command:

flux create source git pong \\
  --url="" \\
  --branch=main \\
  --interval=30s \\
  --export > ./clusters/my-cluster/pong-source.yaml

This command defines a GitRepository resource named pong with the following details:

  • url: The URL of the Git repository containing the manifests.
  • branch: The branch of the repository to watch for changes.
  • interval: The interval at which Flux should check for changes (30 seconds).
  • export: Saves the generated YAML manifest to the ./clusters/my-cluster/pong-source.yaml file.

Generating a Kustomization Resource

Next, we need to define a Kustomization resource to customize the deployment of our application. This resource allows us to apply specific configurations and transformations to the manifests before deploying them to the target cluster.

We can generate the Kustomization resource using the following Flux CLI command:

flux create kustomization pong \\
  --target-namespace=default \\
  --source=pong \\
  --path="./manifests" \\
  --prune=true \\
  --interval=5m \\
  --export > ./clusters/my-cluster/pong-kustomization.yaml

This command defines a Kustomization resource named pong with the following configuration:

  • target-namespace: The Kubernetes namespace where the application will be deployed (default).
  • source: References the podinfo-app GitRepository resource.
  • path: Specifies the path within the repository where the Kustomization configuration file resides (./manifests).
  • prune: Enables automatic removal of deleted resources in the cluster.
  • interval: The interval at which Flux should check for changes (5 minutes).
  • export: Saves the generated YAML manifest to the ./clusters/my-cluster/pong-kustomization.yaml file.

You can inspect the generated manifests by running the command below:

cat ./clusters/my-cluster/pong-kustomization.yaml

You should have a similar manifest:

apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
  name: pong
  namespace: flux-system
spec:
  interval: 5m0s
  path: ./manifests
  prune: true
  sourceRef:
    kind: GitRepository
    name: pong
  targetNamespace: default

Trigger a deployment by making a commit and pushing the newly generated manifests to Github:

git add clusters/ && git commit -m" add kustomize manifests" && git push

To watch flux sync the application run the following command:

flux get kustomizations --watch

Your output should look something like this:

Generating a Kustomization Resource

Once the sync is complete, we can verify the application was deployed correctly using kubectl:

kubectl port-forward svc/pong-server-service 8080:80

In a separate terminal, call the service using Curl:

curl [localhost:8080/ping](<http://localhost:8080/ping>)

Output:

Pong

Updating the Pong App with Flux

Although we've successfully deployed the Pong application using Flux, real-world applications often require updates and modifications. Let's demonstrate how to update the deployment by scaling the number of replicas and deploying the changes using Flux.

Scaling the Deployment:

Edit the Manifest:

Open the pong-deployment.yaml file in a text editor.

Increase Replicas:

Locate the replicas field and change the value to your desired number. In this example, we'll increase it to 3:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: pong-deployment
spec:
  replicas: 3 # Increase to 3 replicas
  selector:
    matchLabels:
      app: pong
  template:
    metadata:
      labels:
        app: pong
    spec:
      containers:
      - name: pong
        image: ghcr.io/s1ntaxe770r/pong
        ports:
        - containerPort: 8080

Save and Commit:

Save the changes to the manifest and commit them to your Git repository:

git add pong-deployment.yaml
git commit -m "Scale pong deployment to 3 replicas"

Push to Git:

Push the committed changes to your remote Git repository:

git push origin main

Flux Detects and Deploys:

Flux automatically detects the changes in your Git repository and triggers a new deployment. You can verify the progress using the following command:

flux logs

Updating the Pong App with Flux

This command displays the logs of the deployment process, showing the creation of new pods and scaling to the desired number of replicas.

Verifying the Update:

Once the deployment is complete, you can verify the update using kubectl:

kubectl get pods

You should see that the number of pods has increased to 3.

Summary

In this post, we explored GitOps and some of its benefits and demonstrated how to deploy Flux and automate deployments using Kustomize. While we used Kustomize in this demonstration, Flux also supports Helm. Take a look at this post by deploying a Node.js application using Flux.