Kubernetes GitOps with FluxCD - Part 1 - Initial Setup
GitOps practice enables us to define our infrastructure as code in a declarative manner. It serves as an audited single source of truth for our cloud/cluster state, providing benefits like: Version control and audit trails for infrastructure changes Automated reconciliation between desired and actual states Improved security through encrypted credentials and access control Simplified rollback capabilities Enhanced collaboration through Git workflows FluxCD is a CNCF graduated project that enables GitOps practices in the Kubernetes ecosystem. It automates the deployment, monitoring, and reconciliation of cluster resources based on Git repositories. This post covers the initial setup and core functionality of FluxCD in a Kubernetes cluster. 1. Setup Git dependencies Lets start by creating git repository in Github. Next, we need to generate a fine-grained access token that FluxCD will use to interact with our repository. These tokens provide more granular control over repository permissions compared to classic personal access tokens. We'll keep Read and write permission for Administration, Contents access and Read-only for Metadata access limited to repository we created above and permissions as recommeded by official FluxCD documentation for this initial setup. 2. Setup Flux CLI Lets start by installing FluxCD cli sudo zypper in flux2-cli Next step is to export github token and user details variables. export GITHUB_TOKEN=****** export GITHUB_USER=***** For this post we are using locally VM hosted k3s cluster, lets check if we have access to same with kubectl. # 1. Point to specific cluster we are setting up export KUBECONFIG=~/.kube/local.config # 2. Check for access and version kubectl version Let's check same with Flux cli if it has access as well. flux check --pre 3. Bootstrap FluxCD We are going to install all components including extra for image automation. flux bootstrap github \ --owner=$GITHUB_USER \ --repository=k8s-gitops \ --branch=main \ --path=./cluster/default \ --read-write-key \ --components source-controller,kustomize-controller,helm-controller,notification-controller \ --components-extra image-reflector-controller,image-automation-controller \ --personal Lets verify Flux setup step by step. Bootstrap has created one deployment key in Github repository and stored as flux-system/flux-secret Let's verify deployment key in Github Let's verify secret with kubectl -n flux-system get secrets Flux has initialized the repository with initial commit having definition of components at cluster/default as specified bootstrap command. FluxCD reconclided with Git repository and installed the components in flux-system namespace, lets verify same with kubectl 4. Verify installation Lets verify our installation by creating a sample deployment. apps/nginx/deployment.yaml apiVersion: apps/v1 metadata: name: nginx-deployment namespace: default kind: Deployment spec: replicas: 1 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:latest ports: - containerPort: 80 resources: requests: memory: "64Mi" cpu: "50m" limits: memory: "64Mi" cpu: "50m" apps/nginx/kustomization.yaml apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: - deployment.yaml cluster/default/nginx.yaml apiVersion: kustomize.toolkit.fluxcd.io/v1 kind: Kustomization metadata: name: nginx namespace: flux-system spec: interval: 5m path: ./apps/nginx prune: true retryInterval: 2m sourceRef: kind: GitRepository name: flux-system targetNamespace: default timeout: 3m wait: true The Kustomization resource has several important fields: interval: How often Flux should reconcile this resource (5m = 5 minutes) path: Directory containing the Kubernetes manifests prune: Whether Flux should delete resources that are no longer defined in Git retryInterval: How long to wait between retries if reconciliation fails wait: Whether Flux should wait for resources to be ready before completing reconciliation timeout: Maximum time to wait for reconciliation Lets push these changes and wait for reconciliation to finish. Lets verify if nginx is deployed 5. What if One of the core goals of GitOps is ensuring that our cluster's state always matches the resources defined in our git repository. This continuous reconciliation process is what makes GitOps powerful for maintaining system consistency. To demonstrate this functionality, we'll delete our nginx deployment using kubectl and observe how Flux's reconciliation process automatically restores it to the desired state defined in Git. This showc

GitOps practice enables us to define our infrastructure as code in a declarative manner. It serves as an audited single source of truth for our cloud/cluster state, providing benefits like:
- Version control and audit trails for infrastructure changes
- Automated reconciliation between desired and actual states
- Improved security through encrypted credentials and access control
- Simplified rollback capabilities
- Enhanced collaboration through Git workflows
FluxCD is a CNCF graduated project that enables GitOps practices in the Kubernetes ecosystem. It automates the deployment, monitoring, and reconciliation of cluster resources based on Git repositories.
This post covers the initial setup and core functionality of FluxCD in a Kubernetes cluster.
1. Setup Git dependencies
Lets start by creating git repository in Github.
Next, we need to generate a fine-grained access token that FluxCD will use to interact with our repository. These tokens provide more granular control over repository permissions compared to classic personal access tokens.
We'll keep Read and write
permission for Administration
, Contents
access and Read-only
for Metadata
access limited to repository we created above and permissions as recommeded by official FluxCD documentation for this initial setup.
2. Setup Flux CLI
Lets start by installing FluxCD cli
sudo zypper in flux2-cli
Next step is to export github token and user details variables.
export GITHUB_TOKEN=******
export GITHUB_USER=*****
For this post we are using locally VM hosted k3s cluster, lets check if we have access to same with kubectl
.
# 1. Point to specific cluster we are setting up
export KUBECONFIG=~/.kube/local.config
# 2. Check for access and version
kubectl version
Let's check same with Flux cli if it has access as well.
flux check --pre
3. Bootstrap FluxCD
We are going to install all components including extra for image automation.
flux bootstrap github \
--owner=$GITHUB_USER \
--repository=k8s-gitops \
--branch=main \
--path=./cluster/default \
--read-write-key \
--components source-controller,kustomize-controller,helm-controller,notification-controller \
--components-extra image-reflector-controller,image-automation-controller \
--personal
Lets verify Flux setup step by step.
- Bootstrap has created one deployment key in Github repository and stored as flux-system/flux-secret
Let's verify deployment key in Github
Let's verify secret with kubectl -n flux-system get secrets
- Flux has initialized the repository with initial commit having definition of components at
cluster/default
as specified bootstrap command.
- FluxCD reconclided with Git repository and installed the components in
flux-system
namespace, lets verify same withkubectl
4. Verify installation
Lets verify our installation by creating a sample deployment.
apps/nginx/deployment.yaml
apiVersion: apps/v1
metadata:
name: nginx-deployment
namespace: default
kind: Deployment
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
resources:
requests:
memory: "64Mi"
cpu: "50m"
limits:
memory: "64Mi"
cpu: "50m"
apps/nginx/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml
cluster/default/nginx.yaml
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: nginx
namespace: flux-system
spec:
interval: 5m
path: ./apps/nginx
prune: true
retryInterval: 2m
sourceRef:
kind: GitRepository
name: flux-system
targetNamespace: default
timeout: 3m
wait: true
The Kustomization resource has several important fields:
-
interval
: How often Flux should reconcile this resource (5m = 5 minutes) -
path
: Directory containing the Kubernetes manifests -
prune
: Whether Flux should delete resources that are no longer defined in Git -
retryInterval
: How long to wait between retries if reconciliation fails -
wait
: Whether Flux should wait for resources to be ready before completing reconciliation -
timeout
: Maximum time to wait for reconciliation
Lets push these changes and wait for reconciliation to finish.
Lets verify if nginx is deployed
5. What if
One of the core goals of GitOps is ensuring that our cluster's state always matches the resources defined in our git repository. This continuous reconciliation process is what makes GitOps powerful for maintaining system consistency.
To demonstrate this functionality, we'll delete our nginx deployment using kubectl and observe how Flux's reconciliation process automatically restores it to the desired state defined in Git. This showcases the "self-healing" capability of the GitOps approach.
In screen above:
- First step is to verify the deployment with
kubectl get deployments
to check if nginx is up and running - Second step is to delete deployment with
kubectl delete deployment/nginx-deployment
- 3rd step to confirm nginx deployment is deleted with
kubectl get deployment
- 4th step is to watch over FluxCD reconciliation to kick in
- 5th step to verify that nginx is re-deployed post Flux's reconciliation
What next ?
Future posts will explore advanced GitOps patterns with FluxCD, including:
- Helm chart automation
- Image update automation
- Notification and alerting configuration
- Secrets management with SOPS
Stay tuned for each of these topics.
References
- Official FluxCD Documentation - https://fluxcd.io/flux/
- GitOps Working Group - https://opengitops.dev
- Kubernetes Documentation - https://kubernetes.io/docs/