Treat every component as code. Adding, changing, or removing should feel like a small, reviewable PR.
The recipe
- Create
K8s/<stack>/<name>/. - Add
kustomization.yaml(resources orhelmCharts). - Apply canonical labels (
owner,business-unit,environment,app.kubernetes.io/*). - Commit + push.
- The ApplicationSet detects the folder → ArgoCD creates the
Application. - Sync follows waves/policies and converges in the cluster.
:::Tip Expose UI via Gateway with an HTTPRoute if relevant. :::
Governance overlay pattern
Every stack ships with a governance/ folder that is synced ahead of the workloads. It
contains the namespace definition plus the mandatory LimitRange and ResourceQuota
for that stack (argocd.argoproj.io/sync-wave keeps the order deterministic). Copy the
pattern from any existing stack such as K8s/events/governance/* or
K8s/cicd/governance/*:
-
namespace.yaml— canonical labels (app.kubernetes.io/part-of,owner,business-unit,environment) and sync wave annotation:metadata:annotations:argocd.argoproj.io/sync-wave: '-2' # Ensures namespace creation before resources -
limitrange.yaml— guardrails for default requests/limits sized for the stack. -
resourcequota.yaml— hard ceilings to keep noisy neighbors in check.
This overlay is part of the platform contract (“Namespace governance” in Contracts & Guardrails); omitting it will fail reviews and breaks capacity planning.
Complete example: Adding Kubecost
Step-by-step walkthrough for adding Kubecost to the observability stack.
Create folder structure
mkdir -p K8s/observability/kubecostcd K8s/observability/kubecostCreate kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1kind: Kustomization
commonAnnotations: argocd.argoproj.io/sync-wave: '3'
helmCharts: - name: cost-analyzer repo: https://kubecost.github.io/cost-analyzer/ version: 2.4.3 releaseName: kubecost namespace: observability valuesFile: values.yaml includeCRDs: trueCreate values.yaml
# @section -- General# -- Priority class for Kubecost podspriorityClassName: platform-observability
# @section -- Cost AnalyzerkubecostProductConfigs: # -- Cluster name for cost attribution clusterName: idp-demo
# @section -- Resourcesresources: requests: # -- CPU request cpu: 100m # -- Memory request memory: 256Mi limits: # -- CPU limit cpu: 500m # -- Memory limit memory: 1Gi
# @section -- Prometheus Integrationprometheus: # -- Use existing Prometheus instance external: enabled: true url: http://prometheus-kube-prometheus-prometheus.observability.svc:9090
# @section -- ServiceMonitorserviceMonitor: # -- Enable ServiceMonitor for Prometheus Operator enabled: true additionalLabels: # -- Prometheus selector label prometheus: kube-prometheus
# @section -- Ingressingress: # -- Enable ingress for Kubecost UI enabled: false # Note: Use Gateway API HTTPRoute instead (see step 5)Expose via Gateway API (Optional)
Create K8s/observability/kubecost/httproute.yaml:
apiVersion: gateway.networking.k8s.io/v1kind: HTTPRoutemetadata: name: kubecost namespace: observability labels: app.kubernetes.io/name: kubecost app.kubernetes.io/part-of: idpspec: parentRefs: - name: platform-gateway namespace: kube-system hostnames: - 'kubecost.${DNS_SUFFIX}' rules: - matches: - path: type: PathPrefix value: / backendRefs: - name: kubecost-cost-analyzer port: 9090Update kustomization.yaml to include it:
resources: - httproute.yamlCommit and verify
git add K8s/observability/kubecost/git commit -m "feat(observability): add Kubecost for cost attribution"git push
# Verify ApplicationSet detectionkubectl get applications -n argocd | grep kubecost
# Wait for syncargocd app wait observability-kubecost --health
# Check deploymentkubectl get pods -n observability -l app.kubernetes.io/name=kubecost
# Access UI (if HTTPRoute was created)echo "https://kubecost.$(dasel -f config.toml -r toml '.network.lan_ip').nip.io"Result
The observability ApplicationSet automatically detects the new
K8s/observability/kubecost/ folder and creates the observability-kubecost
Application. ArgoCD syncs it according to the sync wave (after core infrastructure but
before SLOs), and the component integrates with the existing Prometheus instance for
cost metrics.
Visual flow
The entire process from Git commit to running workload: