PlatformEngr® Argo CD course

Module 01 · Foundations · 45 min · You are: Platform team

Install Argo CD the reviewable way

In this module

  • You learn: How Argo CD is installed and configured from a file in Git, and what it adds to a Kubernetes cluster (new object types and a few controllers).
  • You do: Create the platform repo and a local cluster, write Argo CD's settings in values.yaml, install Argo CD with Helm, then log in to the UI and the CLI.
  • You end with: A running cluster with Argo CD installed from your values file, a platform repo with that file committed, and you logged in as admin in both the UI and the CLI. No applications yet.

Most Argo CD installs start with kubectl apply -f install.yaml from the internet and a handful of later edits nobody remembers. Start the way you mean to go on: a pinned chart version, your settings in a file in Git, and nothing changed by hand. Later, Argo CD takes over its own installation from that same file.

Open this module in the interactive course to track progress and switch tracks.

Concepts

The components
argocd-server (UI and API), argocd-repo-server (clones Git, renders Helm and Kustomize), argocd-application-controller (compares and syncs), Redis (cache), plus the ApplicationSet and notifications controllers.
CRDs
Application (what to deploy from where to where), AppProject (the fence around Applications), ApplicationSet (generates Applications: Fleet GitOps territory).
Pinned chart, values in Git
The chart version is part of the install command and later of a manifest. Your settings live in argocd/values.yaml, reviewed like code.
The admin account
The install creates admin with a random password in a Secret. Fine to get started; not how a team should log in.

Files to know

Open them in your editor or on GitHub; the bullets say what to look at.

Steps

1. Create the platform repo

This is the platform team's repo. Public, so Argo CD can read it without credentials.

cd ~/work && gh repo create YOUR_GITHUB_USER/argocd-platform --public --clone

