How I Standardised Kubernetes Deployments with ArgoCD¶
Why this exists¶
We had multiple teams shipping to multiple clusters, and every team invented their own deployment pattern. It worked—until it didn’t. Rollbacks were manual, promotions were inconsistent, and there was no single place to reason about “what is actually running.”
This post is the blueprint we use to make deployments boring, repeatable, and traceable. It’s a hybrid: short narrative + a practical guide you can apply.
What we standardised on¶
- Single interface: everything deploys through ArgoCD Applications
- Environment overlays: dev → staging → prod are explicit
- Project + RBAC boundaries: no cross‑team bleed
- Promotion in Git: PRs and tags, not click‑ops
- Consistent health + rollouts: same signals everywhere

Architecture (repo + layout)¶
We keep a platform apps repo with a root App‑of‑Apps and a consistent layout:
Root app example:
# repo/gitops/app-of-apps/root-app.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: platform-root
namespace: argocd
spec:
project: platform
source:
repoURL: https://github.com/polarpoint-io/platform-apps
targetRevision: main
path: apps
destination:
server: https://kubernetes.default.svc
namespace: argocd
syncPolicy:
automated:
prune: true
selfHeal: true
1) ArgoCD Projects + RBAC (don’t skip)¶
Projects define where apps can deploy and who can touch them.
# repo/gitops/standardised/projects/platform-project.yaml
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
name: platform
namespace: argocd
spec:
sourceRepos:
- https://github.com/polarpoint-io/platform-apps
destinations:
- namespace: platform-*
server: https://kubernetes.default.svc
roles:
- name: team-readonly
policies:
- p, proj:platform:team-readonly, applications, get, platform/*, allow
- name: team-admin
policies:
- p, proj:platform:team-admin, applications, *, platform/*, allow
Why it matters: without Projects, every app can deploy anywhere. That’s how drift becomes security incidents.
2) Environment overlays (dev/staging/prod)¶
Keep environment diffs explicit and small. Example values:
# repo/gitops/standardised/overlays/values-dev.yaml
replicaCount: 1
resources:
limits:
cpu: 200m
memory: 256Mi
# repo/gitops/standardised/overlays/values-prod.yaml
replicaCount: 3
resources:
limits:
cpu: 1000m
memory: 1Gi
Rule: if it can’t be expressed as an overlay, it doesn’t get deployed.
3) Promotion flow (Git, not clicks)¶
We promote with branches/tags and ArgoCD Applications that point to them:
main→ devrelease/*→ stagingprod→ production (protected)
Example dev/staging/prod apps:
# repo/gitops/standardised/promotion/argocd-app-dev.yaml
spec:
source:
targetRevision: main
helm:
valueFiles: [values-dev.yaml]
# repo/gitops/standardised/promotion/argocd-app-staging.yaml
spec:
source:
targetRevision: release/v1.2.3
helm:
valueFiles: [values-staging.yaml]
# repo/gitops/standardised/promotion/argocd-app-prod.yaml
spec:
source:
targetRevision: prod
helm:
valueFiles: [values-prod.yaml]
4) Health, rollouts, and sync order¶
We standardise sync waves and health checks so dependencies come up in order.
# repo/gitops/standardised/health/sync-waves.yaml
metadata:
annotations:
argocd.argoproj.io/sync-wave: "1"
Standard rules: - readiness/liveness probes on all deployments - consistent timeouts + retries - health overrides for CRDs if needed
Operational impact¶
- Deployments are auditable Git changes
- Rollbacks are a single commit revert
- Drift is visible instead of hidden
- Teams still ship fast—but on rails
Walkthrough files¶
repo/gitops/app-of-apps/root-app.yamlrepo/gitops/standardised/projects/platform-project.yamlrepo/gitops/standardised/overlays/values-dev.yamlrepo/gitops/standardised/overlays/values-staging.yamlrepo/gitops/standardised/overlays/values-prod.yamlrepo/gitops/standardised/promotion/argocd-app-dev.yamlrepo/gitops/standardised/promotion/argocd-app-staging.yamlrepo/gitops/standardised/promotion/argocd-app-prod.yamlrepo/gitops/standardised/health/sync-waves.yaml