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
adminin 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
adminwith 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.
cluster/kind.yaml(reference): The course cluster.platform/argocd/values.yaml(reference): Where you are heading: Argo CD configuration as code. Today you write the first lines.
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 installonce, by hand. In module 04 Argo CD takes over its own installation from the same values file, andhelmis 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-conflictsonce 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
- 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
- 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
- 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
- argocd-repo-server The repo-server renders; the application controller compares and syncs; the server serves UI and API.
- 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.
- 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.