Jenkins CI- Flux CD demo with Kind K8s cluster locally: Part 2

Mohitverma
7 min readAug 15, 2024

--

This is second part of the two parts series.

Part 1: Bootstrap the infrastructure with Ansible playbook and Flux CD.

Part 2: Deploying the application with flux CD and demonstrating complete CI-CD flow using Flux image-automation-controller.

CI-CD flow demo

Next step is to configure Jenkins CI pipeline. Login to the Jenkins UI and use blue ocean plugin to configure the pipeline.

All code used in this demo is uploaded on my github repository, please feel free to check.

https://github.com/mvtech88/fluxcd-demo

Jenkisfile is in the parent root directory of the git repository and it is configured to build a docker image for the php application and push it to docker registry.

➜  fluxcd-demo git:(main) tree CI
CI
├── Dockerfile
├── create.php
├── db.php
├── delete.php
├── index.html
├── index.php
├── read.php
└── update.php

# Jenkins secret

➜ Documents kubectl get secret jenkins -n jenkins -o go-template='{{range $k,$v := .data}}{{"### "}}{{$k}}{{"\n"}}{{$v|base64decode}}{{"\n\n"}}{{end}}'
### jenkins-admin-password
tJOC6LLXLygQv6iu4driLS

### jenkins-admin-user
admin

➜ Documents kubectl port-forward svc/jenkins -n jenkins 8081:8080
Forwarding from 127.0.0.1:8081 -> 8080
Forwarding from [::1]:8081 -> 8080
  • create the github token secret for pipeline to access the github repo where Docker build code is present.
global secret created for Jenkins pipeline
  • Now use the open blue ocean plugin to create the pipeline.
Jenkins pipeline configuration using blue ocean plugin

Pipeline is configured to build image with kaniko, only when the changes are made in the CI folder. Otherwise the pipeline will skip the build step.

Jenkins build pipeline

Jenkins is now configured, and we will deploy the application and set up the required actions to use the image-automation-controller to check the docker repository for updated tags and launch the application each time an image tag is updated.

Commit the app-components folder at path fluxcd demo/clusters/fluxbootstrap/.

➜  gitops tree app-components
app-components
├── helm_repo_private.yaml
├── imagepolicy.yaml
├── imagerepository.yaml
├── imageupdateautomation.yaml
├── kustomization_mysql.yaml
└── kustomization_php.yam
➜  fluxcd-demo git:(main) ✗ git commit -m "adding application folder to the git repository"
[main 775a42f] adding application folder to the git repository
6 files changed, 86 insertions(+)
create mode 100755 clusters/fluxbootstrap/app-components/helm_repo_private.yaml
create mode 100755 clusters/fluxbootstrap/app-components/imagepolicy.yaml
create mode 100755 clusters/fluxbootstrap/app-components/imagerepository.yaml
create mode 100755 clusters/fluxbootstrap/app-components/imageupdateautomation.yaml
create mode 100755 clusters/fluxbootstrap/app-components/kustomization_mysql.yaml
create mode 100755 clusters/fluxbootstrap/app-components/kustomization_php.yaml

➜ fluxcd-demo git:(main) git push origin main
Enumerating objects: 14, done.
Counting objects: 100% (14/14), done.
Delta compression using up to 8 threads
Compressing objects: 100% (10/10), done.
Writing objects: 100% (11/11), 1.85 KiB | 1.85 MiB/s, done.
Total 11 (delta 2), reused 0 (delta 0), pack-reused 0 (from 0)
remote: Resolving deltas: 100% (2/2), completed with 1 local object.
To https://github.com/mvtech88/fluxcd-demo.git
c318ecc..775a42f main -> main

Flux reconciles the git repository and deploy the application as we intend to deploy on the cluster.

vmadmin@ubuntu:~$ kubectl get pods -n demo-webapp
NAME READY STATUS RESTARTS AGE
demo-mysqldb-6b478445ff-j8bdn 1/1 Running 0 2m13s
web-5c8df5bbcd-bgfxq 2/2 Running 0 105s

