GitOps is less about declarative configuration and more about embracing the operational overhead of managing infrastructure as code.
Let’s get Flux v2 running on a Kubernetes cluster, pulling its configuration from a GitLab repository.
First, we need to install Flux. The flux bootstrap command is our entry point. It will install the Flux controllers onto your cluster and configure them to watch a specific Git repository.
flux bootstrap git \
--url=https://gitlab.com/your-username/your-flux-config.git \
--branch=main \
--path=./clusters/my-cluster \
--personal
This command does a few key things:
- Installs Flux Controllers: It deploys the necessary Flux components (Source Controller, Kustomize Controller, Helm Controller, Notification Controller, Image Reflector/Automation Controllers) into the
flux-systemnamespace on your Kubernetes cluster. - Creates a Git Repository: It initializes a new Git repository (or uses an existing one if specified) at the provided
--url. This repository will hold your Kubernetes manifests. - Sets up Authentication: For
--personal, it generates a deploy key (SSH private key) and adds it to your GitLab repository as a deploy key. This allows Flux to securely pull from your repository. If you were using--tokenor--password-stdin, it would use those instead. - Configures the Watch Path: The
--pathargument tells Flux where within the Git repository to look for Kubernetes manifests. In this case, it’s./clusters/my-cluster. - Sets the Default Branch:
--branch=mainspecifies which branch Flux should track for changes.
After running the bootstrap command, you’ll see output indicating that Flux has been installed and is now watching your specified Git repository. You can verify the installation with:
kubectl get pods -n flux-system
You should see pods for source-controller, kustomize-controller, etc., all running.
Now, let’s populate that Git repository. Create a directory structure within your GitLab repository matching the --path you provided during bootstrap. For example, if you used --path=./clusters/my-cluster, you’d create clusters/my-cluster in your GitLab repo.
Inside clusters/my-cluster, you’ll place your Kubernetes manifests. Flux supports Kustomize and Helm charts out-of-the-box. A simple Kustomize example:
Create a file named kustomization.yaml in clusters/my-cluster:
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml
- service.yaml
Then, create deployment.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.21.6
ports:
- containerPort: 80
And service.yaml:
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
type: ClusterIP
Commit these files to your GitLab repository and push them. Flux’s Source Controller will detect the changes in the Git repository. The Kustomize Controller will then apply these manifests to your Kubernetes cluster.
You can check the status of Flux’s reconciliation:
flux get kustomizations --namespace flux-system
flux get sources gitrepositories --namespace flux-system
The kustomizations command will show you the status of applying your manifests. sources shows if Flux is successfully pulling from your Git repo.
If everything is configured correctly, you should see your nginx-deployment and nginx-service created in your cluster:
kubectl get deployments,services
The core mechanism here is the Source Controller. It continuously polls the Git repository for new commits. When a new commit is detected on the tracked branch, it downloads the repository’s content. This content is then made available to other controllers. The Kustomize Controller (or Helm Controller) consumes this source, applies any transformations (like Kustomization overlays or Helm value overrides), and then applies the resulting manifests to the cluster. The entire process is idempotent; Flux ensures the cluster’s state matches the declared state in Git.
The magic of Flux is that it’s not just about applying manifests. The flux create kustomization command (and its Helm equivalent) allows you to define how Flux should manage a set of manifests from a specific Git source.
flux create kustomization nginx-app \
--source=flux-system \
--path="./clusters/my-cluster" \
--prune=true \
--interval=5m \
--namespace=default
This command tells Flux to periodically (every 5 minutes, --interval=5m) reconcile the manifests found at the specified path (--path="./clusters/my-cluster") from the Git repository that was already configured during bootstrap (implicitly flux-system in this case, as it’s the default source controller namespace). The --prune=true is crucial: it means Flux will garbage-collect any resources that are no longer defined in your Git repository. The --namespace=default targets the Kubernetes namespace where these resources should be applied.
The next thing you’ll likely encounter is how to manage multiple clusters or environments from a single GitLab repository, often using Kustomize’s directory structure or Helm’s multi-tenancy features.