{"id":51331033,"url":"https://github.com/gerardrecinto/argocd-gitops","last_synced_at":"2026-07-01T23:01:44.470Z","repository":{"id":359510316,"uuid":"1245424836","full_name":"gerardrecinto/argocd-gitops","owner":"gerardrecinto","description":"GitOps patterns with ArgoCD: App-of-Apps, ApplicationSets, sync policies, RBAC, and multi-cluster deployment workflows","archived":false,"fork":false,"pushed_at":"2026-06-11T09:39:22.000Z","size":729,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-11T11:18:15.914Z","etag":null,"topics":["app-of-apps","applicationset","argocd","continuous-delivery","devops","gitops","helm","kubernetes"],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gerardrecinto.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-21T07:56:08.000Z","updated_at":"2026-06-11T09:39:27.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/gerardrecinto/argocd-gitops","commit_stats":null,"previous_names":["gerardrecinto/argocd-gitops"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/gerardrecinto/argocd-gitops","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gerardrecinto%2Fargocd-gitops","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gerardrecinto%2Fargocd-gitops/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gerardrecinto%2Fargocd-gitops/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gerardrecinto%2Fargocd-gitops/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gerardrecinto","download_url":"https://codeload.github.com/gerardrecinto/argocd-gitops/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gerardrecinto%2Fargocd-gitops/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35025983,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-01T02:00:05.325Z","response_time":130,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["app-of-apps","applicationset","argocd","continuous-delivery","devops","gitops","helm","kubernetes"],"created_at":"2026-07-01T23:01:39.142Z","updated_at":"2026-07-01T23:01:44.460Z","avatar_url":"https://github.com/gerardrecinto.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# argocd-gitops\n\n![ArgoCD GitOps logo](docs/assets/logo.svg)\n\n![ArgoCD](https://img.shields.io/badge/ArgoCD-2.x-EF7B4D?logo=argo\u0026logoColor=white)\n![Kubernetes](https://img.shields.io/badge/Kubernetes-1.28%2B-326CE5?logo=kubernetes\u0026logoColor=white)\n![Helm](https://img.shields.io/badge/Helm-3.x-0F1689?logo=helm\u0026logoColor=white)\n![GitHub Actions](https://img.shields.io/badge/GitHub%20Actions-CI-2088FF?logo=githubactions\u0026logoColor=white)\n![License: MIT](https://img.shields.io/badge/License-MIT-22c55e)\n\n![Demo](docs/assets/demo.gif)\n\nArgoCD GitOps patterns for multi-cluster Kubernetes. Covers the App-of-Apps bootstrap pattern, ApplicationSets for dynamic application generation, sync policies with automated pruning and self-healing, AppProject RBAC, and environment-specific value overlays.\n\nCommercial angle and consulting hooks: [docs/go-to-market.md](docs/go-to-market.md).\n\n\u003e All cluster names, namespaces, registry URLs, and hostnames use `PLACEHOLDER_*` values. These are reference patterns, not a live cluster's actual config. Swap the placeholders for your own before applying anything here.\n\n---\n\n## Structure\n\n```\napps/\n├── root-app.yaml              App-of-Apps: watches apps/infra/ and apps/services/\n├── applicationsets/\n│   ├── cluster-addons.yaml    Cluster generator: deploy infra addons to every registered cluster\n│   ├── services.yaml          Git directory generator: one Application per service directory\n│   └── preview-envs.yaml      Pull request generator: ephemeral preview envs per open PR\n├── infra/\n│   ├── cert-manager.yaml\n│   ├── ingress-nginx.yaml\n│   ├── metallb.yaml\n│   └── monitoring.yaml\n└── services/\n    └── api-gateway.yaml        Standalone Application, onboarded before the ApplicationSet existed\n\nprojects/\n├── infra.yaml                 AppProject: cluster-scoped addons, restricted source repos\n└── services.yaml              AppProject: application services, namespace-scoped\n\nrbac/\n└── policy.csv                 ArgoCD RBAC: get/list for everyone, sync for devs on services/*, full control for leads on services/*, admin for platform\n\nclusters/\n├── prod/\n│   └── values.yaml         Per-cluster overrides (domain, ingress IP, replica bounds), reference\n└── staging/                 values for teams wiring their own service charts, not consumed by\n    └── values.yaml          any Application in this repo yet.\n```\n\n---\n\n## Patterns\n\n### App-of-Apps\n\nA single root Application watches this repo. Any Application manifest added to `apps/infra/` or `apps/services/` is automatically picked up and synced. Bootstrap is one command:\n\n```bash\nargocd app create root \\\n  --repo https://github.com/gerardrecinto/argocd-gitops \\\n  --path apps \\\n  --dest-server https://kubernetes.default.svc \\\n  --dest-namespace argocd \\\n  --sync-policy automated \\\n  --auto-prune \\\n  --self-heal\n```\n\n---\n\n### ApplicationSet: Cluster Addons\n\nDeploys cert-manager, ingress-nginx, MetalLB, and monitoring to every cluster registered in ArgoCD. Adding a cluster automatically provisions all addons without any manual Application creation.\n\nSee [apps/applicationsets/cluster-addons.yaml](apps/applicationsets/cluster-addons.yaml).\n\n`apps/infra/monitoring.yaml` points Grafana's admin credentials at a `grafana-admin-credentials` secret (`admin.existingSecret`) instead of a plaintext value. That secret is provisioned per-cluster out of band, through the platform team's secrets manager, and never committed to this repo. It needs to exist before the monitoring Application syncs.\n\n---\n\n### ApplicationSet: Services (Git Directory Generator)\n\nScans `charts/services/` and creates one Application per subdirectory. New services are deployed by adding a Helm chart directory: no ArgoCD manifest to write. `charts/services/` doesn't exist yet in this repo; `apps/services/api-gateway.yaml` predates the ApplicationSet and is still managed as a standalone Application.\n\nSee [apps/applicationsets/services.yaml](apps/applicationsets/services.yaml).\n\n---\n\n### ApplicationSet: Preview Environments\n\nUses the pull request generator to create a temporary namespace and Application for every open PR targeting `main`. The preview env is garbage-collected when the PR closes.\n\nSee [apps/applicationsets/preview-envs.yaml](apps/applicationsets/preview-envs.yaml).\n\n---\n\n### Sync Policy\n\nAll production Applications use:\n\n```yaml\nsyncPolicy:\n  automated:\n    prune: true      # removes resources deleted from Git\n    selfHeal: true   # reverts manual kubectl edits\n  syncOptions:\n    - CreateNamespace=true\n    - PrunePropagationPolicy=foreground\n    - RespectIgnoreDifferences=true\n  retry:\n    limit: 3\n    backoff:\n      duration: 10s\n      factor: 2\n      maxDuration: 3m\n```\n\nStaging uses the same policy. Preview envs use manual sync to avoid accidental resource creation.\n\n---\n\n### AppProjects\n\n`projects/infra.yaml`: cluster-admin scope, locked to the platform team's repo, only deploys to `kube-system` and addon namespaces.\n\n`projects/services.yaml`: namespace-scoped, locked to the application services repo, teams can only deploy to their own namespaces.\n\nSee [projects/](projects/).\n\n---\n\n### RBAC\n\nFour roles, scoped by both action and project so no role gets a blanket `*/*` grant except `platform`, which is the intentional break-glass/admin tier:\n\n- `readonly`: every authenticated user, `get`/`list` on applications across all projects, `get` on repositories. No write actions anywhere.\n- `developer`: `get`/`sync`/`action` on `services/*` only. Cannot touch `infra/*`.\n- `lead`: full application actions on `services/*` only, plus `repositories, get`. Still can't touch `infra/*`.\n- `platform`: unrestricted. The platform team owns cluster-scoped infra and needs it.\n\nSee [rbac/policy.csv](rbac/policy.csv) for the exact policy: it's the source of truth, this section just summarizes the intent.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgerardrecinto%2Fargocd-gitops","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgerardrecinto%2Fargocd-gitops","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgerardrecinto%2Fargocd-gitops/lists"}