vmadmin@ubuntu:~$ flux get kustomization php-frontend
NAME REVISION SUSPENDED READY MESSAGE
php-frontend main@sha1:775a42fc False True Applied revision: main@sha1:775a42fc
vmadmin@ubuntu:~$
vmadmin@ubuntu:~$ flux get kustomization mysql-backend
NAME REVISION SUSPENDED READY MESSAGE
mysql-backend main@sha1:775a42fc False True Applied revision: main@sha1:775a42fc

We have also defined ImageRepository, ImagePolicy and ImageUpdateAutomation custom resource to monitor the docker repository and check for the changes in the image tag.

➜  app-components git:(main) cat imagepolicy.yaml
apiVersion: image.toolkit.fluxcd.io/v1beta1
kind: ImagePolicy
metadata:
name: demowebapp
namespace: flux-system
spec:
imageRepositoryRef:
name: demowebapp
filterTags:
pattern: '^main-[a-f0-9]+-(?P<ts>[0-9]+)'
extract: '$ts'
policy:
numerical:
order: asc

➜ app-components git:(main) cat imageupdateautomation.yaml
apiVersion: image.toolkit.fluxcd.io/v1beta1
kind: ImageUpdateAutomation
metadata:
name: demowebapp
namespace: flux-system
spec:
interval: 1m0s
sourceRef:
kind: GitRepository
name: flux-system
git:
checkout:
ref:
branch: main
commit:
author:
email: mohit_verma1688@icloud.com
name: mvtech88
messageTemplate: '{{range .Updated.Images}}{{println .}}{{end}}'
push:
branch: main
update:
path: ./application/php-frontend
strategy: Setters

➜ app-components git:(main) cat imagerepository.yaml
apiVersion: image.toolkit.fluxcd.io/v1beta1
kind: ImageRepository
metadata:
name: demowebapp
namespace: flux-system
spec:
secretRef:
name: docker-credentials
image: docker.io/mohitverma1688/php-app
interval: 1m0s

Lets check with the flux cli inside the VM. Flux image controller has scanned 7 image tags in the docker repository for the php-app frontend.

vmadmin@ubuntu:~$ flux get images all
NAME LAST SCAN SUSPENDED READY MESSAGE
imagerepository/demowebapp 2024-08-15T18:35:38+05:30 False True successful scan: found 7 tags

NAME LATEST IMAGE READY MESSAGE
imagepolicy/demowebapp docker.io/mohitverma1688/php-app:main-3255af70-1723132302 True Latest image tag for 'docker.io/mohitverma1688/php-app' resolved to main-3255af70-1723132302

NAME LAST RUN SUSPENDED READY MESSAGE
imageupdateautomation/demowebapp 2024-08-15T18:35:24+05:30 False True repository up-to-date

Due to the extremely ancient mysql database version I’m using, there is a solution to configure the mysqldb with the bash script . Now application is ready to be tested.

➜  fluxcd-demo git:(main) ✗ ./configuredb.sh
Defaulted container "demo-mysqldb" out of: demo-mysqldb, remove-lost-found (init)
mysql: [Warning] Using a password on the command line interface can be insecure.
Defaulted container "demo-mysqldb" out of: demo-mysqldb, remove-lost-found (init)
mysql: [Warning] Using a password on the command line interface can be insecure.

Check for the ingress load balancer IP provided by the metallb after ingress creation. We need to add the FQDN in /etc/hosts file to access the application.

vmadmin@ubuntu:~$ kubectl get ingress -n demo-webapp
NAME CLASS HOSTS ADDRESS PORTS AGE
nginx-web <none> myapp.loc 172.18.255.200 80, 443 29m

vmadmin@ubuntu:~$ cat /etc/hosts | grep myapp.loc
172.18.255.200 myapp.loc

I have not configured the access to the docker VM running on Macbook to access the application from my macbook browser. I will use a utility “w3m” to access the application using terminal cli. This utility allows to access the application homepage on the linux systems without GUI interface/Web Browsers.

vmadmin@ubuntu:~$ w3m https://myapp.loc

This terminal will ask to accept the ingress insecure certificate, press ‘y’ to land on the homepage.

