apiVersion: v1
kind: Secret
metadata:
name: repo-team-a-apps
namespace: argocd
labels:
argocd.argoproj.io/secret-type: repository
stringData:
type: git
url: https://github.com/acme/team-a-apps.git
username: argocd
password: <read-only token>
---
apiVersion: v1
kind: Secret
metadata:
name: cluster-prod-eu
namespace: argocd
labels:
argocd.argoproj.io/secret-type: cluster
env: prod
stringData:
name: prod-eu
server: https://prod-eu.k8s.example.com
config: |
{
"bearerToken": "<service account token>",
"tlsClientConfig": { "caData": "<base64 CA>" }
}
---
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
name: team-a
namespace: argocd
spec:
sourceRepos:
- https://github.com/acme/team-a-apps.git
destinations:
- name: prod-eu
namespace: team-a-*
clusterResourceWhitelist: []
namespaceResourceBlacklist:
- group: ""
kind: ResourceQuota
---
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: team-a
namespace: argocd
spec:
goTemplate: true
goTemplateOptions: ["missingkey=error"]
generators:
- git:
repoURL: https://github.com/acme/team-a-apps.git
revision: main
directories:
- path: apps/*
template:
metadata:
name: "team-a-{{ .path.basename }}"
spec:
project: team-a
source:
repoURL: https://github.com/acme/team-a-apps.git
targetRevision: main
path: "{{ .path.path }}"
destination:
name: prod-eu
namespace: "team-a-{{ .path.basename }}"
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=trueArgo CD graph
Argo CD: ApplicationSet, AppProject and the Applications it generates
How Argo CD turns one ApplicationSet into an Application per app directory, which AppProject limits what they may deploy, and where the repository and cluster credentials live.
An Argo CD Application says: take this path in this repo and keep it in sync with this namespace on this cluster. Writing one per app gets old fast, so an ApplicationSet generates them. Its Git directory generator creates one Application for every folder under apps/.
Two kinds of Secret do the plumbing. A Secret labeled argocd.argoproj.io/secret-type: repository holds Git credentials, and one labeled secret-type: cluster registers a cluster. The AppProject draws the security boundary: which repos, clusters, namespaces and kinds its Applications may use.
Interactive graph
Click a resource to see what it does, or follow the setup step by step.
How it works
All 10 resources and what they do
- Git repository github.com/acme/team-a-apps
- Holds one folder per app under
apps/, each with plain YAML, a Kustomize overlay or a Helm chart. Adding a folder is all it takes to deploy a new app. - Secret repo-team-a-appsv1
- The label
argocd.argoproj.io/secret-type: repositorymakes Argo CD treat it as repository credentials. The repo server and the ApplicationSet controller use it for every Application pointing at this URL. - Secret cluster-prod-euv1
- Registers the
prod-eucluster with its API server URL and credentials.argocd cluster addwrites one of these for you. The Applications refer to the cluster by name. - AppProject team-aargoproj.io/v1alpha1
- Limits what team A's Applications can do: only this repo, only namespaces starting with
team-a-onprod-eu, and no cluster-scoped objects. An Application asking for more fails with a permission error instead of syncing. - ApplicationSet team-aargoproj.io/v1alpha1
- Lists the folders under
apps/and renders the template once per folder, with{{ .path.basename }}as the app name. Folders added or removed in Git turn into Applications created or deleted. - Application team-a-billingargoproj.io/v1alpha1
- Generated from
apps/billing. The ApplicationSet owns it, so a manual edit is overwritten on the next generator run. Its status showsSyncedandHealthyonce the cluster matches Git. - Application team-a-searchargoproj.io/v1alpha1
- Generated from
apps/search, the same way. Each Application syncs on its own, so a broken search manifest doesn't block billing. - StatefulSet argocd-application-controllerapps/v1
- Compares each Application's rendered manifests, which it gets from the repo server, with the live objects on the target cluster, then applies the difference. Large installs shard clusters across its replicas.
- Deployment billingapps/v1
- Applied to
prod-euby the application controller. Argo CD tracks it with theargocd.argoproj.io/tracking-idannotation, the default tracking method since Argo CD 3.0. - Deployment searchapps/v1
- Applied to
prod-eufromapps/search. WithselfHeal: true, akubectl edithere is reverted within a few seconds.
Common mistakes
- The ApplicationSet owns the Applications it generates. Edits to them, including changes from the Argo CD UI, are reverted on the next run. Change the template instead.
- An Application whose destination the AppProject doesn't allow gets an
InvalidSpecErrorcondition, and a kind it doesn't allow fails the sync with "not permitted in project". Compareargocd proj get team-awith what the Application asks for. - With
goTemplate: true,missingkey=errorturns a typo like{{ .path.basname }}into an error. Without it, the typo renders as<no value>and creates an Application with a broken name. - Deleting the ApplicationSet deletes every Application it generated, and with them their resources. Remove the generator's targets one at a time, or orphan them first with
kubectl delete applicationset team-a -n argocd --cascade=orphan. - The
defaultAppProject allows everything. Give each team its own project before you give them the ability to create Applications.
The manifests you write
Everything above that is marked "You write it", in one file. The rest comes from add-ons and controllers.
Keep going
More graphs
- Deployment, Service and Ingress: how a request reaches your Pods
- Gateway API: GatewayClass, Gateway and HTTPRoute with a canary split
- PVC, StorageClass and CSI: how a cloud disk ends up in your Pod
- RBAC: how a ServiceAccount gets its permissions
- cert-manager with Let's Encrypt: Certificate, CertificateRequest, Order and Challenge
- A private CA with cert-manager and trust-manager
- Istio traffic management: Gateway, VirtualService, DestinationRule and policies
- Flux dependencies: Git and OCI sources, Kustomizations and HelmReleases
- Inside an OCI image: tag, index, manifests, config and layers
- OCI artifacts: Helm charts, Flux artifacts and image volumes