Skip to content

Lesson 4: ArgoCD ApplicationSets & Architectural Comparison: Crossplane vs. Terraform

🧠 The Concept (Explain Like I'm 5)

  • Application (One Toy Box): An ArgoCD Application deploys one microservice to one cluster. If you have 50 clusters and 200 microservices, creating 10,000 Application files by hand is impossible.
  • ApplicationSet (The Toy Factory Matrix): An ApplicationSet is a generator. You write one 20-line template that says: "For every cluster in my company, deploy these 10 core tools automatically." When an engineer connects cluster #51, all 10 tools deploy instantly with zero manual YAML!
  • Crossplane vs. Terraform (Continuous Loop vs. One-Time Run):
  • Terraform: Like baking a cake. You follow the recipe, bake it, and you're done. If someone eats half the cake 2 hours later, Terraform doesn't know until you run terraform plan next week.
  • Crossplane: Like a thermostat. You set the temperature to 72°F. If someone opens a window (manual AWS Console edit), the thermostat detects the cold air and automatically turns on the heater to push it back to 72°F (Continuous Reconciliation Loop).

🏢 The Enterprise Context

  • ApplicationSet Generators: Supports Git Directory generators, Cluster generators, and Matrix generators (e.g. combining a list of 50 clusters with a list of 10 microservices to generate 500 applications dynamically).
  • Crossplane vs. Terraform Trade-offs:
Dimension HashiCorp Terraform Crossplane (Kubernetes Control Plane)
Execution Model Discrete, triggered by human or CI/CD pipeline Continuous 24/7 reconciliation loop ($k8s$ controller pattern)
State Storage terraform.tfstate in S3 / DynamoDB lock Stored natively in Kubernetes etcd as Custom Resources
Drift Management Detects drift only during terraform plan Automatically corrects drift immediately upon detection
API Interface HashiCorp Configuration Language (HCL) Native Kubernetes YAML / OpenAPI
Role in Platform Excellent for Day-0 Landing Zones & VPCs Superior for Day-2 Developer Self-Service Claims

🗺️ Visual Architecture: The ApplicationSet Matrix Generator Flow

flowchart TD
    GitClusters["<b>Cluster Discovery Generator</b><br/>• Cluster: prod-us-east-1<br/>• Cluster: prod-eu-west-1<br/>• Cluster: prod-ap-southeast-1"]

    GitApps["<b>Git Directory Generator</b><br/>• Service: payment-api<br/>• Service: order-api<br/>• Service: auth-api"]

    Matrix["<b>ArgoCD ApplicationSet (Matrix Generator)</b><br/>Cross-Multiplies: 3 Clusters × 3 Services = 9 Apps"]

    subgraph GeneratedApps ["Dynamically Generated ArgoCD Applications"]
        A1["App: payment-api on prod-us-east-1"]
        A2["App: payment-api on prod-eu-west-1"]
        A3["App: payment-api on prod-ap-southeast-1"]
        A4["App: order-api on prod-us-east-1"]
        A5["... Remaining 5 Applications"]
    end

    GitClusters --> Matrix
    GitApps --> Matrix
    Matrix --> GeneratedApps

💻 Production Code: ArgoCD Matrix ApplicationSet Manifest

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: fleet-monitoring-deployer
  namespace: argocd
spec:
  generators:
    - matrix:
        generators:
          # Generator 1: Discover all production clusters registered with ArgoCD
          - clusters:
              selector:
                matchLabels:
                  environment: production
          # Generator 2: Discover monitoring components from Git folders
          - git:
              repoURL: https://github.com/my-org/gitops-platform.git
              revision: HEAD
              directories:
                - path: platform-tools/*
  template:
    metadata:
      name: '{{name}}-{{path.basename}}'
    spec:
      project: default
      source:
        repoURL: https://github.com/my-org/gitops-platform.git
        targetRevision: HEAD
        path: '{{path}}'
      destination:
        server: '{{server}}' # Injected dynamically per cluster
        namespace: '{{path.basename}}'
      syncPolicy:
        automated:
          prune: true
          selfHeal: true