Build a GitOps Deployment Platform with ArgoCD
Deploy ArgoCD on Kubernetes, connect it to a Git repository, and implement GitOps workflows with automated sync and rollback.
Domains & Technologies
Blueprint Walkthrough
Architecture Overview
In this project you will build a complete GitOps deployment platform using ArgoCD. You will install ArgoCD on a Kubernetes cluster, connect it to a Git repository that acts as the single source of truth for application state, and implement automated continuous deployment — every merge to main triggers a deployment without any pipeline step that kubectl applies manifests directly.
This architecture eliminates the security problem of CI/CD pipelines holding cluster credentials and is the deployment model used by engineering teams at Atlassian, Zerodha, and most Kubernetes-native product companies.
+----------------------------------------------------------+ | Developer | | | | | +-- git push --► GitHub (main branch) | | | | | v | | GitHub Actions CI | | (build, test, push image) | | | | | Updates image tag | | in manifests repo | | | | | v | | Git Manifests Repo | | (source of truth) | | ^ | | | polls every 3 minutes | | | or webhook on push | | ArgoCD (in cluster) | | | | | v | | Kubernetes Cluster | | (reconciles live state to Git state) | +----------------------------------------------------------+Problem Solved
With traditional push-based CI/CD, the pipeline holds a kubeconfig or service account token with broad cluster permissions. If the CI system is compromised — through a supply chain attack, a malicious PR, or stolen secrets — the attacker gains direct cluster access.
GitOps inverts this. ArgoCD runs inside the cluster and pulls from Git. No external system has cluster credentials. The only way to change the cluster state is to change Git, which requires code review and is fully auditable. Drift — when someone runs kubectl apply directly without going through Git — is detected automatically and can be auto-corrected.
Step-by-Step Implementation Guide
Step 1: Prepare Your Kubernetes Cluster and Git Repositories
You need two Git repositories. One for the application code (where developers push features), and one for the Kubernetes manifests (where ArgoCD reads from). Separating them is a GitOps best practice — it decouples the deployment concerns from the development concerns.
## Verify you have a running Kubernetes clusterkubectl cluster-infokubectl get nodes ## For local development, use kind or k3s## Install kind if neededcurl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.22.0/kind-linux-amd64chmod +x ./kind && sudo mv ./kind /usr/local/bin/kind ## Create a local clusterkind create cluster --name gitops-demo --config - <<EOFapiVersion: kind.x-k8s.io/v1alpha4kind: Clusternodes:* role: control-plane* role: worker* role: workerEOF kubectl get nodes## Expected: 3 nodes Ready (1 control-plane, 2 workers)Create the manifests repository structure on GitHub:
gitops-manifests/+-- apps/| +-- web-app/| +-- base/| | +-- deployment.yaml| | +-- service.yaml| | +-- kustomization.yaml| +-- overlays/| +-- staging/| | +-- kustomization.yaml| +-- production/| +-- kustomization.yaml+-- argocd/ +-- applications/ +-- web-app-staging.yaml +-- web-app-production.yamlRememberThe manifests repository is not the application code repository. Developers commit code to the app repo. The CI pipeline (or an automated tool like ArgoCD Image Updater) commits image tag changes to the manifests repo. ArgoCD watches only the manifests repo.
Step 2: Install ArgoCD on Kubernetes
## Create the argocd namespacekubectl create namespace argocd ## Install ArgoCD — this creates all CRDs, deployments, services, and RBACkubectl apply -n argocd -f \ https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml ## Wait for all pods to be Running (takes 2-3 minutes)kubectl wait --for=condition=available \ --timeout=300s \ deployment/argocd-server -n argocd ## Check all pods are runningkubectl get pods -n argocd## Expected: argocd-server, argocd-repo-server, argocd-application-controller,## argocd-dex-server, argocd-redis all Running ## Get the initial admin password (auto-generated)kubectl -n argocd get secret argocd-initial-admin-secret \ -o jsonpath="{.data.password}" | base64 -d && echo## Save this password — you will need it to log inAccess the ArgoCD UI:
## Forward the ArgoCD server port to your local machinekubectl port-forward svc/argocd-server -n argocd 8080:443 ## Open https://localhost:8080 in your browser## Username: admin## Password: (the value from the command above)Install the ArgoCD CLI:
curl -sSL -o argocd-linux-amd64 \ https://github.com/argoproj/argo-cd/releases/latest/download/argocd-linux-amd64chmod +x argocd-linux-amd64 && sudo mv argocd-linux-amd64 /usr/local/bin/argocd ## Log in via CLIargocd login localhost:8080 \ --username admin \ --password YOUR_PASSWORD \ --insecureStep 3: Create the Application Manifests with Kustomize
Kustomize allows you to have a base configuration and environment-specific overlays — without duplicating YAML files.
Create apps/web-app/base/deployment.yaml in your manifests repo:
apiVersion: apps/v1kind: Deploymentmetadata: name: web-appspec: replicas: 2 selector: matchLabels: app: web-app template: metadata: labels: app: web-app spec: containers: - name: web-app image: nginx:1.25-alpine # ArgoCD Image Updater will manage this tag ports: - containerPort: 80 resources: requests: memory: "64Mi" cpu: "50m" limits: memory: "128Mi" cpu: "200m" readinessProbe: httpGet: path: / port: 80 initialDelaySeconds: 5 periodSeconds: 10Create apps/web-app/base/kustomization.yaml:
apiVersion: kustomize.config.k8s.io/v1beta1kind: Kustomizationresources:- deployment.yaml- service.yamlCreate the production overlay apps/web-app/overlays/production/kustomization.yaml:
apiVersion: kustomize.config.k8s.io/v1beta1kind: Kustomizationresources:- ../../basepatchesStrategicMerge:- | apiVersion: apps/v1 kind: Deployment metadata: name: web-app spec: replicas: 3 # Production runs 3 replicasnamePrefix: prod-namespace: productionCommit and push these files to your manifests repo.
Step 4: Connect ArgoCD to Your Git Repository
## Add your manifests repository to ArgoCD## For a public repo:argocd repo add https://github.com/YOUR_USERNAME/gitops-manifests.git ## For a private repo, use an SSH key or personal access token:argocd repo add https://github.com/YOUR_USERNAME/gitops-manifests.git \ --username YOUR_USERNAME \ --password YOUR_GITHUB_PAT ## Verify the repository was added successfullyargocd repo list## Expected: STATUS = SuccessfulStep 5: Create the ArgoCD Application Resources
Create argocd/applications/web-app-production.yaml in your manifests repo:
apiVersion: argoproj.io/v1alpha1kind: Applicationmetadata: name: web-app-production namespace: argocd finalizers: - resources-finalizer.argocd.argoproj.io # Deletes cluster resources when app is deletedspec: project: default source: repoURL: https://github.com/YOUR_USERNAME/gitops-manifests.git targetRevision: main path: apps/web-app/overlays/production destination: server: https://kubernetes.default.svc namespace: production syncPolicy: automated: prune: true # Delete resources removed from Git selfHeal: true # Revert manual changes to match Git state syncOptions: - CreateNamespace=true # Create namespace if it does not exist - PrunePropagationPolicy=foreground retry: limit: 3 backoff: duration: 5s factor: 2 maxDuration: 3m## Apply the Application resourcekubectl apply -f argocd/applications/web-app-production.yaml ## Watch ArgoCD sync the applicationargocd app get web-app-productionargocd app sync web-app-production # Manual sync for the first time ## Watch the live sync statusargocd app wait web-app-production --health --syncSecurityEnable
selfHeal: truein production. Without it, a developer who runskubectl applydirectly to make an emergency change will cause permanent drift — the cluster state diverges from Git and nobody knows which state is the source of truth.
Step 6: Implement Automated Image Updates with ArgoCD Image Updater
ArgoCD Image Updater watches your container registry for new image tags and automatically commits the updated tag to your manifests repo.
## Install ArgoCD Image Updaterkubectl apply -n argocd -f \ https://raw.githubusercontent.com/argoproj-labs/argocd-image-updater/stable/manifests/install.yaml ## Annotate the Application to enable image updateskubectl annotate application web-app-production -n argocd \ argocd-image-updater.argoproj.io/image-list="web-app=nginx" \ argocd-image-updater.argoproj.io/web-app.update-strategy=semver \ argocd-image-updater.argoproj.io/web-app.allow-tags="regexp:^1\.25\..*"Step 7: Simulate a Rollback
The power of GitOps is that rollback is a git revert.
## Simulate a bad deployment by updating the image to a non-existent tag## Edit apps/web-app/overlays/production/kustomization.yaml## Change the image to: nginx:99.99-brokengit commit -am "test: use broken image tag"git push ## Watch ArgoCD detect the change and try to syncargocd app get web-app-production --watch## The deployment will fail because the image does not exist ## Rollback via Git — the correct GitOps waygit revert HEADgit push ## ArgoCD detects the revert and re-syncs to the working stateargocd app wait web-app-production --healthTipYou can also use
argocd app history web-app-productionandargocd app rollback web-app-production REVISIONto roll back to any previous revision from the ArgoCD CLI without touching Git. However, the Git revert method is preferred because it creates an audit trail in your repository.
Validation & Testing
## 1. Verify ArgoCD shows the app as Synced and Healthyargocd app get web-app-production## Expected: Health Status = Healthy, Sync Status = Synced ## 2. Check the production pods are runningkubectl get pods -n production## Expected: 3 pods Running (prod-web-app-*) ## 3. Test drift detection — make a manual changekubectl scale deployment prod-web-app -n production --replicas=1## Wait 3 minutes (or trigger webhook)argocd app get web-app-production## Expected: Sync Status = OutOfSync (ArgoCD detected the manual change)## With selfHeal=true, ArgoCD will automatically revert this within 3 minutes ## 4. Verify selfHeal reverted the changekubectl get deployment prod-web-app -n production## Expected: DESIRED = 3 (restored from Git state) ## 5. Verify no kubectl credentials exist in your CI system## The entire deployment happened without any pipeline having cluster accessecho "GitOps deployment complete — no cluster credentials in CI"Videos & Guides
ArgoCD GitOps Tutorial — TechWorld with Nana
Complete ArgoCD GitOps tutorial covering installation, application setup, sync policies, and the full GitOps workflow for Kubernetes deployments.
ArgoCD Official Documentation
Official ArgoCD documentation covering all features including ApplicationSets, Projects, RBAC, and SSO integration for enterprise deployments.
GitOps with ArgoCD and GitHub Actions
Practical walkthrough of wiring GitHub Actions CI with ArgoCD GitOps — the image build pushes, the manifest updates, and ArgoCD deploys automatically.