Repo Structure and Naming Conventions#
What This Covers#
Why the repo uses infra/ and apps/ as separate layers, what each folder contains, how
ArgoCD connects them, and the real-world naming rationale behind these conventions.
The Two-Layer Problem#
After adding cert-manager and Gateway API, the repo had two folders both called platform/:
| Path | What it actually contained |
|---|---|
platform/ (root) | Kubernetes manifests - ClusterIssuer, Certificate, GatewayClass |
environments/<cluster>/platform/ | ArgoCD Application CRDs - pointers to go deploy things |
Same name, completely different purpose. The rename fixes this.
The Renamed Structure#
| |
What Each Layer Does#
infra/ - the “what to deploy”#
Raw Kubernetes manifests for shared infrastructure. These are cluster-agnostic - the same
issuer definitions, the same GatewayClass, work on every cluster. Nothing in infra/ knows
about ArgoCD; it’s plain YAML that kubectl apply could also handle.
environments/<cluster>/apps/ - the “how ArgoCD deploys it”#
Every file here is a kind: Application or kind: ApplicationSet. These are instructions
to ArgoCD, not Kubernetes resources. They say: “go to this repo path, apply it to this
cluster, in this namespace, with these sync settings.”
The root bootstrap.yaml points ArgoCD at this folder. ArgoCD reads all the Application
objects inside it and starts managing them - this is the App-of-Apps pattern.
environments/<cluster>/gateway-api/, argocd/, services/#
Cluster-specific state: values, secrets, and resources that differ per cluster. Referenced
by Applications in apps/, not applied directly.
The Cert-Manager Flow (with sync waves)#
| |
Wave 0 must complete before wave 1 because cert-manager’s CRDs (ClusterIssuer, Certificate)
don’t exist until the Helm chart installs them. Applying the issuers before the controller is
ready causes ArgoCD to fail with “no matches for kind ClusterIssuer”.
The Gateway API Flow (with sync waves)#
| |
gateway-api-config.yaml uses ArgoCD’s multi-source feature. The GatewayClass lives in
infra/ because it is cluster-scoped and shared. The Gateway resource lives in
environments/<cluster>/gateway-api/ because it has cluster-specific settings (listeners,
TLS config, hostnames).
Why infra/ and Not platform/#
platform/ is overloaded. In this repo it was already used for two different things. In
wider industry usage it also means the team/layer responsible for developer tooling, not a
folder of raw manifests.
infra/ is unambiguous: it means “infrastructure manifests”. No one reads infra/cert-manager/
and thinks it contains ArgoCD Application objects.
Real-world repos that use this convention: Weaveworks Flux reference architecture, Argo CD reference app (GitHub), most multi-cluster GitOps templates from Codefresh and Grafana.
Why apps/ and Not platform/#
Every file inside environments/<cluster>/apps/ is kind: Application or
kind: ApplicationSet. Calling the folder apps/ makes this immediately obvious. It is the
standard name in the Argo CD community for “the folder that holds Application manifests that
ArgoCD manages”.
The previous name platform/ implied the folder contained platform infrastructure, which is
the opposite of what it does - it contains the instructions to go get and deploy the
platform infrastructure.
Rule of Thumb#
If you’re writing a
kind: Applicationorkind: ApplicationSet- it goes inenvironments/<cluster>/apps/. If you’re writing any other Kubernetes resource that is shared across clusters - it goes ininfra/. If you’re writing a resource that is specific to one cluster - it goes inenvironments/<cluster>/<component>/.