GitOps is mode of operation where you keep Kubernetes manifests in a repo as source of truth and you use some way to sync that to your cluster. There are several ways and tools you can use, ie. ArgoCD or Flux.

Gitlab is using Flux by default. I believe it is more lightweight than ArgoCD and requires les resources in your cluster. This is why it is more suitable for small clusters like k3s or microk8s. You may want to use it if you do not need fancy UI. If you have big team of developers and they do not want to invest any effort to understand k8s logic, use ArgoCD.

Flux will install a few small PODs into your cluster (flux-system namespace). These POds will connect to your Gitlab repo, check for changes, apply kustomizatins or update Helm charts. You can run only PODs you need. Minimal setup will use just 2 PODs: source-controller and kustomization-controller.

Install and Bootstrap

You need to allow Flux to access your Gitlab repo, so you should create and save PAT. Clone your repo and run the following commands from it because Flux will create and commit some files, ie: clusters//flux-system.

export GITLAB_TOKEN=<your-token>
flux bootstrap gitlab --deploy-token-auth --owner=<Gitlab Repo Owner> --repository=<Repo Name>  --branch=main --path=clusters/<name>

This will run the PODs in your cluster, connect them to your Repo and add config files into your repo. These files are used to configure Flux. You can control what components are running by editing clusters//flux-system/gotk-components.yaml. For example, you can scale to 0 helm-controller.

Repo Organization

You should make some kind of hierarchy in your repo to organize files related to app and separate from flux system. Here sample:

├── clusters // flux-system
│   └── dev
│       ├── flux-system
│       │   ├── gotk-components.yaml
│       │   ├── gotk-sync.yaml
│       │   └── kustomization.yaml
│       ├── notes-front
│           └── kustomization.yaml
│      
└── notes-front // your app
    ├── docker-registry.yaml
    ├── kustomization.yaml
    ├── notes-front-deployment.yaml
    ├── notes-front-ingress.yaml
    ├── notes-front-namespace.yaml
    └── notes-front-service.yaml

Sample App

I have dev and prod Kubernetes clusters in different clouds. Both are using different DNS domains, so my app must use different ENV variables for configuration. I’m using Kustomize to overwrite the Deployments and set correct ENV. App is running as single POD in notes-front namespace. There is service and Ingress used to expose the app on the http://dev-domain or http://prod-domain. In real life, I’m using cert-manager and HTTPs.

Kustomize

clusters/dev/notes-front/kustomization.yaml

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
metadata:
  name: notes-front
resources:
  - ../../../notes-front

patches:
  - target:
      kind: Deployment
      name: notes-front-app
    patch: |-
      - op: add
        path: /spec/template/spec/containers/0/env/-
        value:
          name: ENV
          value: dev
      - op: add
        path: /spec/template/spec/containers/0/env/-
        value:
          name: GITOPS
          value: SOME_VALUE

  # Change Ingress class for K3s
  - target:
      kind: Ingress
      name: notes-front-ingress
    patch: |-
      - op: add
        path: /spec/ingressClassName
        value: traefik

notes-front/kustomization.yaml

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - notes-front-namespace.yaml
  - docker-registry.yaml
  - notes-front-deployment.yaml
  - notes-front-service.yaml
  - notes-front-ingress.yaml

Sync and Troubleshoot

After you commit and push to your repo, Flux will sync after around 1 minute and try to apply your manifests. You can follow up using the commands:


# Check the events
flux logs

# Get info about kustomizations
kubectl get kustomizations -n flux-system

# Reply
NAME          AGE     READY   STATUS
flux-system   3d23h   True    Applied revision: main@sha1:5cf7f78c6f8d5629767566279dc618b86a116ac4