Kubernetes Without Headaches: Our ArgoCD Setup

Kubernetes Without Headaches: Our ArgoCD Setup

Two years of ArgoCD in production: what's left of it once the hype dies down.

In 2026, GitOps no longer sounds revolutionary. Yet many teams still struggle with the transition — not because the concept is hard, but because the entry barrier is built from old habits. kubectl apply is fast. A pull request against a GitOps repo is slower. It takes a few weeks before the investment pays off.

The App-of-Apps pattern

The most elegant way to structure ArgoCD is the App-of-Apps pattern: a "root application" points to further ArgoCD applications that in turn deploy the actual Helm charts. This enables hierarchical organization — platform services, tenant apps, brand-specific overlays — without having to maintain a single configuration monster.

For us it looks like this: platform-app-of-apps contains all infrastructure services (cert-manager, ingress-nginx, postgresql, keycloak). sovaia-app-of-apps contains all tenant-specific services. Each tenant team works in its own directory and only sees its own scope.

Sync waves as a lifesaver

A common frustration: a service starts before its dependencies are ready. Ingress-nginx rolls out before cert-manager is up → TLS fails. The fix is the argocd.argoproj.io/sync-wave annotation: lower waves sync first.

We agreed on the following convention:

  • Wave 0: cert-manager
  • Wave 1: coredns, external-secrets, ingress-nginx, cloudflared
  • Wave 2: postgresql, redis, tenant apps
  • Wave 3: minio, monitoring, loki
  • Wave 4: pgadmin, keycloak, velero

Newcomers look at this table and know within thirty seconds where a new service belongs.

Image updates via SHA tags

A decision point is the image-tag strategy. We use sha-<short> tags. A commit in a service repo triggers a CI build that tags the image with the commit SHA. Afterwards we update the values.yaml in the GitOps repo with the new tag — that's the actual deploy.

Why not latest? Because latest offers no reproducibility. What runs as latest today was a different build a week ago. Rollbacks become a guessing game.

Why not semver? Because at 20 services it's too much overhead. SHA tags are right by construction — every commit is a unique identifier, no opinion forming required.

Observability: what we really need

ArgoCD has its own UI that shows sync status and drift nicely. In practice that is enough for daily work. When something goes wrong on a bigger scale we go to Grafana — but that is needed less often than you'd think.

What we built: a Slack channel that posts every successful sync and every error. It does not replace a real monitoring solution but gives all team members an asynchronous overview without having to open ArgoCD.

What we'd do differently today

We invested too much time at the start parameterizing everything. Three brands, four environments, two regions — every axis as a Helm-values overlay. That did not pay off. Two years later, many parameters are hard-coded again because we never actually varied them.

Recommendation: parameterize only when the second or third case appears. Not on suspicion.

SOVAIA (Ein Produkt der KIINNO AG)

Baarerstrasse 52
6300 Zug
Schweiz


plus 4 1 4 1 5 1 0 0 6 7 5