Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Chapter 3: Installing ArgoCD

Like many GitOps solutions, Argo CD serves various users with distinct business goals. Because requirements vary so widely, the platform offers several installation configurations. Choosing the right one depends on five key factors:

  • User Base: Who are the primary users and consumers?
  • Management Scope: What specific infrastructure or applications will Argo CD oversee?
  • Availability: Is high availability (HA) a critical requirement for your operations?
  • Security: What are the mandatory security and compliance standards?
  • Automation: What are your specific needs for bootstrapping and automated workflows?

ArgoCD offers two main installation types depending on your use case:

argocd_installation_types

Core Installation

This is a minimal, lightweight installation intended for users who only need the core GitOps sync functionality without the full ArgoCD UI or API server.

argocd_core_installation Image source: Official ArgoCD Docs Website

Key characteristics:

  • Installs only the essential components: the application controller, repo server, and ApplicationSet controller
  • No API server, no UI, no Dex (authentication server), a minimal version of Redis
  • Intended for cluster admins managing their own cluster, not for multi-tenant or team-shared setups
  • Interaction happens via the argocd CLI (using argocd admin commands) or kubectl directly — not through the web UI
  • Lower resource footprint, simpler attack surface

Best for: Single-tenant, admin-only usage where you want ArgoCD purely as a sync engine with no web interface.

Default (Full) Installation

This is the standard, full-featured installation most teams use. It includes everything needed to operate ArgoCD as a shared platform.

Image source: Official ArgoCD Docs Website

Key characteristics:

  • Installs all components: API server, UI, repo server, application controller, ApplicationSet controller, Dex (SSO), Redis (for caching)
  • Exposes the web dashboard and the full REST/gRPC API
  • Supports multi-tenancy — multiple teams or users can log in, manage projects, and interact with their own apps
  • Supports SSO via Dex (integration with GitHub, LDAP, OIDC providers, etc.)
  • Higher resource usage, but far richer feature set

Best for: Teams and organizations that want a shared GitOps platform with a UI, RBAC, SSO, and API access.

Use Core if you want a lean sync engine you manage via CLI, and Default if you want the full ArgoCD experience with a UI and team collaboration features.

ArgoCD Operating Modes

Cluster-Scoped Mode (Internal & External Clusters)

This is the default operating mode when ArgoCD is installed with cluster-wide permissions.

Internal Cluster:
ArgoCD can deploy to the same cluster it runs in. This cluster is registered automatically and is referred to as https://kubernetes.default.svc — the in-cluster API server address. No extra registration is needed; it’s available out of the box.

External Clusters:
ArgoCD can also manage remote Kubernetes clusters outside of where it’s installed. These are registered explicitly using:

argocd cluster add <context-name>

This creates a ServiceAccount with the necessary permissions in the target cluster and stores the credentials as a Secret in ArgoCD’s namespace.

argocd_cluster_scope_mode

Key characteristics:

  • ArgoCD has cluster-admin level permissions (via ClusterRole)
  • It can manage resources across all namespaces of any registered cluster
  • One ArgoCD instance can act as a central control plane managing dozens of clusters
  • Suitable for platform/ops teams managing infrastructure at scale

Namespaced Mode

This is a restricted operating mode where ArgoCD’s permissions are limited to a specific namespace rather than the entire cluster.

argocd_ns_scope

Key characteristics:

  • ArgoCD only gets Role (not ClusterRole) — scoped to one namespace
  • It can only manage resources within its own namespace
  • Multiple ArgoCD instances can run side by side in the same cluster, each in its own namespace, without interfering with each other
  • Each team or tenant can have their own isolated ArgoCD instance
  • Cannot register or manage external clusters (no cluster-level secret access)

Installed using:

kubectl apply -n my-namespace -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/namespace-install.yaml

For more information, see github.com/argoproj/argo-cd/tree/master/manifests

Quick Comparison

FeatureCluster-ScopedNamespaced
Permission scopeCluster-wide (ClusterRole)Single namespace (Role)
Manages external clusters
Manages in-cluster✅ (all namespaces)✅ (own namespace only)
Multi-tenancy isolationLimitedStrong
Multiple instances per clusterNot typical✅ Common pattern
Best forCentral platform teamsPer-team isolated deployments

