ArgoCD â GitOps Deployment & Application Management Guide
In this tutorial, you'll learn about ArgoCD. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.
ArgoCD is a declarative, GitOps-driven continuous delivery tool for Kubernetes that automatically synchronizes cluster state with the desired state defined in a Git Repository.
What You'll Learn
Why It Matters
Manual kubectl commands and CI-push deployments create configuration drift â what's running in the cluster differs from what's in Git. ArgoCD enforces that the cluster state always matches the Git Repository, providing automated sync, drift detection, instant rollback, and a visual UI for application state. DodaTech manages 80+ Kubernetes applications across 5 clusters using ArgoCD, eliminating configuration drift and reducing deployment Incident Response time by 70%.
Real-World Use
DodaZIP's Kubernetes stack â 30 Microservices, 15 databases, 10 middleware components â is defined entirely in a dodatech-infra Git Repository. ArgoCD watches this Repository and automatically applies any change to the production cluster. A misconfigured deployment is rolled back by reverting a Git commit.
flowchart TD
A[Git Repository] --> B[ArgoCD Server]
B --> C[Application Controller]
C --> D[Kubernetes Cluster]
D --> E[Deployments]
D --> F[Services]
D --> G[ConfigMaps]
D --> H[Ingresses]
E --> I{Drift Detected?}
I -->|Yes| J[Auto-Sync / Prune]
I -->|No| K[Healthy Status]
J --> D
style A fill:#2F73DA,color:#fff
style B fill:#EF7B4D,color:#fff
Prerequisites: A running Kubernetes cluster. kubectl and argocd CLI installed. Basic understanding of GitOps principles.
Installing ArgoCD
# Create namespace
kubectl create namespace argocd
# Install ArgoCD
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
# Expected output:
# namespace/argocd created
# customresourcedefinition.apiextensions.k8s.io/applications.argoproj.io created
# customresourcedefinition.apiextensions.k8s.io/appprojects.argoproj.io created
# serviceaccount/argocd-redis created
# ... (25+ resources created)
# Verify pods
kubectl get pods -n argocd
# NAME READY STATUS
# argocd-application-controller-0 1/1 Running
# argocd-applicationset-controller-6c9b5f8d5f-4hj2k 1/1 Running
# argocd-dex-server-7f5c6b74b6-8zkw9 1/1 Running
# argocd-notifications-controller-5b8c9d5b99-v9xfc 1/1 Running
# argocd-redis-7f8f458bc6-vshmb 1/1 Running
# argocd-repo-server-6f7b5c8d4c-j48h2 1/1 Running
# argocd-server-b64fcfccc-c9pz6 1/1 Running
# Access the UI
kubectl port-forward svc/argocd-server -n argocd 8080:443
# Get the initial admin password
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d
# Login via CLI
argocd login localhost:8080 --username admin --password <initial-password> --insecure
# Change password
argocd account update-password
Defining an Application
# application.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: user-service
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/dodatech/user-service.git
targetRevision: main
path: k8s/overlays/production
helm:
valueFiles:
- values-prod.yaml
destination:
server: https://kubernetes.default.svc
namespace: production
syncPolicy:
automated:
prune: true
selfHeal: true
allowEmpty: false
syncOptions:
- CreateNamespace=true
- PrunePropagationPolicy=foreground
- PruneLast=true
retry:
limit: 5
backoff:
duration: 5s
factor: 2
maxDuration: 3m
revisionHistoryLimit: 10
# Create the application
kubectl apply -f application.yaml
# Or use the CLI
argocd app create user-service \
--repo https://github.com/dodatech/user-service.git \
--path k8s/overlays/production \
--dest-server https://kubernetes.default.svc \
--dest-namespace production \
--sync-policy automated \
--auto-prune \
--self-heal
Sync Management
# Manual sync
argocd app sync user-service
# Expected output:
# TIMESTAMP GROUP KIND NAMESPACE NAME
# 2026-06-24T10:00:00Z apps Deployment production user-service Synced
# 2026-06-24T10:00:01Z v1 Service production user-service Synced
# 2026-06-24T10:00:02Z networking Ingress production user-service Synced
# Get sync status
argocd app get user-service
# Expected output:
# Name: user-service
# Project: default
# Server: https://kubernetes.default.svc
# Namespace: production
# URL: https://argocd.dodatech.com/applications/user-service
# Repo: https://github.com/dodatech/user-service.git
# Target: main
# Path: k8s/overlays/production
# Sync Status: Synced
# Health Status: Healthy
# Rollback to previous revision
argocd app rollback user-service --prune
AppProject Configuration
# project.yaml
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
name: doda-backend
namespace: argocd
spec:
description: DodaTech backend services
sourceRepos:
- 'https://github.com/dodatech/*'
destinations:
- namespace: production
server: https://kubernetes.default.svc
- namespace: staging
server: https://kubernetes.default.svc
- namespace: 'team-*'
server: 'https://*.k8s.dodatech.com'
clusterResourceWhitelist:
- group: ''
kind: Namespace
- group: 'rbac.authorization.k8s.io'
kind: ClusterRole
namespaceResourceBlacklist:
- group: ''
kind: Secret
roles:
- name: read-only
description: Read-only access to applications
policies:
- p, proj:doda-backend:read-only, applications, get, doda-backend/*, allow
groups:
- dodatech-developers
- name: ci-deployer
description: Automated deployment from CI
policies:
- p, proj:doda-backend:ci-deployer, applications, sync, doda-backend/*, allow
jwtTokens:
- iat: 1719200000
Multi-Cluster Management
# Add a remote cluster
argocd cluster add production-context \
--name prod-us-east \
--label environment=production \
--label region=us-east-1
# Expected output:
# Cluster 'prod-us-east' added
# List clusters
argocd cluster list
# SERVER NAME STATUS
# https://kubernetes.default.svc in-cluster Successful
# https://api.prod-us-east.k8s.io prod-us-east Successful
# https://api.staging-eu.k8s.io staging-eu Successful
# Deploy to a specific cluster
argocd app create multi-cluster-app \
--repo https://github.com/dodatech/infra.git \
--path k8s/app \
--dest-server https://api.prod-us-east.k8s.io \
--dest-namespace production
ApplicationSet for Multi-Environment
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: user-service-envs
namespace: argocd
spec:
generators:
- list:
elements:
- environment: dev
cluster: https://api.dev.k8s.dodatech.com
namespace: user-service-dev
- environment: staging
cluster: https://api.staging.k8s.dodatech.com
namespace: user-service-staging
- environment: production
cluster: https://api.prod.k8s.dodatech.com
namespace: user-service-production
template:
metadata:
name: 'user-service-{{environment}}'
spec:
project: default
source:
repoURL: https://github.com/dodatech/user-service.git
targetRevision: main
path: 'k8s/overlays/{{environment}}'
destination:
server: '{{cluster}}'
namespace: '{{namespace}}'
syncPolicy:
automated:
prune: true
selfHeal: true
Common Configuration Mistakes
Not enabling auto-prune: Without
prune: true, ArgoCD never removes resources that were deleted from Git. Stale resources accumulate and drift goes undetected.Hardcoding cluster URLs in Application manifests: When clusters rotate, every Application must be updated. Use ApplicationSet generators or cluster labels for dynamic targeting.
Missing syncOptions for namespace creation: Without
CreateNamespace=true, the sync fails if the target namespace doesn't exist. Always include this for new environments.Ignoring sync waves for dependency ordering: Resources without sync waves deploy in arbitrary order. Use
argocd.argoproj.io/sync-wave: "-5"annotations to order dependent resources (e.g., ConfigMap before Deployment).Using default project without restricting sources: The default project allows any source Repository. Create AppProjects with locked-down
sourceReposanddestinations.
Practice Questions
What is the difference between sync and health status in ArgoCD? Answer: Sync status indicates whether the cluster matches Git (Synced/OutOfSync). Health status indicates whether the application is running correctly (Healthy/Degraded/Progressing).
How does self-heal differ from auto-sync? Answer: Auto-sync refreshes from Git on schedule or Webhook. Self-heal automatically corrects any manual changes made to the cluster, reverting them to the Git-defined state.
What is an ApplicationSet generator? Answer: ApplicationSet generators dynamically create Applications based on parameters â from lists, Git directories, cluster labels, pull requests, or SCM providers.
How do you handle secrets in a GitOps workflow? Answer: Use SealedSecrets (encrypted secrets stored in Git), External Secrets Operator (syncing from AWS Secrets Manager/Vault), or SOPS-encrypted files with ArgoCD's built-in decryption.
Challenge
Deploy a complete application stack with ArgoCD: create an AppProject for a team with restricted source repos and destination namespaces, define Applications for a frontend and backend service across dev, staging, and production using an ApplicationSet, configure automated sync with self-heal and prune, set up sync waves so ConfigMaps deploy before Deployments, and add a multi-cluster cluster destination.
Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro