GitOps with ArgoCD
Implement Continuous Deployment with ArgoCD
Learn how to deploy and manage applications using GitOps principles with ArgoCD.
What You’ll Learn
- Install ArgoCD on AWS EKS cluster
- Access and configure ArgoCD Web UI
- Deploy applications using GitOps from Git repository
- Create ArgoCD Applications for nginx and Todo App
- Monitor application sync status and health
- Understand GitOps workflow and benefits
Prerequisites
- AWS EKS cluster running (see Exercise 1)
- kubectl configured and connected to your cluster
- Git repository with Kubernetes manifests
- Basic understanding of Kubernetes resources
Verify prerequisites:
kubectl get nodes
kubectl version --clientUnderstanding GitOps and ArgoCD
What is GitOps?
GitOps is a way of managing Kubernetes deployments where:
- Git repository = Single source of truth
- Desired state = Manifests in Git
- Actual state = What’s running in cluster
- ArgoCD = Ensures desired state matches actual state
Traditional Deployment vs GitOps
Traditional (Push Model):
Developer β kubectl apply β ClusterProblems:
- No audit trail
- Manual process
- Hard to rollback
- Credentials needed
GitOps (Pull Model):
Developer β Git Push β ArgoCD detects change β Cluster syncs automaticallyBenefits:
- Full audit trail (Git history)
- Automated sync
- Easy rollback (Git revert)
- No cluster credentials needed for developers
How ArgoCD Works
ββββββββββββββββ
β Git Repo β β Developer pushes changes
β (manifests) β
ββββββββ¬ββββββββ
β
β (ArgoCD polls every 3 minutes)
ββββββββββββββββ
β ArgoCD β β Compares desired vs actual state
β Application β
ββββββββ¬ββββββββ
β
β (Auto-sync or manual sync)
ββββββββββββββββ
β Kubernetes β β Resources created/updated
β Cluster β
ββββββββββββββββStep 1: Install ArgoCD
1.1 Create ArgoCD Namespace
kubectl create namespace argocd1.2 Install ArgoCD
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yamlThis installs:
- ArgoCD API Server
- Repository Server (connects to Git)
- Application Controller (syncs resources)
- Redis (caching)
- Dex (SSO, optional)
- Web UI
Expected output:
customresourcedefinition.apiextensions.k8s.io/applications.argoproj.io created
customresourcedefinition.apiextensions.k8s.io/applicationsets.argoproj.io created
...
deployment.apps/argocd-server created1.3 Verify Installation
# Check all pods are running
kubectl get pods -n argocdExpected:
NAME READY STATUS RESTARTS AGE
argocd-application-controller-0 1/1 Running 0 2m
argocd-applicationset-controller-... 1/1 Running 0 2m
argocd-dex-server-... 1/1 Running 0 2m
argocd-notifications-controller-... 1/1 Running 0 2m
argocd-redis-... 1/1 Running 0 2m
argocd-repo-server-... 1/1 Running 0 2m
argocd-server-... 1/1 Running 0 2mWait for all pods to be ready (may take 2-3 minutes):
kubectl wait --for=condition=ready pod --all -n argocd --timeout=300sStep 2: Access ArgoCD Web UI
2.1 Expose ArgoCD Server
Option 1: Port Forward (Recommended for Testing)
kubectl port-forward svc/argocd-server -n argocd 8080:443Keep this terminal open. ArgoCD UI will be available at https://localhost:8080
Option 2: LoadBalancer (For Production)
kubectl patch svc argocd-server -n argocd -p '{"spec": {"type": "LoadBalancer"}}'Wait for external IP:
kubectl get svc argocd-server -n argocd -wGet the URL:
kubectl get svc argocd-server -n argocd -o jsonpath='{.status.loadBalancer.ingress[0].hostname}'2.2 Get Initial Admin Password
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d && echoCopy this password! You’ll need it to login.
Example output:
TkX9vR2zQ8yHn4Wp2.3 Login to ArgoCD Web UI
- Open browser to
https://localhost:8080(or LoadBalancer URL) - Accept the self-signed certificate warning
- Login:
- Username:
admin - Password: (from step 2.2)
- Username:
You should see the ArgoCD dashboard!
2.4 Change Admin Password (Recommended)
In the ArgoCD UI:
- Click User Info (top right)
- Click Update Password
- Enter current password and new password
- Click Save
Step 3: Understand the Git Repository Structure
3.1 Repository Overview
We’ll use: https://github.com/larsappel/ArgoCD.git
Repository structure:
ArgoCD/
βββ nginx/
β βββ nginx-deployment.yaml
β βββ nginx-service.yaml
β
βββ ToDoApp-K8S-Manifests/
βββ storageclass.yaml
βββ mongodb-statefulset.yaml
βββ mongodb-service.yaml
βββ mongo-init-job.yaml
βββ mongo-express-deployment.yaml
βββ mongo-express-service.yaml
βββ todo-configmap.yaml
βββ todo-deployment.yaml
βββ todo-service.yaml3.2 What Each Folder Contains
nginx/ - Simple nginx deployment for testing
- nginx-deployment.yaml: Nginx pods
- nginx-service.yaml: Nginx service
ToDoApp-K8S-Manifests/ - Complete Todo application
- Storage: StorageClass and StatefulSet for MongoDB
- Database: MongoDB with persistent storage
- Admin UI: Mongo Express for database inspection
- Application: Todo app with ConfigMap
Step 4: Deploy Nginx with ArgoCD (Web UI)
4.1 Create New Application
In the ArgoCD Web UI:
- Click + NEW APP (top left)
- Fill in the form:
GENERAL:
- Application Name:
nginx - Project Name:
default - Sync Policy:
Manual
SOURCE:
- Repository URL:
https://github.com/larsappel/ArgoCD.git - Revision:
HEAD - Path:
nginx
DESTINATION:
- Cluster URL:
https://kubernetes.default.svc(should be auto-filled) - Namespace:
default
- Click CREATE (top of page)
4.2 View Application Status
You should see the nginx app in the dashboard:
Status: OutOfSync - This means Git has resources that aren’t in the cluster yet
Click on the nginx application to see the details.
4.3 Sync the Application
Method 1: Manual Sync (Full Control)
- Click SYNC button (top right)
- Review the resources that will be created:
- Deployment: nginx
- Service: nginx-service
- Click SYNCHRONIZE
Expected: Status changes to:
- Syncing β Synced
- Health: Progressing β Healthy
4.4 Verify Deployment in Cluster
# Check pods
kubectl get pods -l app=nginx
# Check service
kubectl get svc nginx-serviceExpected:
NAME READY STATUS RESTARTS AGE
nginx-85b98978db-xxxxx 1/1 Running 0 1m
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx-service ClusterIP 10.100.x.x <none> 80/TCP 1m4.5 Explore Application in UI
In the ArgoCD UI:
Application View shows:
- Resource tree (Deployment β ReplicaSet β Pods)
- Sync status
- Health status
- Last sync time
Click on resources to see:
- Live manifest
- Desired manifest (from Git)
- Differences
- Events
- Logs (for pods)
Step 5: Deploy Todo App with ArgoCD (Web UI)
5.1 Create Todo App Application
In the ArgoCD Web UI:
- Click + NEW APP
- Fill in the form:
GENERAL:
- Application Name:
todo-app - Project Name:
default - Sync Policy:
Manual
SOURCE:
- Repository URL:
https://github.com/larsappel/ArgoCD.git - Revision:
HEAD - Path:
ToDoApp-K8S-Manifests
DESTINATION:
- Cluster URL:
https://kubernetes.default.svc - Namespace:
default
- Click CREATE
5.2 Review Resources Before Sync
- Click on the todo-app application
- Status shows OutOfSync
- You can see all resources that will be created:
- StorageClass: ebs-sc
- StatefulSet: mongodb
- Services: mongodb-service, todo-service, mongo-express-service
- Deployments: todo-deployment, mongo-express
- ConfigMap: todo-configmap
- Job: mongo-init-job
5.3 Sync the Todo App
- Click SYNC button
- Review all resources
- Click SYNCHRONIZE
ArgoCD will:
- Create StorageClass first
- Create MongoDB StatefulSet with PVC
- Wait for MongoDB to be ready
- Run mongo-init-job to seed database
- Deploy Todo app and Mongo Express
- Create services
5.4 Monitor Deployment Progress
Watch the application tree in real-time:
Initial state:
StorageClass: Synced, Healthy
StatefulSet: Syncing, Progressing
PVC: Syncing, PendingAfter ~2 minutes:
StorageClass: Synced, Healthy
StatefulSet: Synced, Healthy
PVC: Synced, Bound
Services: Synced, Healthy
Deployments: Synced, Healthy5.5 Verify in Cluster
# Check all resources
kubectl get all -l app=todo-webapp
# Check MongoDB
kubectl get statefulset mongodb
kubectl get pvc
# Check services
kubectl get svc | grep -E 'todo-service|mongo-express-service'5.6 Access the Todo Application
Get service endpoints:
# Todo App
kubectl get svc todo-service -o jsonpath='{.status.loadBalancer.ingress[0].hostname}'
# Mongo Express
kubectl get svc mongo-express-service -o jsonpath='{.status.loadBalancer.ingress[0].hostname}'If using LoadBalancer type, wait 2-3 minutes for AWS to provision the load balancers.
Access in browser:
http://<todo-service-url>
http://<mongo-express-service-url>Step 6: Enable Auto-Sync
6.1 Enable Auto-Sync for Nginx
- In ArgoCD UI, click on nginx application
- Click APP DETAILS (top left)
- Click ENABLE AUTO-SYNC
- Options:
- β Prune Resources (delete resources not in Git)
- β Self Heal (revert manual changes)
- Click OK
Now ArgoCD will automatically sync changes from Git every 3 minutes!
6.2 Test Auto-Sync
Make a change in Git (using GitHub web interface or locally):
- Go to:
https://github.com/larsappel/ArgoCD - Navigate to
nginx/nginx-deployment.yaml - Click Edit (pencil icon)
- Change replicas from
1to3:spec: replicas: 3 # Changed from 1 - Commit the change
Watch ArgoCD UI:
- Wait ~3 minutes (polling interval)
- Status changes to OutOfSync
- ArgoCD automatically syncs
- Status changes to Synced
- You now have 3 nginx pods!
Verify:
kubectl get pods -l app=nginxExpected: 3 nginx pods running
6.3 Test Self-Heal
Make a manual change to the cluster:
kubectl scale deployment nginx --replicas=5Watch ArgoCD UI:
- ArgoCD detects the drift
- Self-heal kicks in (~30 seconds)
- Reverts back to 3 replicas (desired state from Git)
This demonstrates GitOps: Git is the source of truth!
Step 7: Understanding Application Health
7.1 Health Status Types
ArgoCD shows different health statuses:
Healthy β
- Resource is running as expected
- Example: Deployment has desired replicas running
Progressing π
- Resource is being created or updated
- Example: Deployment rolling out new pods
Degraded β οΈ
- Resource exists but not fully functional
- Example: Some pods are crashing
Suspended βΈοΈ
- Resource is intentionally paused
- Example: CronJob is suspended
Missing β
- Resource should exist but doesn’t
- Example: Resource deleted manually
Unknown β
- ArgoCD can’t determine health
- Example: Custom resource without health check
7.2 Sync Status Types
Synced β
- Git state matches cluster state
- Everything is up to date
OutOfSync β οΈ
- Git state differs from cluster state
- Changes need to be applied
Unknown β
- ArgoCD can’t determine sync status
Step 8: Rollback Using GitOps
8.1 View Application History
- In ArgoCD UI, click on nginx application
- Click HISTORY AND ROLLBACK tab
- You see all sync operations with:
- Revision (Git commit SHA)
- Timestamp
- User/System who triggered sync
- Status
8.2 Rollback to Previous Version
Method 1: ArgoCD UI Rollback
- In HISTORY AND ROLLBACK tab
- Find the previous successful sync
- Click … (three dots)
- Click ROLLBACK
- Confirm
ArgoCD syncs to the previous Git commit!
Method 2: Git Revert (Preferred)
This is the true GitOps way:
# Clone the repo locally
git clone https://github.com/larsappel/ArgoCD.git
cd ArgoCD
# View history
git log --oneline nginx/
# Revert the last commit
git revert HEAD
# Push
git push origin mainArgoCD will detect the revert and sync automatically (if auto-sync enabled).
Step 9: Application Best Practices
9.1 Sync Policy Recommendations
Manual Sync:
- Use for: Production environments
- Why: Human approval before changes
- When: Critical applications
Auto-Sync:
- Use for: Development/staging environments
- Why: Fast feedback loop
- When: Non-critical applications
Auto-Sync with Prune:
- Use for: Fully GitOps-managed apps
- Why: Ensures Git is single source of truth
- Risk: Can delete resources not in Git
9.2 Repository Organization
Good structure:
repo/
βββ base/ # Shared resources
βββ overlays/
β βββ dev/ # Dev environment
β βββ staging/ # Staging environment
β βββ prod/ # Production environmentPer-app structure:
repo/
βββ app1/
β βββ manifests/
βββ app2/
β βββ manifests/9.3 Namespace Strategy
Option 1: App per namespace
DESTINATION:
Namespace: nginx-app
Namespace: todo-appOption 2: Environment per namespace
DESTINATION:
Namespace: dev
Namespace: prodStep 10: Monitoring and Troubleshooting
10.1 View Application Logs
In ArgoCD UI:
- Click on application
- Click on a Pod in the resource tree
- Click LOGS tab
- View real-time logs
10.2 View Events
In ArgoCD UI:
- Click on any resource
- Click EVENTS tab
- See Kubernetes events for that resource
10.3 Compare Live vs Desired State
In ArgoCD UI:
- Click on any resource
- Click DIFF tab
- See differences between:
- Desired: What’s in Git
- Live: What’s in cluster
Green: Git has it, cluster doesn’t Red: Cluster has it, Git doesn’t
10.4 Refresh vs Hard Refresh
Refresh:
- Compares Git and cluster state
- No changes to cluster
- Fast (uses cached data)
Hard Refresh:
- Re-fetches everything from cluster
- Clears cache
- Slow but accurate
Use Hard Refresh when:
- State seems incorrect
- Resources modified externally
- Debugging sync issues
Troubleshooting
Issue 1: Application Stuck in “Progressing”
Symptom: Application shows “Progressing” health for >5 minutes
Check:
In ArgoCD UI:
- Click on the resource showing “Progressing”
- Check EVENTS tab
- Check LOGS tab (if pod)
Common causes:
- Image pull errors
- Resource limits too low
- Missing dependencies (ConfigMap, Secret)
Fix:
# Describe the resource in kubectl
kubectl describe pod <pod-name>
# Check events
kubectl get events --sort-by='.lastTimestamp'Issue 2: “OutOfSync” But Already Synced
Symptom: Application shows OutOfSync immediately after sync
Cause: Resource has fields managed by Kubernetes controllers
Common culprits:
- Service with
clusterIPauto-assigned - StatefulSet with
volumeClaimTemplates - Deployment with resource defaults
Fix:
Add ignore differences in Application:
- Click APP DETAILS
- Scroll to SYNC POLICY
- Add IGNORE DIFFERENCE:
Group: "" Kind: Service JSONPointers: ["/spec/clusterIP"]
Issue 3: “Permission Denied” Errors
Symptom: ArgoCD can’t create resources
Check:
# Check ArgoCD controller logs
kubectl logs -n argocd deployment/argocd-application-controllerCommon causes:
- ArgoCD doesn’t have RBAC permissions for resource type
- Namespace doesn’t exist
- Resource requires cluster-admin
Fix:
Grant additional permissions to ArgoCD:
# Create ClusterRole and ClusterRoleBinding if neededIssue 4: “Repository Not Found”
Symptom: Application can’t connect to Git repository
Check:
- In ArgoCD UI: Settings β Repositories
- Check connection status
Common causes:
- Private repo without credentials
- Wrong URL
- Network issues
Fix:
For private repos, add credentials:
- Settings β Repositories
- Click CONNECT REPO
- Add SSH key or HTTPS credentials
Issue 5: Sync Takes Too Long
Symptom: Manual sync is very slow
Cause:
- Large number of resources
- Slow image pulls
- Resource dependencies
Check:
# Check sync operation status
kubectl get application nginx -n argocd -o yamlOptimization:
- Use sync waves (annotations) for ordering
- Split into multiple apps
- Pre-pull images
Cleanup
Remove Applications (Keeps Cluster Resources)
In ArgoCD UI:
- Click on application
- Click DELETE
- Uncheck “Cascade”
- Click OK
This removes app from ArgoCD but keeps resources in cluster.
Delete Applications (Removes Cluster Resources)
In ArgoCD UI:
- Click on application
- Click DELETE
- Check “Cascade” β
- Click OK
This removes app from ArgoCD AND deletes all resources from cluster.
Or via kubectl:
# Delete with cascade (removes cluster resources)
kubectl delete application nginx -n argocd
# Delete without cascade (keeps cluster resources)
kubectl delete application nginx -n argocd --cascade=falseUninstall ArgoCD
# Delete ArgoCD
kubectl delete -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
# Delete namespace
kubectl delete namespace argocdUnderstanding GitOps Benefits
Before GitOps (Manual kubectl)
Challenges:
- β No history of what was deployed
- β Hard to reproduce deployments
- β Manual process, error-prone
- β Need cluster credentials
- β No audit trail
- β Difficult rollbacks
After GitOps (ArgoCD)
Benefits:
- β Git history = deployment history
- β Reproducible deployments
- β Automated process
- β No cluster credentials for developers
- β Full audit trail (who changed what, when)
- β Easy rollbacks (git revert)
- β Drift detection and self-healing
- β Multi-cluster support
Real-World Workflow
Development:
1. Developer commits code
2. CI builds container image
3. CI updates manifest in Git (new image tag)
4. ArgoCD detects change
5. ArgoCD deploys to dev clusterPromotion to Production:
1. Merge dev branch to main
2. ArgoCD detects change in main
3. ArgoCD deploys to prod clusterRollback:
1. Issue detected in production
2. Git revert the problematic commit
3. Push to main
4. ArgoCD syncs previous version
5. Application restoredSummary
What you accomplished:
- β Installed ArgoCD on EKS cluster
- β Accessed ArgoCD Web UI
- β Created Applications from Git repository
- β Deployed nginx and Todo App using GitOps
- β Enabled auto-sync and self-healing
- β Tested GitOps workflow (commit β auto-deploy)
- β Monitored application health and sync status
- β Performed GitOps rollback
Key concepts learned:
- GitOps principles - Git as single source of truth
- Declarative deployments - Desired state in Git
- Continuous sync - ArgoCD keeps cluster in sync with Git
- Self-healing - Automatic revert of manual changes
- Audit trail - Git history tracks all changes
- Easy rollbacks - Git revert = instant rollback
Architecture you built:
Developer β Git Push β GitHub Repository
β
(ArgoCD polls)
β
ArgoCD Application
β
(Auto/Manual Sync)
β
βββββββββββββββββββββββββββββββββββββββββββ
β AWS EKS Cluster β
β βββ Nginx (nginx/) β
β βββ Todo App (ToDoApp-K8S-Manifests/) β
β βββ MongoDB StatefulSet β
β βββ Todo App Deployment β
β βββ Mongo Express β
βββββββββββββββββββββββββββββββββββββββββββNext Steps
Ready for more?
- Multiple environments - Create dev, staging, prod apps
- Application Sets - Manage multiple apps from one definition
- Helm charts - Use ArgoCD with Helm
- Sync waves - Control resource creation order
- SSO integration - Use corporate SSO (Okta, Google, etc.)
- Notifications - Slack/email alerts for sync events
- Progressive delivery - Canary and blue-green deployments
Congratulations! π
You now know how to:
- Implement GitOps with ArgoCD
- Manage Kubernetes applications declaratively
- Automate deployments from Git
- Monitor and troubleshoot applications
- Rollback using Git history
- Build production-ready CD pipelines
GitOps is the modern way to manage Kubernetes deployments!
Happy GitOps! π