Repo Server

Repo Server Deep-Dive

What This Component Does

The Repo Server is Argo CD’s stateless manifest generation service. It is responsible for the critical translation step: taking an application source definition (Git repo URL, path, revision, tool-specific parameters) and producing a list of rendered Kubernetes manifests ready for comparison or deployment. It supports multiple configuration management tools (Helm, Kustomize, Jsonnet, plain YAML/JSON) and custom Config Management Plugins (CMP).

The repo server is designed for throughput and cacheability. It implements aggressive multi-level caching (in-memory + Redis), parallelism controls, and failure backoff to handle large-scale Argo CD installations with thousands of applications. It is the only component that interacts directly with Git repositories and Helm/OCI registries.

Use cases: Runs as a Deployment in the argocd namespace. Scale horizontally by increasing replicas for manifest generation throughput. Configure via --parallelism-limit for concurrent generation limits and --max-combined-directory-manifests-size for output size caps.

How It Works

The repo server exposes a gRPC service that the Application Controller calls. On each GenerateManifest request, it clones (or fetches from cache) the Git repository, resolves the target revision, runs the appropriate manifest generation tool, and returns the rendered manifests. The entire pipeline is designed for idempotency and cacheability.

Internal Flow Diagram

flowchart TD
    A[gRPC Request<br/>GenerateManifest<br/>repo, rev, path, params] --> B{Cache Lookup<br/>Redis + in-memory}
    B -->|Hit| C[Return cached manifests]
    B -->|Miss| D[Acquire semaphore<br/>parallelism-limit]
    D --> E[Git Operation<br/>Clone or fetch revision]
    E --> F[Resolve revision<br/>Branch -> commit SHA]
    F --> G{Detect tool type}
    G -->|Helm| H[helm template<br/>+ values files + params]
    G -->|Kustomize| I[kustomize build<br/>+ overlays]
    G -->|Jsonnet| J[jsonnet eval<br/>+ ext vars + TLAs]
    G -->|Directory| K[Read YAML/JSON files<br/>from path]
    G -->|Plugin| L[CMP Sidecar<br/>Custom generation]
    H --> M[Validate output<br/>Size limits check]
    I --> M
    J --> M
    K --> M
    L --> M
    M --> N[Cache result<br/>Redis + in-memory]
    N --> O[Return manifests<br/>gRPC response]

    style A fill:#f9f
    style O fill:#9f9

Step-by-Step Process:

  1. Request Reception: Application Controller sends gRPC GenerateManifest with repo URL, target revision, path, Helm values, Kustomize options, etc.
  2. Cache Lookup: Checks in-memory cache and Redis for a previous result matching the composite key (repoURL, revision, path, params, toolVersion). On hit, returns immediately.
  3. Concurrency Control: Acquires a semaphore slot (configurable via --parallelism-limit) to prevent resource exhaustion from concurrent generations.
  4. Git Operations: Clones the repository (shallow clone for efficiency) or fetches the target revision if a local checkout exists. Supports submodules, GPG verification, and SSH/HTTPS auth.
  5. Revision Resolution: Resolves symbolic references (branch names, tags) to concrete commit SHAs for cache determinism.
  6. Tool Detection: Determines the manifest generation tool based on directory contents (Chart.yaml -> Helm, kustomization.yaml -> Kustomize) or explicit Application source configuration.
  7. Manifest Generation: Runs the appropriate tool:
    • Helm: Executes helm template with values files, parameters, and --api-versions
    • Kustomize: Runs kustomize build with optional overlay paths
    • Jsonnet: Evaluates Jsonnet files with external variables and top-level arguments
    • Directory: Reads all .yaml/.json files from the specified path
    • CMP: Delegates to a Config Management Plugin sidecar via gRPC
  8. Validation: Checks output against size limits (--max-combined-directory-manifests-size). Rejects oversized results to prevent memory issues.
  9. Caching: Stores the result in both in-memory and Redis caches with the composite key.
  10. Response: Returns the list of Kubernetes manifests to the Application Controller.

Key Code Paths

Server Setup

reposerver/server.go - gRPC server initialization:

The ArgoCDRepoServer struct wraps the gRPC server with TLS configuration, health checks, and metrics. It initializes the repoService which handles the actual manifest generation logic.

Repository Service

reposerver/repository/ - Core generation logic:

This package contains the Service struct implementing the RepoServerServiceServer gRPC interface. Key methods:

  • GenerateManifest(): Primary entry point. Orchestrates the full pipeline from Git clone to manifest output.
  • Tool-specific generators: Each tool has dedicated functions for parameter handling, execution, and output parsing.
  • ListRefs(): Lists Git branches and tags for UI dropdowns.
  • ListApps(): Discovers applications in a repository (app-of-apps pattern).
  • ResolveRevision(): Resolves symbolic refs to commit SHAs.

Caching Layer

reposerver/cache/ - Multi-level cache:

Request → In-Memory Cache → Redis Cache → Generate → Store in both

Cache key composition includes:

  • Repository URL and resolved revision (commit SHA)
  • Path within the repository
  • Tool-specific parameters (Helm values, Kustomize options)
  • Tool version (Helm version, Kustomize version)
  • Server API versions (for Helm --api-versions)

