Lab 14 — Install ArgoCD on kind, deploy the URL shortener via App-of-Apps, prove drift detection and git-push deploys
Lesson 14 · Cloud Infrastructure & DevOps · ~60 min
Prereqs
The L13 lab must be complete: the URL shortener with HPA, PDB, and blue/green is working on your kind cluster. For the GitOps loop you need to be able to push to a git remote — fork the course repo to your own GitHub account and edit repoURL: in the ArgoCD manifests to point at your fork before applying. You also need the argocd CLI:
brew install argocd # macOS
# or download from https://github.com/argoproj/argo-cd/releases/tag/v2.11.0
argocd version --client
Step 1 — Tear down the helm-installed app
We are about to install the same chart via ArgoCD. Starting clean shows the bootstrap order in the UI.
helm uninstall url-shortener -n url-shortener
kubectl delete namespace url-shortener
kubectl get ns url-shortener # should return NotFound
Step 2 — Install ArgoCD
kubectl create namespace argocd
kubectl apply -n argocd \
-f https://raw.githubusercontent.com/argoproj/argo-cd/v2.11.0/manifests/install.yaml
kubectl -n argocd rollout status deploy/argocd-server --timeout=5m
Expected output: deployment "argocd-server" successfully rolled out.
Step 3 — Get the admin password and open the UI
kubectl -n argocd port-forward svc/argocd-server 8080:443 &
kubectl -n argocd get secret argocd-initial-admin-secret \
-o jsonpath='{.data.password}' | base64 -d ; echo
Open https://localhost:8080 in your browser. Accept the self-signed cert. Log in as admin with the password above.
Step 4 — Edit repoURL in the ArgoCD manifests to your fork
Before applying, replace the <you> placeholder with your actual GitHub username across all manifests:
sed -i.bak 's|https://github.com/<you>/Claude_Lessons.git|https://github.com/YOURNAME/Claude_Lessons.git|g' \
cloud-devops/sample-app/argocd/*.yaml \
cloud-devops/sample-app/argocd/children/*.yaml
git diff
git add cloud-devops/sample-app/argocd/
git commit -m "lab(L14): point ArgoCD manifests at my fork"
git push origin main
Step 5 — Apply the App-of-Apps
kubectl apply -n argocd -f cloud-devops/sample-app/argocd/app-of-apps.yaml
In the UI: a single app-of-apps Application appears. Click it. Within a few seconds, child Applications appear in the list: cert-manager, ingress-nginx, kube-prometheus-stack, url-shortener. Watch the sync wave order — the wave −1 applications (cert-manager, ingress-nginx, kube-prometheus-stack) go Healthy before url-shortener (wave 0) starts syncing.
argocd login localhost:8080 --insecure
argocd app list
argocd app get url-shortener
Step 6 — Wait for everything Healthy
kubectl -n url-shortener rollout status deploy url-shortener-api-blue --timeout=10m
kubectl -n url-shortener get pods,svc,ingress,hpa,pdb
curl -sk https://localhost/
Confirm the same shape you had at the end of L13 — HPA present, PDB present, blue Deployment serving — just installed via ArgoCD instead of a manual helm upgrade.
Step 7 — Prove drift detection
Manually edit a Deployment outside of git:
kubectl -n url-shortener scale deploy url-shortener-api-blue --replicas=10
kubectl -n url-shortener get deploy url-shortener-api-blue
# DESIRED: 10 (for now)
Watch the UI: within ~3 minutes the url-shortener Application goes OutOfSync (yellow indicator). Then ArgoCD automatically reverts the change because automated.selfHeal: true is set. Confirm:
kubectl -n url-shortener get deploy url-shortener-api-blue
# DESIRED is back to 3 (or whatever values-prod.yaml says), not 10.
Now test the ignoreDifferences exception. Drive load against the API so the HPA scales it up:
# Drive load (adapt the host as needed)
for i in $(seq 1 200); do curl -sk https://localhost/s/any & done
kubectl -n url-shortener get hpa url-shortener-api --watch
The HPA scales replicas from 2 → N. Wait 3+ minutes. Confirm ArgoCD did not revert the replica count back to the git value — because /spec/replicas is in ignoreDifferences.
Step 8 — Deploy via git push
Edit cloud-devops/sample-app/helm/values-prod.yaml and change something visible, for example bump api.maxReplicas:
grep maxReplicas cloud-devops/sample-app/helm/values-prod.yaml
# Change the value, e.g. from 8 to 10
git add cloud-devops/sample-app/helm/values-prod.yaml
git commit -m "lab(L14): bump api maxReplicas to 10"
git push origin main
Within ~3 minutes ArgoCD detects the change in main, syncs, and updates the HPA. Watch the UI — url-shortener briefly goes OutOfSync then returns to Healthy. Confirm:
kubectl -n url-shortener get hpa url-shortener-api -o jsonpath='{.spec.maxReplicas}'
# 10
No kubectl edit. No helm upgrade. No SSH. Git push is the deploy.
Step 9 — Roll back via git revert
git revert HEAD --no-edit
git push origin main
ArgoCD picks up the revert commit and syncs. The HPA maxReplicas returns to its previous value. Confirm in the UI and via kubectl.
Step 10 — Optional: swap App-of-Apps for ApplicationSet
kubectl delete -n argocd -f cloud-devops/sample-app/argocd/app-of-apps.yaml
kubectl apply -n argocd -f cloud-devops/sample-app/argocd/appset-environments.yaml
argocd app list
Expect three Applications: url-shortener-dev, url-shortener-stage, url-shortener-prod. Each renders the same Helm chart with a different values file into a different namespace. If values-dev.yaml or values-stage.yaml do not exist yet, those Applications will be OutOfSync — create the missing files (or copy values.yaml) and push to fix.
Step 11 — Verify the full loop works end-to-end
- A git push to
mainthat edits a values file results in a sync within 3 min, no human action on the cluster. - HPA-driven replica changes are not reverted (the
ignoreDifferencesrule works). - The Grafana dashboard for the URL shortener still populates, served by the ArgoCD-managed
kube-prometheus-stack. - Rolling back is
git revert <sha> && git push. Verify by reverting yourmaxReplicasbump.
What you should leave with
A kind cluster fully managed by ArgoCD: every Helm chart deployed via an Application, sync waves bootstrap the dependencies in order, drift is auto-corrected within 3 minutes, deploys are git pushes. This is the production shape.
Course wrap-up
You have built a 14-lesson path-of-a-feature deployment stack — container, Dockerfile design, multi-service builds, CI, scanning and signing, push-to-deploy, VM hosting, Terraform, Kubernetes, Helm, Ingress and TLS, observability, autoscaling, GitOps. The URL shortener is small; the platform around it is full-shape. The next move is your app. Pick one. Run through the same stack. Operate it for 30 days. Then re-read your own observability dashboards and decide what to refactor.
Troubleshooting
- “ArgoCD UI stuck at ‘Loading’” → cert acceptance issue. Open in incognito or accept the self-signed cert in your browser settings.
- “Application stuck on
Progressing” → checkargocd app get <name>for the specific resource that is failing. Usually a CRD ordering issue → check sync-wave annotations on the failing child Application. - “App-of-Apps doesn’t pick up new children” → check
directory.recurse: trueinapp-of-apps.yamland confirm the new YAML is committed and pushed tomain. - “ArgoCD reverts my HPA changes” →
ignoreDifferencesfor/spec/replicasnot applied. Confirm withargocd app diff url-shortener; look for areplicasentry in the diff. - “Secrets show in
argocd app diff” → you committed plaintext secrets to git. Rotate the secrets, scrub the repo history, and install Sealed Secrets or external-secrets-operator (covered in homework).