GitOps with ArgoCD & Flux

ArgoCD Architecture & Setup

18 min Lesson 3 of 30

ArgoCD Architecture & Setup

ArgoCD is the most widely deployed GitOps operator in the industry. Before you install it, you need to understand its internals — otherwise, every production incident will feel like a black box. ArgoCD consists of three principal components: the Application Controller, the Repo Server, and the API Server (plus the UI and Dex for SSO). Each has a distinct responsibility in the reconciliation loop that keeps your cluster in sync with Git.

Component 1: The Repo Server

The Repo Server is ArgoCD's source-of-truth reader. It is responsible for cloning Git repositories, rendering manifests from whatever templating engine the application uses (plain YAML, Helm, Kustomize, Jsonnet, custom plugins), and returning the rendered Kubernetes objects as a list. It is intentionally stateless — it holds no cluster credentials and never talks to the Kubernetes API. This isolation is a security boundary: a compromised Repo Server cannot directly mutate the cluster.

The Repo Server caches rendered manifests in a local cache (backed by the argocd-repo-server Deployment's in-memory store). When you trigger a refresh, the Repo Server re-clones or fetches the latest commit, re-renders, and hands the result to the Application Controller. You can run multiple replicas of the Repo Server for high availability — each is stateless, so they are safe to scale independently.

Pro tip — Repo Server resource sizing: Helm chart rendering is CPU-intensive. At scale (hundreds of Applications), the Repo Server becomes the bottleneck. Set explicit CPU requests/limits and run at least 2 replicas. Google and Stripe both run dedicated Repo Server pools for large multi-tenant ArgoCD installations.

Component 2: The Application Controller

The Application Controller is the heart of ArgoCD. It is a Kubernetes controller — it runs a reconciliation loop, just like the Deployment controller you already know. Every N seconds (default: 3 minutes, configurable via --app-resync-period), it:

  1. Reads the desired state from the Repo Server (the rendered Git manifests).
  2. Reads the live state from the cluster (via the Kubernetes API).
  3. Diffs the two states.
  4. If syncPolicy.automated is enabled, applies the diff. Otherwise, marks the Application as OutOfSync and waits for a human or CI trigger.

The Application Controller also evaluates health status. It knows how to assess the health of built-in Kubernetes resource types (Deployment, StatefulSet, DaemonSet, Service, Ingress) and lets you define custom health checks in Lua for CRDs. An Application is Healthy only when every child resource is healthy — not just present.

Key idea — sharding at scale: By default, one Application Controller pod manages all Applications. When you reach hundreds of Applications, a single controller becomes a bottleneck. ArgoCD supports controller sharding via the ARGOCD_CONTROLLER_REPLICAS environment variable — each shard owns a partition of the Application set. This is how companies like Intuit (ArgoCD's original author) run thousands of Applications on a single control plane.

Component 3: The API Server & the Application CRD

The API Server exposes the REST and gRPC API consumed by the CLI, the UI, and external CI systems. It handles authentication (local users, OIDC/Dex, LDAP), RBAC enforcement via AppProject policies, and routes commands (sync, rollback, refresh) to the Application Controller via the shared Redis instance.

The Application CRD is the declarative unit of work in ArgoCD. Every ArgoCD Application is a custom Kubernetes resource of kind Application in the argoproj.io/v1alpha1 API group. Its spec has three mandatory sections:

  • source — which Git repo, revision (branch/tag/SHA), and path (or chart name + version for Helm repos).
  • destination — which cluster (by URL or in-cluster) and which namespace to deploy into.
  • project — which AppProject governs RBAC and allowed clusters/repos for this Application.
ArgoCD component architecture and reconciliation flow Git Repo (source of truth) ArgoCD Control Plane (argocd namespace) Repo Server clone & render Helm/Kustomize App Controller diff & reconcile health checks API Server REST/gRPC + RBAC Redis shared cache App CRD etcd Target Cluster Kubernetes API fetch manifests reads/writes apply diff commands
ArgoCD reconciliation flow: the Repo Server renders manifests from Git, the Application Controller diffs and applies them to the target cluster, and the Application CRD in etcd is the single source of control-plane state.

Installing ArgoCD — Production-Grade Setup

The official install manifest is a good starting point, but production deployments need a few tweaks before they are ready. Below is the standard install sequence followed by the critical post-install configuration steps that most tutorials skip.

# 1. Create the namespace kubectl create namespace argocd # 2. Apply the stable install manifest (pin to a specific version — never use latest in prod) kubectl apply -n argocd -f \ https://raw.githubusercontent.com/argoproj/argo-cd/v2.11.3/manifests/install.yaml # 3. Wait for all components to be ready kubectl -n argocd rollout status deploy/argocd-server kubectl -n argocd rollout status deploy/argocd-repo-server kubectl -n argocd rollout status deploy/argocd-application-controller # 4. Retrieve the initial admin password (auto-generated, stored in a Secret) kubectl -n argocd get secret argocd-initial-admin-secret \ -o jsonpath="{.data.password}" | base64 -d; echo # 5. Port-forward the API server for first-time access kubectl -n argocd port-forward svc/argocd-server 8080:443 & # 6. Log in with the ArgoCD CLI argocd login localhost:8080 --username admin --insecure # 7. Change the admin password immediately (the initial secret should be deleted after this) argocd account update-password # 8. Delete the bootstrap secret — it is no longer needed kubectl -n argocd delete secret argocd-initial-admin-secret
Production pitfall — never expose argocd-server with type LoadBalancer before enabling TLS termination. The default install runs without TLS. Exposing it publicly (even briefly) leaks your cluster credentials to anyone who can reach the endpoint. Use an Ingress with cert-manager, or an internal ALB, and enable OIDC SSO before promoting to production.

Your First Application CRD

Once ArgoCD is installed, you define Applications as YAML. The following manifest deploys a Helm chart from a Git repo into the staging namespace, with automated sync and self-healing enabled:

# file: apps/staging/payments.yaml # Apply with: kubectl apply -f apps/staging/payments.yaml -n argocd apiVersion: argoproj.io/v1alpha1 kind: Application metadata: name: payments-staging namespace: argocd # Finalizer ensures ArgoCD deletes all child resources when the Application is deleted (cascade delete) finalizers: - resources-finalizer.argocd.argoproj.io spec: project: default source: repoURL: https://github.com/example-org/platform-gitops targetRevision: HEAD # track main branch; use a SHA or tag for immutable prod deploys path: helm/payments # path inside the repo containing Chart.yaml or kustomization.yaml helm: valueFiles: - values.yaml - values-staging.yaml # environment overlay destination: server: https://kubernetes.default.svc # in-cluster deployment namespace: staging syncPolicy: automated: prune: true # delete resources removed from Git selfHeal: true # re-sync if someone manually edits the cluster syncOptions: - CreateNamespace=true - PrunePropagationPolicy=foreground retry: limit: 5 backoff: duration: 5s factor: 2 maxDuration: 3m
Key idea — prune: true and selfHeal: true together enforce strict GitOps. Without prune, resources deleted from Git linger in the cluster. Without selfHeal, a manual kubectl apply or helm upgrade from a developer's laptop will create a divergence that ArgoCD never fixes. Both flags are off by default — turn them on in all non-production environments first, observe the behaviour, then enable in production.

Inspecting Application State from the CLI

The argocd CLI is the operator's primary debug tool. These commands cover the most common production queries:

# List all Applications and their sync/health status argocd app list # Show full details: sync status, health, last sync time, images deployed argocd app get payments-staging # Force an immediate refresh from Git (bypasses the resync interval cache) argocd app get payments-staging --refresh # Trigger a manual sync argocd app sync payments-staging # Show exactly what ArgoCD would change before syncing (dry-run diff) argocd app diff payments-staging # Roll back to the previous synced revision argocd app rollback payments-staging 0 # 0 = one step back; use ID from history argocd app history payments-staging # list available rollback targets # Watch sync progress in real time argocd app wait payments-staging --sync --health --timeout 120

Understanding the Architecture → Setup → Inspect workflow is the foundation for every advanced ArgoCD topic: multi-cluster management, App-of-Apps, ApplicationSets, and secrets handling. The components you learned here — Repo Server, Application Controller, API Server, Application CRD — map directly to the failure modes you will diagnose in production incidents.