diff --git a/APPLICATIONSET_GUIDE.md b/APPLICATIONSET_GUIDE.md new file mode 100644 index 0000000..c0be09c --- /dev/null +++ b/APPLICATIONSET_GUIDE.md @@ -0,0 +1,290 @@ +# ApplicationSet Guide + +## Overview + +This repository uses **ApplicationSet** (instead of the traditional app-of-apps pattern) to manage infrastructure applications. ApplicationSet automatically discovers and creates ArgoCD Applications based on a git directory pattern. + +## How It Works + +### ApplicationSet Definition +Located in `argocd/_app-of-apps.yaml`: + +```yaml +apiVersion: argoproj.io/v1alpha1 +kind: ApplicationSet +metadata: + name: infrastructure-apps + namespace: argocd +spec: + goTemplate: true + generators: + - git: + repoURL: https://github.com/fortedigital/sturdy-adventure.git + revision: HEAD + directories: + - path: argocd/infra/*.yaml + template: + # Template applied to each discovered file +``` + +### Key Components + +1. **Generator**: Scans `argocd/infra/*.yaml` for all Application manifests +2. **Path Variables**: Each match provides template variables: + - `{{ .path.basenameNormalized }}` - filename without extension (e.g., "prometheus") + - `{{ .path.dir }}` - directory path (e.g., "argocd/infra") +3. **Template**: Used to create consistent Applications from the discovered files + +## How Applications Are Created + +When you create a new file `argocd/infra/my-app.yaml`: + +```yaml +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: my-app + # ... other config +spec: + # ... your application spec +``` + +The ApplicationSet: +1. Discovers the file matching `argocd/infra/*.yaml` +2. Extracts metadata: `basenameNormalized=my-app`, `dir=argocd/infra` +3. Renders the template with these variables +4. Creates an Application resource with: + - Name: `my-app` + - Labels applied from the template + - Sync policy inherited from template + - Source path: `argocd/infra` + +## Adding New Applications + +### Step 1: Create Application YAML +Create `argocd/infra/my-new-app.yaml`: + +```yaml +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: my-new-app + annotations: + argocd.argoproj.io/sync-wave: "2" # Optional: control sync ordering +spec: + project: default + source: + repoURL: https://my-helm-repo.com + chart: my-chart + targetRevision: "1.0.0" + helm: + releaseName: my-new-app + destination: + server: https://kubernetes.default.svc + namespace: my-namespace + # Note: syncPolicy is applied from the ApplicationSet template + # No need to duplicate it here +``` + +### Step 2: Push to Repository +```bash +git add argocd/infra/my-new-app.yaml +git commit -m "Add my-new-app infrastructure application" +git push +``` + +### Step 3: Verify Discovery +```bash +# View all generated applications +kubectl get applications -n argocd + +# Check ApplicationSet status +kubectl describe applicationset infrastructure-apps -n argocd + +# Watch for your new application +kubectl get application my-new-app -n argocd -w +``` + +## Template Variables + +The ApplicationSet template uses these variables for each discovered file: + +| Variable | Example | Description | +|----------|---------|-------------| +| `{{ .path.basenameNormalized }}` | `prometheus` | Filename without extension | +| `{{ .path.dir }}` | `argocd/infra` | Directory containing the file | +| `{{ .path.path }}` | `argocd/infra/prometheus.yaml` | Full path to the file | + +## ApplicationSet Features Used + +### 1. Git Directory Generator +```yaml +generators: +- git: + repoURL: https://github.com/fortedigital/sturdy-adventure.git + revision: HEAD + directories: + - path: argocd/infra/*.yaml # Match all YAML files +``` + +Automatically discovers applications in the git repository. + +### 2. Go Templating +```yaml +goTemplate: true +``` + +Enables Go template syntax for variable interpolation (e.g., `{{ .path.basenameNormalized }}`). + +### 3. Dynamic Application Generation +```yaml +template: + metadata: + name: "{{ .path.basenameNormalized }}" + labels: + app.kubernetes.io/name: "{{ .path.basenameNormalized }}" +``` + +Each discovered file generates an Application with consistent configuration. + +## Benefits Over App-of-Apps Pattern + +| Feature | ApplicationSet | App-of-Apps | +|---------|---|---| +| Auto-discovery | ✅ Automatic | ❌ Manual list required | +| New app onboarding | 1 file created | 1 file created + parent update | +| Consistency | ✅ Template enforced | ❌ Manual consistency | +| Scalability | ✅ Grows automatically | ❌ Manual maintenance | +| RBAC per app | ✅ Supported | ❌ Limited | +| Drift detection | ✅ Per app | ✅ Per app | + +## Sync Policy Applied by ApplicationSet + +All generated Applications inherit this sync policy from the template: + +```yaml +syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=true + - Validate=true + - ServerSideApply=true + timeout: 300s + retry: + limit: 5 + backoff: + duration: 5s + factor: 2 + maxDuration: 3m +``` + +**What this means:** +- ✅ Automatic syncing when repository changes +- ✅ Automatic pruning of deleted resources +- ✅ Self-healing if cluster drifts from git +- ✅ Namespace auto-creation if missing +- ✅ Manifest validation before applying +- ✅ Server-side apply for field ownership +- ✅ 5-minute timeout per application sync +- ✅ Up to 5 retry attempts with exponential backoff + +## Monitoring ApplicationSet + +### View ApplicationSet Status +```bash +kubectl describe applicationset infrastructure-apps -n argocd +``` + +Output shows: +- Condition status (Healthy, Progressing, etc.) +- Number of applications created +- Last sync time +- Error messages if any + +### View Generated Applications +```bash +# All applications created by this ApplicationSet +kubectl get applications -n argocd -l app.kubernetes.io/managed-by=argocd + +# View a specific application +kubectl get application prometheus -n argocd -o yaml +``` + +### Check Sync Status +```bash +# Watch all applications +kubectl get applications -n argocd -w + +# Detailed sync status +argocd app list + +# Application health +kubectl get applications -n argocd -o wide +``` + +## Troubleshooting + +### ApplicationSet Not Creating Applications + +**Problem**: Files in `argocd/infra/` but no Applications created + +**Solutions**: +1. Check file naming: Must end with `.yaml` (not `.yml`) +2. Verify path: Files must be in `argocd/infra/` (not subdirectories) +3. Check permissions: Repository URL must be accessible +4. Review ApplicationSet status: `kubectl describe applicationset infrastructure-apps -n argocd` + +### Application Created But Not Syncing + +**Problem**: Application exists but stays in "OutOfSync" state + +**Solutions**: +1. Check application spec is valid YAML +2. Verify `destination.server` is accessible: `https://kubernetes.default.svc` +3. Check `destination.namespace` exists or `CreateNamespace=true` is set +4. Review application logs: `kubectl logs -n argocd deployment/argocd-application-controller` + +### ApplicationSet Generates Duplicate Applications + +**Problem**: Same application created multiple times + +**Solutions**: +1. Check for duplicate files in `argocd/infra/` with same name +2. Clear git cache: `git clean -fd` +3. ApplicationSet may take time to reconcile; wait 60 seconds + +## Best Practices + +1. **File Organization** + - Keep only Application manifests in `argocd/infra/` + - Don't mix other resource types (ConfigMaps, Secrets, etc.) + - Use consistent naming: `lowercase-with-hyphens.yaml` + +2. **Application Design** + - Keep each Application spec in the discovered file + - Don't rely on syncPolicy being defined in the Application (it comes from ApplicationSet) + - Use sync waves for dependency ordering + +3. **Repository Management** + - All files in `argocd/infra/` should be valid Kubernetes manifests + - Regular commits to track changes + - Use branches for testing new applications before merging + +4. **Monitoring** + - Regularly check ApplicationSet status + - Monitor generated applications for sync status + - Set up alerts for Failed or Degraded applications + +5. **Updates** + - Update application specs directly in `argocd/infra/` files + - ApplicationSet changes take effect within 60 seconds + - Test in dev environment first + +## Related Documentation + +- [ArgoCD ApplicationSet Docs](https://argocd-applicationset.readthedocs.io/) +- [ArgoCD Application Spec](https://argo-cd.readthedocs.io/en/stable/operator-manual/declarative-setup/#applications) +- [Kubernetes Application Convention](https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#recommended-labels) + diff --git a/argocd/_app-of-apps.yaml b/argocd/_app-of-apps.yaml index 76b1c2f..2a6f08a 100644 --- a/argocd/_app-of-apps.yaml +++ b/argocd/_app-of-apps.yaml @@ -1,26 +1,44 @@ apiVersion: argoproj.io/v1alpha1 -kind: Application +kind: ApplicationSet metadata: - name: app-of-apps + name: infrastructure-apps namespace: argocd - labels: - scope: infra spec: - project: default - source: - repoURL: https://github.com/fortedigital/sturdy-adventure.git - targetRevision: HEAD - path: argocd - directory: - recurse: true - destination: - server: https://kubernetes.default.svc - namespace: argocd - syncPolicy: - automated: - prune: true - selfHeal: true - syncOptions: - - CreateNamespace=true - - Validate=true - - ServerSideApply=true + goTemplate: true + generators: + - git: + repoURL: https://github.com/fortedigital/sturdy-adventure.git + revision: HEAD + directories: + - path: argocd/infra/*.yaml + template: + metadata: + name: "{{ .path.basenameNormalized }}" + labels: + app.kubernetes.io/name: "{{ .path.basenameNormalized }}" + app.kubernetes.io/part-of: platform + app.kubernetes.io/managed-by: argocd + spec: + project: default + source: + repoURL: https://github.com/fortedigital/sturdy-adventure.git + targetRevision: HEAD + path: "{{ .path.dir }}" + destination: + server: https://kubernetes.default.svc + namespace: argocd + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=true + - Validate=true + - ServerSideApply=true + timeout: 300s + retry: + limit: 5 + backoff: + duration: 5s + factor: 2 + maxDuration: 3m diff --git a/bootstrap.sh b/bootstrap.sh index 4d7840d..f17451b 100644 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -36,7 +36,7 @@ ArgoCd() helm upgrade --install argocd argo-cd \ --repo https://argoproj.github.io/argo-helm \ --namespace argocd --create-namespace \ - --values argocd-values.yaml \ + --values argocd/values/argocd-values.yaml \ --timeout 60s --atomic }