Project 7: GitOps with ArgoCD¶
Pull-based GitOps: ArgoCD syncs the cluster from Git with self-healing, automated image tag updates, and zero manual kubectl commands. View source on GitHub
Project Overview¶
This project implements GitOps using ArgoCD — a pull-based continuous delivery tool that runs inside the Kubernetes cluster and continuously reconciles cluster state with a Git repository. Rather than a CI pipeline pushing changes into the cluster (Project 5's approach), ArgoCD watches Git and pulls changes into the cluster automatically.
The project deploys the flask-tasks app (Project 5) using the Helm chart from Project 6, with ArgoCD managing the full lifecycle for two environments: dev (manual sync) and prod (automated sync with self-healing).
Developer pushes code
|
| git push → main
v
+-----------------------------------------------+
| GitHub Actions: project5-ci-cd.yml |
| test → build → push image to GHCR |
| flask-tasks:sha-abc1234 |
+-----------------------------------------------+
|
| workflow_run: completed (success)
v
+-----------------------------------------------+
| GitHub Actions: project7-image-updater.yml |
| Updates flask-tasks-prod.yaml image.tag |
| git commit + git push → main |
+-----------------------------------------------+
|
| Git state changed (ArgoCD polls every 3 min)
v
+-----------------------------------------------+
| ArgoCD Controller (inside Minikube) |
| Detects changed Application manifest |
| Renders Project 6 Helm chart |
| Applies updated Deployment to cluster |
| selfHeal: reverts any manual kubectl edits |
+-----------------------------------------------+
|
+--> flask-tasks-dev (namespace: flask-tasks-dev)
| Manual sync, 1 replica, DEBUG logging
|
+--> flask-tasks-prod (namespace: flask-tasks-prod)
Auto-sync, 3 replicas, HPA, pinned image tag
Push-based vs Pull-based CD¶
| Project 5 (push-based) | Project 7 (pull-based / GitOps) | |
|---|---|---|
| Who initiates the deploy? | CI pipeline pushes to cluster | ArgoCD inside cluster pulls from Git |
| Cluster credentials location | Stored in GitHub Actions secrets | Never leave the cluster |
| Source of truth | CI script logic | Git repository |
| Self-healing | No — manual change persists | Yes — ArgoCD reverts drift |
| Audit trail | CI run logs | Git commit history |
| Deploy when CI is down | No | Yes — ArgoCD keeps reconciling |
Technology Stack¶
| Technology | Role |
|---|---|
| ArgoCD | GitOps controller — watches Git, syncs cluster |
| Kubernetes (Minikube) | Target cluster |
| Helm (via ArgoCD) | Chart rendering — consumes Project 6's chart |
| GitHub Actions | Image tag writeback — completes the automated loop |
| Git | Single source of truth for all desired cluster state |
Key Features¶
- Two
ApplicationCRDs: dev with manual sync, prod withautomatedsync andselfHeal: true - ArgoCD renders the Project 6 Helm chart directly — no duplicate manifests
- Inline
helm.valuesin each Application keeps this project self-contained (no files modified in Projects 5 or 6) project7-image-updater.ymlworkflow closes the GitOps loop: triggered by Project 5's pipeline completion, updates the prod image tag, commits back to Gitsedanchor comment ensures only the managed tag line is patched — safe and idempotentprune: trueremoves orphaned resources when they are deleted from Git- Self-healing demo: any
kubectledit to the prod namespace is reverted within ArgoCD's sync cycle
Codebase Overview¶
project7-gitops-argocd/
├── argocd/
│ └── apps/
│ ├── flask-tasks-dev.yaml # Application CRD: dev, manual sync, 1 replica
│ └── flask-tasks-prod.yaml # Application CRD: prod, auto-sync, HPA, managed image tag
└── README.md # This file
# Workflow at portfolio root (no Project 5/6 files are modified):
.github/workflows/
└── project7-image-updater.yml # Triggered on Project 5 completion; patches image tag and pushes
Quick Start¶
1. Prerequisites¶
2. Install ArgoCD¶
kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
# Wait for all pods to be ready
kubectl wait --for=condition=available deployment --all -n argocd --timeout=120s
3. Access the ArgoCD UI¶
# Port-forward the ArgoCD API server
kubectl port-forward svc/argocd-server -n argocd 8080:443
# Retrieve the initial admin password
kubectl get secret argocd-initial-admin-secret -n argocd \
-o jsonpath="{.data.password}" | base64 -d && echo
Open https://localhost:8080 — username admin, password from the command above.
4. Install the ArgoCD CLI (optional but recommended)¶
# Linux
curl -sSL -o argocd https://github.com/argoproj/argo-cd/releases/latest/download/argocd-linux-amd64
chmod +x argocd && sudo mv argocd /usr/local/bin/
argocd login localhost:8080 --insecure --username admin
5. Apply the Application manifests¶
kubectl apply -f argocd/apps/flask-tasks-dev.yaml
kubectl apply -f argocd/apps/flask-tasks-prod.yaml
Both Applications will appear in the ArgoCD UI immediately. Prod will begin syncing automatically; dev waits for a manual trigger.
6. Sync the dev Application manually¶
7. Verify deployments¶
# Check ArgoCD sync status
argocd app list
argocd app get flask-tasks-prod
# Check pods in each namespace
kubectl get pods -n flask-tasks-dev
kubectl get pods -n flask-tasks-prod
# Access the dev API
minikube service flask-tasks-dev -n flask-tasks-dev --url
Demonstrating Self-Healing¶
# Manually scale the prod deployment down to 1 replica
kubectl scale deployment flask-tasks-prod -n flask-tasks-prod --replicas=1
# Watch ArgoCD revert it back to 3 within the sync cycle
kubectl get pods -n flask-tasks-prod -w
# ArgoCD detects drift and re-applies the desired state from Git
argocd app get flask-tasks-prod # status will briefly show OutOfSync then Synced
The Automated GitOps Loop¶
Once both projects are set up, the full loop is automatic:
- Push any code change to
main - Project 5's pipeline runs: test → build → push
flask-tasks:sha-<commit>to GHCR - On success,
project7-image-updater.ymltriggers automatically viaworkflow_run - The updater patches
flask-tasks-prod.yamlwith the new tag and pushes tomain - ArgoCD detects the manifest change within its poll interval (default 3 minutes)
- ArgoCD renders the Helm chart with the new tag and rolls out the updated Deployment
- No manual
kubectlorhelm upgradecommands required
Useful ArgoCD CLI Commands¶
# List all applications and their sync status
argocd app list
# Get detailed status and health of an application
argocd app get flask-tasks-prod
# Manually trigger a sync
argocd app sync flask-tasks-dev
# View sync history
argocd app history flask-tasks-prod
# Roll back to a previous sync revision
argocd app rollback flask-tasks-prod <revision-number>
# Delete an application (leaves cluster resources in place by default)
argocd app delete flask-tasks-dev
Future Work¶
- Configure an ArgoCD webhook on the portfolio GitHub repo to eliminate the 3-minute poll delay
- Add an App of Apps pattern — a root Application that manages both flask-tasks Applications
- Use ArgoCD Image Updater as an alternative to the image-updater workflow
- Add ArgoCD notifications (Slack or email) on sync failure
- Restrict ArgoCD project permissions using AppProject to limit which repos and namespaces each app can target