The simple application is a CRUD application with PHP front end which uses a mysql db as backend.

php application web frontend with terminal

The Final CI-CD show.

Finally, we can test the settings now. After I update the application from version 3 to version 4, we will test the flux CD auto update feature. The application will be automatically deployed by Flux CD after it has scanned the new image tag that was pushed to the Docker registry by the Jenkins CI build pipeline.

The deployment yaml is controlled by the flux using the config {“$imagepolicy”: “flux-system:demowebapp”} as shown below.

➜  fluxcd-demo git:(main) ✗ cat application/php-frontend/deployment.yaml

.
.
spec:
containers:
- name: php-fpm
image: docker.io/mohitverma1688/php-app:main-3255af70-1723132302 # {"$imagepolicy": "flux-system:demowebapp"}
ports:
- containerPort: 9000
name: http
protocol: TCP
.
.
➜  fluxcd-demo git:(main) ✗ git add .
➜ fluxcd-demo git:(main) ✗ git commit -m "Changing the application version from 3 to version 4"
[main e9c3cd6] Changing the application version from 3 to version 4
2 files changed, 1 insertion(+), 1 deletion(-)
mode change 100644 => 100755 configuredb.sh
➜ fluxcd-demo git:(main)
➜ fluxcd-demo git:(main) git push origin main
Enumerating objects: 7, done.
Counting objects: 100% (7/7), done.
Delta compression using up to 8 threads
Compressing objects: 100% (4/4), done.
Writing objects: 100% (4/4), 391 bytes | 391.00 KiB/s, done.
Total 4 (delta 3), reused 0 (delta 0), pack-reused 0 (from 0)
remote: Resolving deltas: 100% (3/3), completed with 3 local objects.
To https://github.com/mvtech88/fluxcd-demo.git
775a42f..e9c3cd6 main -> main

When checked the Jenkins UI, we can see that that CI build step is completed successfully.

Jenkins CI build image step.

From docker registry, the new image can be seen pushed with the commit tag.

Jenkins CI build step pushed the image with git commit tag

The new image tag can also be cross validated on the deployment.yaml file. The pod age confirmed that the pod has been recreated with the new image tag.


vmadmin@ubuntu:~$ kubectl get pods -n demo-webapp
NAME READY STATUS RESTARTS AGE
demo-mysqldb-6b478445ff-j8bdn 1/1 Running 0 83m
web-55b7cdc4fc-mhws8 2/2 Running 0 12m

vmadmin@ubuntu:~$ kubectl get deployment web -n demo-webapp -o yaml | grep -i Image -A3 -B3
version: v1
spec:
containers:
- image: docker.io/mohitverma1688/php-app:main-e9c3cd68-1723729530
imagePullPolicy: IfNotPresent
name: php-fpm
ports:
- containerPort: 9000
--
- mountPath: /etc/nginx/conf.d/default.conf
name: nginx-config-volume
subPath: default.conf

vmadmin@ubuntu:~$ flux get images all
NAME LAST SCAN SUSPENDED READY MESSAGE
imagerepository/demowebapp 2024-08-15T19:32:24+05:30 False True successful scan: found 8 tags

NAME LATEST IMAGE READY MESSAGE
imagepolicy/demowebapp docker.io/mohitverma1688/php-app:main-e9c3cd68-1723729530 True Latest image tag for 'docker.io/mohitverma1688/php-app' updated from main-3255af70-1723132302 to main-e9c3cd68-1723729530

NAME LAST RUN SUSPENDED READY MESSAGE
imageupdateautomation/demowebapp 2024-08-15T19:32:46+05:30 False True repository up-to-date

Now, lets check if the application is showing that changes we made or not.

vmadmin@ubuntu:~$ w3m https://myapp.loc

We can see that the version is now changed from version 3 -> version 4 in the application UI.

Application has been auto deployed with Version 4.

Flux CD has also committed to the git repository with the new commit with latest image tag.

Now we have a successfully tested CI-CD flow running locally on the kubernetes cluster.

Happy Learning!!.

--

--