GitHub Actions FluxCD & Helm

ALT TEXT

In the upcoming blog post, we will implement continuous integration and deployment with Helm and some GitOps characteristics

Guidelines

The primary focus of this blog post is to explore and showcase three key topics:

  1. Utilizing GitHub Actions Workflow
  2. Implementing deployment through Helm, with an emphasis on basic templating techniques
  3. Employing FluxCD for deployment and its integration with the HelmRelease resource and Image Automation

Considering that the blog post serves as an illustrative example, it's important to note that there are additional aspects of Continuous Integration (CI) and Continuous Deployment (CD) that are not covered in detail here. For instance, in the realm of CI, aspects such as testing methodologies and strategies play a crucial role. Similarly, in the CD complex processes within the workflow are also beyond the scope of this example.

Repository Structure

There are several ways to structure FluxCD repository More information can be found here. For the sake of simplicity in this tutorial, we will utilize a monorepo approach, consolidating all Kubernetes manifests within a single Git repository.

This is a simple Java Maven repository that was forked from here and on top of it we`ve added

  1. Dockerfile with simple multistage
  2. Two ways of deployment
    1. Kubectl and Helm CLIs
    2. FluxCD
      1. Using HelmRelease
      2. Using Flux Image Controller / Policy
  3. The above are orchestrated as CI and CD via GitHub Action Workflow

Our repository is structured in a manner of a monorepo, yet it has been simplified for the purposes of this example. This streamlined approach retains the core characteristics of a monorepo while ensuring ease of understanding and accessibility for demonstration purposes.

High level structure:

├── myapp (Java, Maven and Docker)
└── deployment
    ├── myapp-chart (Helm Chart)
    └── flux
        ├── apps
        │   └── base
        ├── infrastructure
        │   └── dev
        └── clusters
            └── dev

GitHub Workflow

We've breaken our pipline into three GitHub Action jobs): app-build, docker-build and deployment. Refer to the workflow yaml located at .github/workflows/myapp-workflow.yaml for detailed information about the jobs and steps. Note: In case you want to run it on your repository make sure to create PAT in order to get repository access (same as describe below for setting GITHUB_TOKEN in order to locally run FluxCD)

  • app-build: Java build using Maven. i.e. mvn clean package
  • docker-build: In this phase, we build the container using the Dockerfile, just for the example the Dockerfile includes multilayer. This job stars running only after a succesful complition of app-build phase.
  • deployment: triggering three independent jobs:
    • Simple docker run
    • Kind cluster installation and Helm CLI (using the utility script)
    • Kind cluster installation and FluxCD bootstrap (using the utility script)

GitHub Action Summary At the buttom of the image you can see the logs of Helm CLI & FluxCD bootstrap steps (printing out the POD logs as explianed below).

Note: The repository also demostrate some branch protection:

  • Require a pull request & approvals before merging
  • Require status checks to pass before merging, it will run the app-build as part of the pull request GitHub Branch Protection

Deployment

For your convinence you can use two utlity scripts:

  1. setup.sh - Setup the required softwares (the same script called during the CI/CD workflow)
  2. deploy.sh - Automate the deployment proccess for both options: Kubectl & Help CLIs as well as using FluxCD

Using Kubectl and Helm CLI

Executing the script:

cd deployment
./deploy.sh -v 1.0.0

The script will install KIND Cluster and once the cluster is ready it will start the deployment using Helm Chart located at deployment/myapp-chart using values-dev.yaml templating as well as --set image.tag=${VERSION} as was set using the -v flag.

Using FluxCD

Make to create and set GITHUB_TOKEN

Or if you are using different Git server follow the bootstrap documentation

You`ll need to set the both GITHUB_TOKEN & GITHUB_USER, it will be used by the utitlity script for FluxCD bootstrap command:

export GITHUB_TOKEN=<YOUR_PAT>
export GITHUB_USER=<YOUR_GH_USER>

Executing the script:

cd deployment
./deploy.sh --flux

Verify Flux PODs

The following pods should be running on flux-system namespace

kubectl get pod -n flux-system

NAME                                           READY   STATUS    RESTARTS   AGE
helm-controller-69dbf9568-tp4x6                1/1     Running   0          2m5s
image-automation-controller-6bbc947558-h82k6   1/1     Running   0          2m5s
image-reflector-controller-7c49fdc68f-skrjs    1/1     Running   0          2m5s
kustomize-controller-77bf676476-cj5rr          1/1     Running   0          2m5s
notification-controller-7bb6d7684d-k9s9l       1/1     Running   0          2m5s
source-controller-5996567c74-kt5nt             1/1     Running   0          2m5s

Exploring Flux Kustomizations

Flux manage the deployment and its dependencies using a kustomization resource. To watch the kustomizations list and thier status:

flux get kustomizations

NAME                REVISION            SUSPENDED   READY   MESSAGE                              
flux-system         master@sha1:d27dac72    False       True    Applied revision: master@sha1:d27dac72  
myapp-dev           master@sha1:d27dac72    False       True    Applied revision: master@sha1:d27dac72

Checking the logs

Once the deployment is done, the script will get the POD i.e. myapp-6fc4d44c75-4jpvg logs and pring it out.

Starts new deployment...
Version: Managed By FluxCD
Deploy using FluxCD

deployment "myapp" successfully rolled out
POD Image Details:
Image: devozs/myapp:1.0.0
Image ID: docker.io/devozs/myapp@sha256:0ac0962589fa30ca8d09f073a33fe7791359a295324aa237e2c5b6980f848415
POD Logs:
Hello World! DevOzs
Deployment Done

Secrets

In this tutorial, we haven't utilized a secret manager like Azure Key Vault or any other valut. In case you need to use secrets (i.e when using Flux Image Repository with private regitry) make sure not to keep your secrets in Git.

Make sure not to put your kubernetes secrets in Git

For testing purpuse you can add them to gitignore. Permenant solution would be to use key vault or other solution like sealed-secrets (works well with FluxCD)

Docker Pull Secret

In case you are workign with images from private registry, Docker pull secret is will used in two ways:

  • Pull the deployment image from Github registry
  • FluxCD uses it to fetch new tags from Github registry
apiVersion: v1
kind: Secret
metadata:
  name: cr-secret
  namespace: flux-system
type: kubernetes.io/dockerconfigjson
data:
  .dockerconfigjson: <PUT_YOURS>
---
apiVersion: v1
kind: Secret
metadata:
  name: cr-secret
  namespace: dev
type: kubernetes.io/dockerconfigjson
data:
  .dockerconfigjson: <PUT_YOURS>

The FluxCD Magic 🪄

We are using two powerful Flux capabilities:

  • Listen to new images in a certian repository and given pattern
apiVersion: image.toolkit.fluxcd.io/v1beta1
kind: ImagePolicy
metadata:
  name: myapp
  namespace: flux-system
spec:
  imageRepositoryRef:
    name: myapp
  policy:
    semver:
      range: 1.0.x
apiVersion: image.toolkit.fluxcd.io/v1beta1
kind: ImageRepository
metadata:
  name: myapp
  namespace: flux-system
spec:
  image: devozs/myapp
  interval: 1m0s
flux get image policy -A
NAMESPACE   NAME    LATEST IMAGE        READY   MESSAGE                                                           
dev         myapp   devozs/myapp:1.0.40 True    Latest image tag for 'devozs/myapp' updated from 1.0.39 to 1.0.40   

flux get image repository   
NAMESPACE   NAME    LAST SCAN                   SUSPENDED   READY   MESSAGE                        
dev         myapp   2023-12-18T00:43:48+02:00   False       True    successful scan: found 41 tags
  • Update the resolved image tag in the relevant Kubernetes yaml (directly to the Deployment YAML or vie Kustomization YAML)
apiVersion: image.toolkit.fluxcd.io/v1beta1
kind: ImageUpdateAutomation
metadata:
  name: image-update-automation
  namespace: flux-system
spec:
  interval: 1m10s
  sourceRef:
    kind: GitRepository
    name: flux-system
  git:
    checkout:
      ref:
        branch: main
    commit:
      author:
        email: fluxcdbot@users.noreply.github.com
        name: fluxcdbot
      messageTemplate: '{{range .Updated.Images}}{{println .}}{{end}}'
    push:
      branch: main
  update:
    path: ./gitops/clusters/dev
    strategy: Setters