Go into it and make the three folders this repo uses: argocd (Argo CD's own settings), apps (Application files) and bootstrap (the one file applied by hand later).

cd ~/work/argocd-platform && git switch -C main && mkdir -p argocd apps bootstrap

2. Create the cluster

kind create cluster --config ~/work/argocd-gitops/cluster/kind.yaml

When it finishes, check that kubectl talks to the new cluster:

kubectl cluster-info --context kind-argocd
kubectl get nodes
On an existing cluster
kubectl config use-context YOUR_CONTEXT
kubectl get nodes

3. Write the values file and commit it first

This file is Argo CD's settings, written down so they can be reviewed like code. Open it in your editor (VS Code, vim, nano, anything) and type or paste it in. It holds three settings, each with a comment saying why. This first commit goes straight to main.

Create ~/work/argocd-platform/argocd/values.yaml

# Argo CD Helm values: the platform team's configuration of Argo CD itself.
# Every change here is a commit, reviewed like code.
global:
  domain: argocd.localtest.me

configs:
  cm:
    # Check Git every minute instead of every two: faster feedback on a laptop.
    timeout.reconciliation: 60s

# No SSO on a laptop. In production, configure OIDC or Dex here.
dex:
  enabled: false

Save it in Git, so the install in the next step reads a file that is already committed:

cd ~/work/argocd-platform && git add -A && git commit -qm "Argo CD values" && git push -qu origin main

4. Install Argo CD with Helm, pinned

Helm is a package manager for Kubernetes: a chart is a package of manifests, and your values.yaml is the settings you hand to it. Chart 10.10.5 on purpose: not the latest, so you can practise an upgrade later.

First tell Helm where the Argo CD chart lives:

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

The install. This is the command that puts Argo CD in your cluster: this chart, this version, your values file. --wait makes it return only when every pod is ready (about a minute).

helm install argocd argo/argo-cd --version 10.10.5 \
  --namespace argocd --create-namespace -f ~/work/argocd-platform/argocd/values.yaml --wait

Every pod should be Running, with 1/1 or 2/2 under READY:

kubectl -n argocd get pods

5. See what you just installed

Argo CD is not a separate server next to Kubernetes: it is a few controllers inside your cluster, plus new object types. Three short checks show what that means.

1. New object types. Argo CD adds CRDs to the Kubernetes API, so an Application is a Kubernetes object: you write it in YAML and keep it in Git. Expect three lines: applications, applicationsets and appprojects.

kubectl get crd | grep argoproj.io

2. The parts that do the work. Each name matches a card in Key ideas above. When Argo CD misbehaves, this is the first list to look at. All should show 1/1.

kubectl -n argocd get deployments,statefulsets

3. Your file became the configuration. Your values file set timeout.reconciliation: 60s. The chart rendered it into the argocd-cm ConfigMap, which is where Argo CD reads its settings. Expect 60s.

kubectl -n argocd get configmap argocd-cm -o jsonpath='{.data.timeout\.reconciliation}'; echo

6. Open the UI

The UI is served by argocd-server, which has no address outside the cluster, so you reach it with a port-forward.

Warning. The port-forward is required, and it must stay running. The UI and the argocd CLI both reach Argo CD only through it. Every later module assumes your cluster is up and this port-forward is running in its own terminal (until module 06 replaces it with an ingress). If it stops, the UI will not load and argocd commands fail with connection refused: start it again.

1. Get the admin password. The install created a user called admin and stored a random password in a Secret. This prints it. Copy it: you need it in step 4.

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

2. Forward a local port to the server. Run this in a new terminal and leave it running: it prints Forwarding from 127.0.0.1:8080 and then waits. Closing it, or pressing Ctrl+C, closes the UI and breaks the argocd CLI too. Keep this terminal open for the rest of the course, and start it again whenever you come back to a fresh session or the cluster has been restarted.

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

3. Get past the browser warning. Open https://localhost:8080. Your browser shows Your connection is not private (NET::ERR_CERT_AUTHORITY_INVALID). That is expected: Argo CD created its own certificate when it was installed, and no certificate authority your computer trusts has signed it, so the browser cannot prove who is answering. Here it is safe to continue, because the connection only goes from your browser, through kubectl on your own machine, to your own cluster. Chrome and Edge: Advanced, then Proceed to localhost (unsafe). Firefox: Advanced, then Accept the Risk and Continue. Safari: Show Details, then visit this website. Never click through this warning for a site on the internet.

4. Sign in with username admin and the password from step 1. You land on the empty Applications page.

7. Find four things in the UI

Find each item and check you see what is described.

1. The New App button. On the Applications page, find + New App. It creates an Application by hand, and nothing about it ends up in Git. Do not use it: in this course you change things through Git and use the UI to watch.

2. The cluster. Open Settings (the gear in the left sidebar), then Clusters. You see one cluster, in-cluster, with the URL https://kubernetes.default.svc: the cluster Argo CD itself runs in. Its connection status probably says Unknown: Argo CD only connects to a cluster once an Application uses it.

3. The default project. Settings, then Projects, then default. Source repositories and Destinations are both *: any repo may deploy anything to any namespace.

4. Who you are. Click User Info in the left sidebar: you are admin, one shared account that can do everything.

8. Find the same things with the CLI

The CLI talks to the same API as the UI. Run these in your first terminal, while the port-forward keeps running in the other. Without the port-forward, every argocd command fails.

Log in with the same admin account and password. The login lasts 24 hours: when a later command says Unauthenticated, run this command again (the yellow box on each module repeats it):

argocd login localhost:8080 --insecure --username admin --password "$(kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath='{.data.password}' | base64 -d)"

The cluster from item 2: same name, same URL.

argocd cluster list

The project from item 3: * after Repositories and Destinations.

argocd proj get default

Simplified for the course

You install with helm install once, by hand. In module 04 Argo CD takes over its own installation from the same values file, and helm is never used against this release again.

Break it on purpose: Change Argo CD by hand, then upgrade

During an incident someone slows Argo CD down by editing its ConfigMap with kubectl. Nobody writes it down. Weeks later, the platform team runs a routine helm upgrade.

You practise: reading a server-side apply conflict, finding where a setting really lives, and making Git its only owner.

1. Break it

The incident fix: set the reconciliation timeout to 300 seconds by hand.

kubectl -n argocd patch configmap argocd-cm --type merge -p '{"data":{"timeout.reconciliation":"300s"}}'

Check that it took effect. Expect 300s:

kubectl -n argocd get configmap argocd-cm -o jsonpath='{.data.timeout\.reconciliation}'; echo

Weeks later, the routine upgrade:

helm upgrade argocd argo/argo-cd --version 10.10.5 -n argocd -f ~/work/argocd-platform/argocd/values.yaml --wait

2. What you see

Expected: a routine upgrade that just works. You get: UPGRADE FAILED: conflict occurred while applying object argocd/argocd-cm ... conflict with "kubectl-patch" using v1: .data.timeout.reconciliation.

Helm 4 applies changes server-side, and Kubernetes records which tool last set each field (its field manager). Your values file says 60s, but the field now belongs to kubectl-patch with 300s, so Kubernetes refuses to overwrite it silently. See it yourself: kubectl -n argocd get configmap argocd-cm --show-managed-fields -o yaml | grep -B3 -A5 kubectl-patch.

3. Fix it yourself

The incident fix is still wanted: keep 300s, and get the upgrade through with the value coming from Git. Then put it back to 60s through Git, and finish with a plain helm upgrade (no extra flags) that succeeds: proof that Git is now the only owner.

Hint 1

Which value should win, and where should it live? Once Git says what you want, there is nothing to argue about: an apply that sets the same value does not conflict.

Hint 2

Changing the field to a different value still conflicts while kubectl-patch co-owns it. helm upgrade --force-conflicts tells Kubernetes that Helm takes the field over. Use it only after Git holds the value you want.

The fix

Put the incident value in Git. The upgrade now applies the same value as the hand edit, so there is no conflict:

Change in ~/work/argocd-platform/argocd/values.yaml

-     timeout.reconciliation: 60s
+     timeout.reconciliation: 300s
cd ~/work/argocd-platform && git commit -qam "Argo CD: reconcile every 5 minutes (incident)" && git push -q
helm upgrade argocd argo/argo-cd --version 10.10.5 -n argocd -f argocd/values.yaml --wait

Incident over: back to 60 seconds in Git. kubectl-patch still co-owns the field, so this one upgrade takes it over with --force-conflicts:

Change in ~/work/argocd-platform/argocd/values.yaml

-     timeout.reconciliation: 300s
+     timeout.reconciliation: 60s
git commit -qam "Argo CD: reconcile every minute" && git push -q
helm upgrade argocd argo/argo-cd --version 10.10.5 -n argocd -f argocd/values.yaml --wait --force-conflicts

Expect 60s:

kubectl -n argocd get configmap argocd-cm -o jsonpath='{.data.timeout\.reconciliation}'; echo

The proof: a plain upgrade succeeds, because only Helm owns the field now.

helm upgrade argocd argo/argo-cd --version 10.10.5 -n argocd -f argocd/values.yaml --wait
After you fixed it: the five questions
What failed?
A configuration change made outside Git blocked the next upgrade. (With client-side apply, Helm 3 for example, it is worse: the upgrade succeeds and silently puts back the old value.)
How was it detected?
The upgrade failed with a server-side apply conflict that named the field and the tool that changed it (kubectl-patch).
Who responds?
The platform team.
How is it corrected?
Decide the value, put it in argocd/values.yaml, commit, and upgrade; take the field over with --force-conflicts once Git holds the value you want.
How is it prevented?
Make the values file the only way to change Argo CD: once Argo CD manages itself from it with self-heal, a manual edit is reverted in seconds.

Quiz

  1. Which component clones Git and renders Helm charts?
    • argocd-repo-server
    • argocd-server, which serves the UI and API and also fetches and renders every chart
    • argocd-application-controller, which pulls Git, runs helm template and then compares the result
  2. Why install chart 10.10.5 instead of "latest"?
    • "latest" is not a real chart version, so Helm refuses to install it and a number has to be typed in
    • An install you can repeat and review: the version is in Git, and upgrades are deliberate changes
    • A pinned older version is always lighter and faster, and newer releases are slower to start up
  3. Where does the admin password come from?
    • You set it yourself in values.yaml before the install, and Helm stores exactly that password in the cluster
    • The password is always the literal word "admin" until you change it in the Argo CD settings page
    • The install generates it into the argocd-initial-admin-secret Secret
Answers
  1. argocd-repo-server The repo-server renders; the application controller compares and syncs; the server serves UI and API.
  2. An install you can repeat and review: the version is in Git, and upgrades are deliberate changes Pinned versions make installs reproducible and upgrades reviewable.
  3. The install generates it into the argocd-initial-admin-secret Secret Use it to bootstrap, then replace it with personal accounts or SSO (module 06).

Field note

The first question in every audit I have done: "show me how Argo CD itself is configured". The teams with a values file in Git answered in one minute. The others needed a week of kubectl get configmap.

Report a problem with this module