Use Cluster-Scoped mode when you need a centralized ArgoCD managing many clusters, and Namespaced mode when you want strong isolation between teams sharing a single cluster.

Creating Kubernetes Cluster

💡 PRACTICE
To access code files go to Chapter 2

For our examples we will use kind tool to create Kubernetes cluster.

To create a specific multi-node configuration in Kind, you need to move beyond simple CLI flags and use a YAML configuration file.

By default, Kind creates a single-node cluster. For our setup we will use your 1 Control Plane (Master) and 3 Worker nodes:

Create the kind Configuration File

Create a file named kind-config.yaml. This file defines the topology of your cluster.

kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
  # The one master node (control-plane)
  - role: control-plane
  # The three worker nodes
  - role: worker
  - role: worker
  - role: worker

Create the Named Cluster

Run the following command to spin up the cluster. The --name flag allows you to give it a custom identifier (e.g., my-custom-cluster), and the --config flag points to the YAML file you just created.

kind create cluster --name my-custom-cluster --config kind-config.yaml

Verify the Nodes

Once the process finishes, verify that all four nodes (1 control-plane + 3 workers) are up and running:

kubectl get nodes

Expected Output:

NAME                                STATUS   ROLES           AGE   VERSION
my-custom-cluster-control-plane     Ready    control-plane   1m    v1.35.0
my-custom-cluster-worker            Ready    <none>          1m    v1.35.0
my-custom-cluster-worker2           Ready    <none>          1m    v1.35.0
my-custom-cluster-worker3           Ready    <none>          1m    v1.35.0

Tips for Multi-Node Kind Clusters

  • Resource Usage: Remember that each “node” is actually a Docker container. Running four nodes will consume significantly more RAM and CPU than a single-node setup. Ensure your Docker Desktop or Docker Engine has at least 8GB of RAM allocated.
  • Context Switching: If you have multiple Kind clusters, you can switch between them using: kubectl config use-context kind-my-custom-cluster
  • Deleting the Cluster: When you’re done, clean up everything with: kind delete cluster --name my-custom-cluster

Installing ArgoCD via Helm

To install Argo CD via Helm, you will use the official community-maintained repository. Helm is the preferred method for many because it makes managing updates and customizing configurations (like cluster-scoped vs. namespace-scoped) much easier than raw manifests.

Add the Argo Helm Repository

First, add the repository to your local Helm client and update it to ensure you have the latest chart versions.

helm repo add argo https://argoproj.github.io/argo-helm
helm repo update

Configure for Cluster-Scoped Mode (Default)

By default, the Argo CD Helm chart installs in cluster-scoped mode. This means the Argo CD controller has a ClusterRole and can manage resources across the entire cluster.

If you want to verify or customize settings, you can create a values.yaml file, but for a standard installation, the default values are sufficient.

Install the Chart

Create the namespace and install the chart. We will name the release argocd.

# Create the namespace
kubectl create namespace argocd

# Install the chart
helm install argocd argo/argo-cd --namespace argocd

You should see output similar to this:

NAME: argocd
LAST DEPLOYED: Thu May 14 21:03:57 2026
NAMESPACE: argocd
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
In order to access the server UI you have the following options:

1. kubectl port-forward service/argocd-server -n argocd 8080:443

    and then open the browser on http://localhost:8080 and accept the certificate

2. enable ingress in the values file `server.ingress.enabled` and either
      - Add the annotation for ssl passthrough: https://argo-cd.readthedocs.io/en/stable/operator-manual/ingress/#option-1-ssl-passthrough
      - Set the `configs.params."server.insecure"` in the values file and terminate SSL at your ingress: https://argo-cd.readthedocs.io/en/stable/operator-manual/ingress/#option-2-multiple-ingress-objects-and-hosts


After reaching the UI the first time you can login with username: admin and the random password generated during the installation. You can find the password by running:

kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d