Failure Backoff

The repo server implements smart failure handling to avoid repeatedly attempting expensive operations that are failing:

  • PauseGenerationAfterFailedGenerationAttempts: Number of failures before pausing
  • PauseGenerationOnFailureForMinutes: Time-based cooldown after repeated failures
  • PauseGenerationOnFailureForRequests: Request-based throttling after failures

This prevents a broken Git repo or misconfigured Helm chart from consuming all repo server capacity.

Architecture Diagram

graph TD
    subgraph "Repo Server Pod"
        GRPC[gRPC Server<br/>reposerver/server.go]
        Svc[Repository Service<br/>reposerver/repository/]
        MemCache[In-Memory Cache]
        Semaphore[Parallelism Semaphore]

        subgraph "Tool Adapters"
            HelmGen[Helm Generator<br/>helm template]
            KustGen[Kustomize Generator<br/>kustomize build]
            JsonGen[Jsonnet Generator<br/>jsonnet eval]
            DirGen[Directory Reader<br/>YAML/JSON files]
        end
    end

    subgraph "External Systems"
        AC[Application Controller<br/>gRPC client]
        Redis[Redis<br/>Distributed cache]
        Git[Git Repositories<br/>GitHub, GitLab, etc.]
        HelmRepo[Helm Repositories<br/>OCI / HTTP]
        CMP[CMP Sidecar<br/>Custom plugins]
    end

    AC -->|GenerateManifest| GRPC
    GRPC --> Svc
    Svc --> MemCache
    Svc --> Redis
    Svc --> Semaphore
    Semaphore --> HelmGen
    Semaphore --> KustGen
    Semaphore --> JsonGen
    Semaphore --> DirGen
    HelmGen --> Git
    HelmGen --> HelmRepo
    KustGen --> Git
    JsonGen --> Git
    DirGen --> Git
    Svc -->|Delegate| CMP

Git Operations Detail

The repo server manages a local checkout cache for Git repositories:

sequenceDiagram
    participant Svc as Repo Service
    participant Local as Local Git Cache
    participant Remote as Remote Git Repo

    Svc->>Local: Check for existing checkout
    alt Exists
        Svc->>Local: git fetch origin <revision>
        Local->>Remote: Fetch objects
        Remote-->>Local: Objects
    else New repo
        Svc->>Remote: git clone --depth 1
        Remote-->>Local: Shallow clone
    end
    Svc->>Local: git checkout <revision>
    Local-->>Svc: Working directory ready
    Svc->>Svc: Run tool (helm/kustomize/etc.)

Authentication: Supports HTTPS (username/password, token), SSH (key-based), and GitHub App credentials. Credentials are stored as Kubernetes Secrets and managed via the API Server. The repo server reads them from the ArgoCD database (util/db/).

Helm Generation Detail

For Helm-based applications, the repo server performs:

  1. Chart resolution: Locates Chart.yaml in the specified path, or fetches from a Helm repository/OCI registry
  2. Dependency update: Runs helm dependency build if Chart.lock exists
  3. Template rendering: Executes helm template with:
    • Values files (specified in Application source)
    • Parameter overrides (--set equivalents)
    • --api-versions from the target cluster capabilities
    • --kube-version from the target cluster version
    • Release name and namespace
  4. Post-processing: Parses the YAML output into individual resource manifests

Configuration

FlagDefaultDescription
--parallelism-limit0 (unlimited)Max concurrent manifest generations
--max-combined-directory-manifests-size10MBTotal size limit for directory manifests
--helm-manifest-max-extracted-size1GBMax Helm template output size
--oci-manifest-max-extracted-size1GBMax OCI artifact extraction size
--disable-tlsfalseDisable TLS for gRPC (use with sidecar TLS)
--repo-cache-expiration24hGit repo cache expiration time
--redisargocd-redis:6379Redis address for distributed cache
--otlp-address(empty)OpenTelemetry collector for tracing

Key Design Decisions

  • Stateless design: Each repo server instance is fully stateless (cache is in Redis). Enables simple horizontal scaling by adding replicas. Local Git checkouts are ephemeral and rebuilt on cache miss.
  • Multi-level caching: In-memory cache for hot paths (same revision accessed repeatedly within seconds), Redis for distributed cache (shared across replicas, survives pod restarts). Composite cache key ensures deterministic results.
  • Semaphore-based concurrency: Rather than unbounded goroutines, uses a semaphore to limit concurrent generations. Prevents CPU/memory exhaustion during burst loads (e.g., mass re-sync after cache flush).
  • Failure backoff: Smart backoff on repeated failures prevents a single broken repo from consuming all capacity. Exponential backoff with configurable thresholds.
  • CMP sidecar isolation: Custom manifest generation plugins run in separate sidecar containers, preventing untrusted code from accessing repo server credentials or memory. Communication via Unix domain socket or gRPC.
  • Shallow clones: Uses --depth 1 for Git clones to minimize bandwidth and disk usage. Full history is only needed for specific operations (e.g., listing all revisions).