Discovering GitOps with FluxCD
In this article, I'll discover the GitOps approach and how to manage environment lifecycles in a Kubernetes context. To help with this, I'll try in the meantime FluxCD, a tool to easily handle "as-code" your environments' topology in a Kubernetes cluster. (It could have been ArgoCD also, but Flux is the tool picked by GitLab by default to manage GitOps from it. I'll write articles on both subjects, Argo & GitLab integration, soon 😉).
A quick definition of GitOps
As this article is not dedicated to GitOps, here is a simple definition of GitOps:
GitOps is an operational framework that takes DevOps best practices used for application development such as version control, collaboration, compliance, and CI/CD, and applies them to infrastructure automation.
The main objective of such an approach is to easily manage your environments with an "as-code" approach. Everything is versioned, reproducible. Git is the source of truth and gives access to a complete changelog of the infrastructure. It's some kind of evolution of Infrastructure-as-Code, aka IaC, where git
becomes the controller of the changes lifecycle.
FluxCD
In the landscape of GitOps tooling, FluxCD is one of the most used ones. It has been picked by GitLab as the default tool for GitOps enablement into his platform.
Installation & Configuration
Let's start by initializing Flux into our cluster, to do so, we need to install the CLI on our laptop, as described here. If you don't want to install some stuff locally, you can also use the docker image available. I'm going to use the CLI in the article.
Flux respects GitOps approach, so to initialize it in a cluster, we need to boostrap it. Here I'll use GitLab to host the sources. To bootstrap flux installation, we need to provide at least the following elements:
owner: either your login or a group (with potential subgroups) path
repository: the repository in which flux will commit information regarding flux installation
branch: default branch to commit to
path: directory path where to commit flux information
Here I specified more option token-auth
to specify an authentication with a personal access token and private
to make the repository public, so that you can have access to the sources of this article (by default, everything is created in private
)
$ flux bootstrap gitlab \
--owner=fun_with/fun-with-k8s \
--repository=fun-with-fluxcd \
--branch=main \
--path=clusters/ovh-fluxcd \
--token-auth \
--private=false
[...]
Please enter your GitLab personal access token (PAT): <GITLAB_PERSONAL_ACCESS_TOKEN>
[...] # If everything goes well, you should see this kind of log
► connecting to https://gitlab.com
► cloning branch "main" from Git repository "https://gitlab.com/fun_with/fun-with-k8s/fun-with-fluxcd.git"
✔ cloned repository
► generating component manifests
✔ generated component manifests
✔ component manifests are up to date
► installing components in "flux-system" namespace
✔ installed components
✔ reconciled components
► determining if source secret "flux-system/flux-system" exists
► generating source secret
► applying source secret "flux-system/flux-system"
✔ reconciled source secret
► generating sync manifests
✔ generated sync manifests
✔ committed sync manifests to "main" ("b34d6c8587efe288f541eb34eb046b9083cd743a")
► pushing sync manifests to "https://gitlab.com/fun_with/fun-with-k8s/fun-with-fluxcd.git"
► applying sync manifests
✔ reconciled sync configuration
◎ waiting for Kustomization "flux-system/flux-system" to be reconciled
✔ Kustomization reconciled successfully
► confirming components are healthy
✔ helm-controller: deployment ready
✔ kustomize-controller: deployment ready
✔ notification-controller: deployment ready
✔ source-controller: deployment ready
✔ all components are healthy # All good !
Now we can see that FluxCD has instantiated some elements in the cluster.
$ kubectl get ns
NAME STATUS AGE
default Active 11m
flux-system Active 2m35s # New namespace created
kube-node-lease Active 11m
kube-public Active 11m
kube-system Active 11m
# Check resources in this namespace
$ kubectl get po -n flux-system
NAME READY STATUS RESTARTS AGE
helm-controller-7f8449fd58-skd26 1/1 Running 0 5m7s
kustomize-controller-6f666f899b-mp6cg 1/1 Running 0 5m7s
notification-controller-55bcdc9fcf-cv9xl 1/1 Running 0 5m7s
source-controller-b5f58d88d-h56wf 1/1 Running 0 5m7s
And also some files in the newly created repository
gotk-components contains all resources for FluxCD to work correctly (namespace, policies, custom resources, ...)
gotk-sync contains information to get Flux deployed resources synchronized with the definitions in the repository (GitOps approach)
kustomization lists the elements to apply
We are now ready to start managing some projects. Let's go!
First deployment based on git
In this first example, I'll configure FluxCD to synchronize a git repository.
Let's create a simple repository containing a single file deployment.yaml
in deployment
directory describing a simple sample app
apiVersion: v1
kind: Namespace
metadata:
labels:
app.kubernetes.io/instance: flux-demo
app.kubernetes.io/name: flux-demo
name: flux-demo
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: flux-demo
namespace: flux-demo
annotations:
kubernetes.io/ingress.class: nginx
cert-manager.io/cluster-issuer: letsencrypt-production
spec:
rules:
- host: flux.ovh.yodamad.fr
http:
paths:
- backend:
service:
name: flux-demo
port:
number: 80
pathType: Prefix
path: /
tls:
- hosts:
- flux.ovh.yodamad.fr
secretName: nginx-demo-tls
---
apiVersion: v1
kind: Service
metadata:
name: flux-demo
namespace: flux-demo
spec:
ports:
- port: 80
targetPort: 80
selector:
app: flux-demo
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: flux-demo
namespace: flux-demo
spec:
replicas: 2
selector:
matchLabels:
app: flux-demo
template:
metadata:
labels:
app: flux-demo
spec:
containers:
- image: nginxdemos/hello
name: flux-demo
ports:
- containerPort: 80
Now I'll configure Flux to monitor this repository and apply it to the cluster. Therefore I need to configure 2 components:
GitRepository which represents the repository to synchronize by defining
the url of the repository
the ref/branch to synchronize with cluster state
the interval to check if some new commits have been made
apiVersion: source.toolkit.fluxcd.io/v1
kind: GitRepository
metadata:
name: flux-simple-app
namespace: flux-system
spec:
interval: 1m0s
ref:
branch: main
url: https://gitlab.com/fun_with/fun-with-k8s/fluxcd-samples/sample-git-repository.git
- Kustomization which specifies in
GitRepository,
the path to synchronize and some options likeprune
. This one specifies to Flux to apply garbage collector on resources, which means that resources that are no longer present in the yaml descriptions files are removed. Theinterval
defined inKustomization,
is the interval to reconcile resources state and resources definition.
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: flux-simple-app
namespace: flux-system
spec:
interval: 1m0s
path: ./deployment
prune: true
sourceRef:
kind: GitRepository
name: flux-simple-app
We can commit these 2 elements in a single file under clusters/ovh-flucd/simple-app
in the repository created from the bootstrap command.
Once committed, Flux will do the job. A few seconds later, I can see a newly created namespace flux-demo
and pods created inside of it
$ kubectl get ns
NAME STATUS AGE
[...]
flux-demo Active 4m38s # My namespace defined in my git repo
flux-system Active 5m14s # FluxCD dedicated namespace
[...]
kube-node-lease Active 22m
kube-public Active 22m
kube-system Active 22m
$ kubectl get po -n flux-demo
NAME READY STATUS RESTARTS AGE
flux-demo-688dbc9f65-kdkhl 1/1 Running 0 5m46s
flux-demo-688dbc9f65-qs7fh 1/1 Running 0 5m46s
We can see in the logs of the source-controller
pod of Flux that the repository has been detected
$ kubectl logs source-controller-b5f58d88d-4hzz7 -n flux-system
[...]
{"level":"info","ts":"2023-08-17T13:16:50.324Z","msg":"stored artifact for commit '🥳 Init deployment'","controller":"gitrepository","controllerGroup":"source.toolkit.fluxcd.io","controllerKind":"GitRepository","GitRepository":{"name":"flux-simple-app","namespace":"flux-system"},"namespace":"flux-system","name":"flux-simple-app","reconcileID":"6dd85fb4-b6d5-43b0-ae9b-1ed67aaf50c4"}
[...]
My repository is now synchronized with Flux, if I make any change in my deployment configuration, it will be automatically applied. Let's say I want to increase the number of nginx replicas to 3. I commit in the sample-git-repository
: replicas: 3
, and a few seconds after, I can see that it has been applied to the cluster
$ kubectl get po -n flux-demo
NAME READY STATUS RESTARTS AGE
flux-demo-688dbc9f65-kdkhl 1/1 Running 0 13m
flux-demo-688dbc9f65-kpskm 1/1 Running 0 78s
flux-demo-688dbc9f65-qs7fh 1/1 Running 0 13m
Again, in source-controller
pod, I can see that the changes had been detected & applied
$ kubectl logs source-controller-b5f58d88d-4hzz7 -n flux-system
[...]
{"level":"info","ts":"2023-08-17T13:28:53.889Z","msg":"stored artifact for commit '💪 Increase replicas'","controller":"gitrepository","controllerGroup":"source.toolkit.fluxcd.io","controllerKind":"GitRepository","GitRepository":{"name":"flux-simple-app","namespace":"flux-system"},"namespace":"flux-system","name":"flux-simple-app","reconcileID":"e54ef49e-30d8-4302-9d37-a8ff53cfd4b7"}
Other possible inputs
As it would be too long in this article to cover them all, FluxCD does support another kind of sources:
Helm repository
Kustomization repository
Cloud providers vendor locking ones
For the 2 first ones, I'd probably write some dedicated articles on them to introduce Helm
and Kustomize
in the meantime.
Conclusion
In this article, I introduce GitOps approach based on a git repository and managed with FluxCD. At the end of your reading, you should be able to set it up and start your journey to GitOps. This is the first basic approach and I will complete this with further articles to bring more real-life use cases and integration with a classic DevOps platform such as #gitlab
At the time of this article, flux was in version 2.0.1. Sources are available in my GitLab space :
fluxcd samples : https://gitlab.com/fun_with/fun-with-k8s/fun-with-fluxcd
demo app repository : https://gitlab.com/fun_with/fun-with-k8s/fluxcd-samples/sample-git-repository
Thanks again to OVHcloud for their support in providing me with resources to try all these nice tools
Subscribe to my newsletter
Read articles from Matthieu Vincent directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Matthieu Vincent
Matthieu Vincent
TechAdvocate DevSecOps / Cloud platform Lead Architect @ Sopra Steria Speaker @ Devoxx, Snowcamp, Breizhcamp, GitLab Connect and internally Co-Founder of Volcamp IT Conference @ Clermont-Fd (https://volcamp.io) GitLab Hero