(You should delete the initial secret afterwards as suggested by the Getting Started Guide: https://argo-cd.readthedocs.io/en/stable/getting_started/#4-login-using-the-cli)

As output suggests don’t forget to delete the initial secret afterwards. For more information, see Getting Started Guide.

With kubectl get po -n argocd you can verify that all ArgoCD components are running as pods in argocd namespace:

NAME                                                READY   STATUS    RESTARTS   AGE
argocd-application-controller-0                     1/1     Running   0          20m
argocd-applicationset-controller-8466bbdf48-gx7sw   1/1     Running   0          20m
argocd-dex-server-5b97f65bfd-rsrkw                  1/1     Running   0          20m
argocd-notifications-controller-68767c8f58-shngh    1/1     Running   0          20m
argocd-redis-75fb94c8-44xg8                         1/1     Running   0          20m
argocd-repo-server-6c684bd96b-vwfl2                 1/1     Running   0          20m
argocd-server-599cd4fb9c-tpnrd                      1/1     Running   0          20m

As you can see all ArgoCD internal components for a full installation type are running in pods.

When you install Argo CD in this mode, the Helm chart sets up several components that interact to sync your Git repository to your Kubernetes cluster.

Common Helm Customizations

If you want to modify the installation during the helm install command, you can use the --set flag. Here are a few common examples:

  • To enable the Ingress (if you have an ingress controller):
--set server.ingress.enabled=true

or enable ingress in the values file server.ingress.enabled and either:

  • To change the service type to LoadBalancer:
--set server.service.type=LoadBalancer
  • To disable the initial admin password secret (not recommended for production):
--set configs.secret.createSecret=false

Using Custom Helm Values File

To see the available configuration options for the Argo CD Helm chart, you have two primary methods.

Method 1: The Helm CLI

You can extract the default values.yaml directly from the repository you added earlier without downloading the whole chart package.

helm show values argo/argo-cd > argocd-values.yaml

This command takes the default values, redirects them into a file named argocd-values.yaml, and saves it in your current directory.

Method 2: GitHub

If you prefer a searchable web interface with syntax highlighting, you can view the values.yaml file directly in the official argo-helm repository:

What to Look For in the File

The values.yaml for Argo CD is quite large (often over 2,000 lines) because it is highly configurable. Here are the key sections you might want to inspect:

  • global: Settings that apply to all components, like image registry mirrors or global labels.
  • server: Configuration for the UI and API, including ingress, service type, and RBAC.
  • controller: Settings for the application-controller (the “brain” that syncs your apps).
  • repoServer: Configuration for the component that handles Git cloning and manifest generation.
  • configs: Where you define things like cm (ConfigMaps) for custom styles or params for system-wide behavior.

How to Use the File

Once you’ve identified a setting you want to change (for example, enabling the ingress), you don’t need to keep the entire 2,000-line file. It is best practice to create a “thin” values file:

  1. Create a new custom file called e.g.my-values.yaml.
  2. Add only the specific keys you want to override:
server:
  service:
    type: LoadBalancer
  1. Apply it during your installation or upgrade:
helm upgrade --install argocd argo/argo-cd -n argocd -f my-values.yaml

Accessing the UI

Just like the manifest installation, you’ll need to retrieve the autogenerated password:

kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d; echo

Then, port-forward to access the dashboard:

kubectl port-forward service/argocd-server -n argocd 8080:443

Default username is admin.

⚠️ NOTE
For production environment use Ingress with custom domain for ArgoCD UI Dashboard.
For more information, see Ingress Configuration.

How to Upgrade

One of the biggest advantages of using Helm is the ease of upgrading to newer versions of Argo CD:

helm repo update
helm upgrade argocd argo/argo-cd --namespace argocd

Note: Since we are using a Kind cluster with multiple nodes, Argo CD will treat all those nodes as part of the “in-cluster” destination (https://kubernetes.default.svc), allowing to deploy applications to any of those worker nodes easily.

Provision ArgoCD UI Dasboard with Ingress

⚠️ IMPORTANT
Please be aware that for demo purposes and simplicity we are using Nginx Ingress Controller that was archived and deprecated by Kubernetes Community.

For production use-cases consider using other Ingress Controllers or Gateway API.

If you already have a cluster running, you will need to recreate it. We must add extraPortMappings to pass traffic from your real machine into the Docker container running the control plane, and label it as ingress-ready.

Save this file as kind-ingress-config.yaml:

kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
  - role: control-plane
    kubeadmConfigPatches:
      - |
        kind: InitConfiguration
        nodeRegistration:
          kubeletExtraArgs:
            node-labels: "ingress-ready=true"
    extraPortMappings:
      - containerPort: 80
        hostPort: 80
        protocol: TCP
      - containerPort: 443
        hostPort: 443
        protocol: TCP
  # Adding worker nodes
  - role: worker
  - role: worker
  - role: worker

Spin up the cluster using this config:

kind create cluster --name argo-project --config kind-ingress-config.yaml

If you need to delete cluster:

kind delete cluster --name argo-project

Deploy the NGINX Ingress Controller

The standard NGINX Ingress manifest needs slight tweaks to run properly inside Kind (such as utilizing the host ports we just mapped and scheduling onto our labeled control-plane node).

The Kubernetes team maintains a dedicated manifest specifically for Kind. Run this command to deploy it:

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml

⚠️ IMPORTANT
The latest nginx ingress controller kind manifest no longer enforces the nodeSelector for ingress-ready=true, so it is required explicitly patch Nginx Ingress deployment. However, old releases has that support as in here.

Without that, the pod lands on a worker node which has no host port mappings, so port 80 never gets traffic

Patch the deployment to make Ingress controller pods run on the control-plane node:

kubectl patch deployment ingress-nginx-controller -n ingress-nginx --type=json \
  -p='[{"op":"add","path":"/spec/template/spec/nodeSelector","value":{"ingress-ready":"true"}}]'

Wait until ready:

kubectl wait --namespace ingress-nginx \
  --for=condition=ready pod \
  --selector=app.kubernetes.io/component=controller \
  --timeout=90s

You should see output similar to this:

pod/ingress-nginx-controller-56dc4b4c6-wmlm6 condition met

Testing With Local Domain

For local testing, you don’t need to buy a real domain name or modify your DNS records on the internet. Instead, you can use a local hosts file override.

This method tells your operating system that a specific domain name lives at 127.0.0.1 (localhost) instead of looking it up on the internet.

  1. Pick a fake domain name for testing, such as argocd-dashboard.ui or my-app.test.
  2. Open your machine’s hosts file:
  • Linux / macOS: sudo vim /etc/hosts
  1. Add the following line at the bottom of the file:
127.0.0.1 argocd-dashboard.ui
  1. Save and close the file.

Now, you can update your Argo CD Ingress resource to use argocd-dashboard.ui as the host. When you type http://argocd-dashboard.ui into your browser, your computer will route the traffic straight into your Kind cluster.

How to Update your Ingress with the Test Domain

To apply this to your Argo CD Helm deployment, update your argocd-ingress-values.yaml file with your chosen testing domain:

global:
  domain: argocd-dashboard.ui

configs:
  params:
    server.insecure: true

server:
  ingress:
    enabled: true
    ingressClassName: nginx
    hostname: argocd-dashboard.ui
    annotations:
      nginx.ingress.kubernetes.io/force-ssl-redirect: "false"
  • global.domain — sets argocd.localhost as the base domain used by the chart
  • configs.params.server.insecure: true — runs ArgoCD server in HTTP mode, letting the ingress handle SSL termination
  • server.ingress.enabled: true — creates the Ingress resource
  • server.ingress.ingressClassName: nginx — targets the nginx ingress controller (standard for kind)
  • server.ingress.hostname: argocd.localhost — the hostname to access the UI

the annotation disables forced SSL redirect since we’re running insecure locally

Then upgrade the chart:

helm install argocd argo/argo-cd -n argocd -f argocd-ingress-values.yaml

Once applied, you can open your browser and navigate directly to your test domain http://argocd-dashboard.ui to access the Argo CD dashboard.

local_domain_argocd_ui

The whole flow of your traffic looks like this now:

References