Introduction
Jenkins is a popular CI (Continuous Integration) tool for automating, building, and testing projects. It divides the job into various pipeline stages for this process. Jenkins is extended sometimes as a CD (Continuous Deployment) server for getting projects deployed to the required environments such as testing, staging, production etc.
Now, why extend a tool primarily developed for CI to CD, when modern CD tools like FluxCD make use of GitOps principles?
FluxCD makes sure that the services deployed to a kubernetes cluster are in line with the description provided in the manifest files committed in a Git repo. Thus every deployment whether new or upgraded is recorded as a series of Git commits. This gives one many advantages of version control and reliable-cum-faster deployments. To know more about how GitOps can help you, see What is GitOps.
Entrusting the responsibility of CD to Flux will give us a clear boundary between CI and CD. We understand that CI builds are unstable whereas deployment needs reliability. In this tutorial we will connect Jenkins with Flux and deploy an example application (docker image) to a kubernetes cluster.
Overview
Once the project is built to a tag, Jenkins tests it and deploys it to a container registry. In this example, let’s assume that Jenkins is using docker for containerization and pushes it to the docker hub. Of course the example is a container-tech antagonist and you are free to choose.
Flux deploys applications from a manifest file (in a Git repo) which refers to a specific version of image to be deployed, and makes sure that the deployed application remains true to the version and other information (eg: number of replicas) as specified in the manifest file.
What we require is a way to automatically update the specific version inside the manifest file according to the version of image in the docker hub. In this way, whatever image Jenkins pushes with a specific tag, the information is committed to Git repo and image is further deployed (with certain rules) to a cluster.
FluxCD provides us this feature with the name ‘auto image updation’
Prerequisites
- A running kubernetes cluster with flux installed.
- A flux client on our system to access the remote flux controllers.
- A Jenkins pipeline pushing to an image hub.
- Git installed on the system.
The automatic image updation feature is not installed by default when we bootstrap flux.
It requires a special controller provided by flux, to install it:
Rerun bootstrap with `–components-extra=image-reflector-controller, image-automation-controller
or, apply these CRDs to cluster and bootstrap again.
kubectl apply -f https://raw.githubusercontent.com/fluxcd/image-automation-controller/main/config/crd/bases/image.toolkit.fluxcd.io_imageupdateautomations.yaml
kubectl apply -f https://raw.githubusercontent.com/fluxcd/image-reflector-controller/main/config/crd/bases/image.toolkit.fluxcd.io_imagerepositories.yaml
kubectl apply -f https://raw.githubusercontent.com/fluxcd/image-reflector-controller/main/config/crd/bases/image.toolkit.fluxcd.io_imagepolicies.yaml
Refer, Flux Installation to know how to bootstrap flux on a cluster and also set up a flux client.
Working directory
An example for a working directory and explanation of the various terms is given below:
Working Directory:
flux-test
clusters
my-cluster
podinfo-deployment.yaml
podinfo-policy.yaml
podinfo-registry.yaml
flux-system
gotk-components.yaml
gotk-sync.yaml
Kustomization.yaml
podinfo-deployment.yaml – Specifies that flux should deploy a service named podinfo into the cluster.
podinfo-registry.yaml – Specifies a resource of type ImageRepository which points to the container registry in which new tags have to be scanned. The container registry will be the same in which jenkins pushes the tags.
podinfo-policy.yaml – Specifies the rules/policy by which a tag must adhere to if it has to be automatically pulled. It references an image repository.
flux-system-automation.yaml – Specifies a resource of type ImageUpdateAutomation. Through this, flux will know exactly in which file image version update is required, and what should be the commit message by executing the image policy files at a specific interval.
flux-system – Contains manifest files of flux components made by flux bootstrap command.
Next comes the steps to be followed for the demonstration. Make sure to change username, imagename, tag etc at your discrimination! I have used my personal project and logs as an example.
Clone your Git repository
Clone your git repository using the command given below:
sh
git clone https://github.com//flux-test
cd flux-test
Create a deployment of your service
Create a deployment of your service. Inside clusters/my-cluster create a file named, podinfo-deployment.yaml with tag reference. The image name must be the same as the one pushed by jenkins pipeline. I have used a fork of podinfo app by stefanprodan
apiVersion: apps/v1
kind: Deployment
metadata:
name: podinfo
namespace: default
spec:
selector:
matchLabels:
app: podinfo
template:
metadata:
labels:
app: podinfo
spec:
containers:
- name: podinfod
image: docker.io/utkarshopsmx/podinfo:1.0.0
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 9898
protocol: TCP
You can either wait or force flux to pull and apply changes:
flux reconcile kustomization flux-system --with-source
Check the podinfo deployed on your cluster:
kubectl get deployment/podinfo -oyaml | grep 'image:'
Create an ImageRepository
Now, create an image repository. This will start the image scanning by flux system at regular intervals.
Either use the command:
flux create image repository podinfo \
--image=docker.io/utkarshopsmx/podinfo \
--interval=5m \
--export > ./clusters/my-cluster/podinfo-registry.yaml
or copy-paste the below manifest:
apiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImageRepository
metadata:
name: podinfo
namespace: flux-system
spec:
image: docker.io/utkarshopsmx/podinfo
interval: 5m0s
If the image is private (usually they are), create a Kubernetes secret in the same namespace as the ImageRepository by executing the below command:
kubectl create secret docker-registry
Then configure Flux to use the credentials by referencing the Kubernetes secret in the ImageRepository:
kind: ImageRepository
spec:
secretRef:
name: regcred
Commit and push the above changes.
Create an ImagePolicy
The next step is to create an ImagePolicy. In our case, flux will be informed as to which version of the image it should pull.
flux create image policy podinfo \
--image-ref=podinfo \
--select-semver=1.0.x \
--export > ./clusters/my-cluster/podinfo-policy.yaml
Or copy-paste:
apiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImagePolicy
metadata:
name: podinfo
namespace: flux-system
spec:
imageRepositoryRef:
name: podinfo
policy:
semver:
range: 1.0.x
Refer ImagePolicy Examples, to know about various policy examples.
Commit and push the above changes.
Force flux to reconcile by executing the below command:
flux reconcile kustomization flux-system --with-source
Check if the `ImageRepository` has scanned the latest tag from registry:
$ flux get image repository podinfo
NAME LAST SCAN SUSPENDED READY MESSAGE
podinfo 2024-05-02T11:34:48+05:30 False True successful scan: found 2 tags
To see sample of tags scanned, execute the below command:
kubectl -n flux-system describe imagerepositories podinfo
To find which image tag matches the policy semantice version range, execute the below command:
$ flux get image policy podinfo
NAME LATEST IMAGE READY MESSAGE
podinfo docker.io/utkarshopsmx/podinfo:1.0.2 True Latest image tag for 'doker.io/utkarshopsmx/podinfo' resolved to 1.0.2
Configure Image Updates:
Edit the podinfo-deployment file to mark the tagline with the specific image policy. That policy will be used to update the image.
image: doker.io/utkarshopsmx/podinfo:1.0.0 # {"$imagepolicy": "flux-system:podinfo"}
Now create an ImageUpdateAutomation to specify the Git Repository we need to write the image updates:
flux create image update flux-system \
--interval=10m \
--git-repo-ref=flux-system \
--git-repo-path="./clusters/my-cluster" \
--checkout-branch=main \
--push-branch=main \
--author-name=fluxcdbot \
--author-email=fluxcdbot@users.noreply.github.com \
--commit-template="{{range .Changed.Changes}}{{print .OldValue}} -> {{println .NewValue}}{{end}}" \
--export > ./clusters/my-cluster/flux-system-automation.yaml
Or copy-paste:
apiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImageUpdateAutomation
metadata:
name: flux-system
namespace: flux-system
spec:
git:
checkout:
ref:
branch: main
commit:
author:
email: fluxcdbot@users.noreply.github.com
name: fluxcdbot
messageTemplate: '{{range .Changed.Changes}}{{print .OldValue}} -> {{println
.NewValue}}{{end}}'
push:
branch: main
interval: 5m0s
sourceRef:
kind: GitRepository
name: flux-system
update:
path: ./clusters/my-cluster
strategy: Setters
Commit and push the changes.
Testing our setup:
Run the Jenkins pipeline to push a new tag to docker hub. Either wait for some time to let flux update the changes or force flux to reconcile immediately.
Now check the latest version of your git repo and lookout for the image line in the deployment file.
You will see that the file has been updated:
$ git pull && cat clusters/my-cluster/podinfo-deployment.yaml | grep "image:"
image: ghcr.io/stefanprodan/podinfo:1.0.2 # {"$imagepolicy": "flux-system:podinfo"}
Check the latest deployment in cluster:
$ watch "kubectl get deployment/podinfo -oyaml | grep 'image:'"
image: ghcr.io/stefanprodan/podinfo:1.0.2
The manifest file was updated after, flux observed a new tag pushed by jenkins and finally deployed the tag to the cluster.
Additional changes
It’s recommended that the registry is private and to access the registry one can create a kubernetes secret and refer it in the policy:
kubectl create secret docker-registry
kind: ImageRepository
spec:
secretRef:
name: regcred
Refer ImagePolicy Examples, to specify a range of versions to be scanned.
To revert an image upgrade (due to issues caused by the latest tag) specify exactly which tag should be deployed by editing the deployment file as shown below:
policy:
semver:
range: 1.0.0
or by executing the following command:
flux create image policy podinfo \
--image-ref=podinfo \
--select-semver=1.0.0
Execute the given commands to do the following actions:
- To suspend flux pushing image updates:
flux suspend image update flux-system
- To resume the updates:
flux resume image update flux-system
or specify in ImageUpdateAutomation:
kind: ImageUpdateAutomation
metadata:
name: flux-system
namespace: flux-system
spec:
suspend: true
If you want a push system rather than a pull system from flux so as to immediately deploy the latest tag, refer, Trigger image updates with webhooks.
If you want to push to different branch than the one specified in ImageUpdateAutomation:
spec:
git:
checkout:
ref:
branch: main
push:
branch: flux-image-updates
- To automate PR generations against the main branch refer, GitHub Actions Auto Pull Request.
- To update tags in the manifest files(like HelmRelease) that are different from native kubernetes custom resources, refer, Configure Image Update for Custom Resources,as flux provides different image policy markers.
About OpsMx
OpsMx is a leading innovator and thought leader in the Continuous Delivery space. OpsMx’s Solution for Flux helps DevOps teams manage their Flux deployments at scale.
Talk to OpsMx’s FluxCD experts about any questions that you may have around Flux, GitOps-style deployments, Kubernetes, or DevSecOps. Our services enable the largest and most innovative companies to optimize their (GitOps) delivery pipelines.
0 Comments