GitOps Principles & Practice›02 · Repository design

Lesson 02 of 7 · Level 1 — The model

Repository design

Design the Git repositories GitOps reads from: why application source and deployment configuration usually live apart, directory layouts per environment and cluster, Kustomize overlays versus Helm values, the rendered-manifests pattern, and how the structure grows from one team to many.

Practitioner → Advanced
Key wordsGitOps repositoryapp repoconfig repoenvironment directoriesKustomizebase and overlaysHelm valuesrendered manifestsmonorepoper-team reposcluster bootstrap

Two kinds of repository

Repository Contains Changed by
Application repo Source code, Dockerfile, tests, often the Helm chart Developers, through PRs; CI builds images
Config (environment) repo What runs where: versions, values, overlays per environment and cluster Promotion PRs (automated or human), platform changes

Keeping them apart means a replica change doesn't trigger app builds, production config can have stricter reviewers (CODEOWNERS), and the config repo's history is a clean deployment log. Small teams can start with a deploy/ folder in the app repo and split later.

The recipe book (app repo) says how to cook the dish. The restaurant's daily menu board (config repo) says which dishes are served today, in which branch, in what portion size. Chefs change recipes; managers change the menu board.

A layout that grows well

gitops-config/
├── clusters/                     # what each cluster runs (entry points for the agent)
│   ├── dev-eu-1/
│   │   ├── platform.yaml         # points at platform/ with dev settings
│   │   └── apps.yaml             # points at apps/*/envs/dev
│   └── prod-eu-1/
├── platform/                     # cluster add-ons: ingress, cert-manager, monitoring...
│   ├── base/
│   └── overlays/{dev,prod}/
└── apps/
    ├── orders-api/
    │   ├── base/                 # Deployment, Service, HPA, PDB
    │   └── envs/
    │       ├── dev/   kustomization.yaml  (image tag, 1 replica)
    │       ├── staging/
    │       └── prod/  kustomization.yaml  (image digest, 6 replicas, bigger requests)
    └── payments/

Principles: one entry point per cluster, platform separate from apps, environment differences in small overlays, and nothing duplicated that could drift.

Kustomize overlays or Helm values?

# apps/orders-api/envs/prod/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - ../../base
images:
  - name: ghcr.io/acme/orders-api
    digest: sha256:3f1c9a0b7e2d4c5a8b9e1f2d3c4b5a6978e1d2c3b4a5968778695a4b3c2d1e0f
replicas:
  - name: orders-api
    count: 6
patches:
  - path: resources-prod.yaml
Kustomize Helm
Model Plain YAML base + patches per environment Templates + values per environment
Strength No templating language; diffs are obvious Packaging, parameters, huge ecosystem of charts
Common use Your own apps and overlays Third-party software; your apps if you publish charts

Mixing is normal: Helm charts for third-party add-ons (with a values file per environment), Kustomize for your own services, or Kustomize wrapping a Helm chart. Both Argo CD and Flux render either natively.

The rendered-manifests pattern

Instead of letting the agent render templates, CI renders them and commits the plain YAML to an environment branch or folder. Reviewers then see the exact Kubernetes objects that will change, not just "values.yaml changed". The cost is an extra pipeline and larger diffs; it's most valuable for production and for charts with complex templates.

As the organisation grows

Size Structure
One team One config repo (or a folder in the app repo)
Several teams One config repo with a folder per team, CODEOWNERS per folder
Many teams / strict isolation A config repo per team plus a platform repo; the platform repo registers the teams' repos (App-of-Apps / ApplicationSets or Flux tenants)

Try it: build the layout

  1. Create the gitops-config layout above for one app with base and dev/prod overlays.
  2. Run kustomize build for both and diff them: only intended differences should appear.
  3. Validate the output with kubeconform.
  4. Point Argo CD or Flux at apps/orders-api/envs/dev on a kind cluster.

Recap

  • Separate app repos (code, CI) from the config repo (what runs where) once more than one team is involved.
  • One entry point per cluster; platform separate from apps; small overlays per environment.
  • Kustomize for your own YAML, Helm for packaged software; both work with GitOps agents.
  • Rendered manifests make production reviews exact; structure grows from folders to per-team repos.

This site is a public version of my personal engineering knowledge hub. It intentionally excludes confidential company information and internal operational details.