Skip to content

GitOps with ArgoCD — Complete Guide for Kubernetes Deployments

DodaTech 12 min read

In this tutorial, you'll learn about GitOps with ArgoCD. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.

This tutorial teaches you how to implement a complete GitOps workflow using ArgoCD on Kubernetes — you will install ArgoCD, declare applications declaratively, configure sync strategies, manage multiple environments, and automate drift detection and self-healing.

Why It Matters

Traditional CI/CD pipelines push configuration to clusters with a one-shot kubectl apply — if the command succeeds you assume it worked, and if someone later changes a resource directly on the cluster there is no record and no automatic rollback. GitOps flips this model: a controller inside the cluster continuously pulls the desired state from Git and reconciles any drift automatically. Every change is audited, versioned, and reviewable through standard pull requests, turning infrastructure management into a developer-grade workflow.

Real-World Use

DodaTech manages Durga Antivirus Pro's Kubernetes infrastructure with ArgoCD — every Deployment, Service, ConfigMap, and encrypted Secret lives in a Git Repository. When a developer opens a Pull Request changing the API replica count, the PR triggers a preview environment, and merging to main automatically syncs the change to production via ArgoCD's automated sync policy.

flowchart LR
    A[Developer] -->|git push| B[Git Repository]
    B --> C[ArgoCD Controller]
    C -->|sync| D[Kubernetes Cluster]
    D -->|status| C
    C -->|drift detected| D
    C -->|re-sync| D
    E[Manual Change] -->|drift| C
    style C fill:#EF7B4D,color:#fff
    style B fill:#4CAF50,color:#fff
â„šī¸ Info

Prerequisites: Kubernetes fundamentals (Pods, Deployments, Services), Git workflow knowledge, plus a running Kubernetes cluster (local kind/minikube or cloud-based).

What Is GitOps?

GitOps is an operational model that uses a Git Repository as the single source of truth for infrastructure and application configuration. Instead of running kubectl apply from a CI pipeline, you declare the desired state of your cluster in YAML files stored in Git, and a software agent running inside the cluster continuously ensures the live state matches that declaration.

Three principles define GitOps:

  • Declarative configuration — every resource (Deployment, Service, ConfigMap, etc.) is defined as a YAML file, not created imperatively.
  • Git as source of truth — the Repository is the authoritative record; no change happens without a commit.
  • Automated reconciliation — the agent detects and corrects drift between the Git state and the live cluster.

ArgoCD Architecture

ArgoCD is the most widely adopted GitOps operator for Kubernetes. It consists of three core components:

Component Role
API Server Exposes gRPC/REST APIs for the CLI, Web UI, and CI/CD integrations. Handles authentication, authorization, and app management.
Repository Server Clones Git repositories, caches manifests, and renders templates (Kustomize, Helm, Jsonnet, etc.) into raw Kubernetes resources.
Application Controller Continuously compares desired state (from Git) against live state (from the cluster API) and triggers sync operations when drift is detected.

The controller runs a three-second reconciliation loop by default. It queries the cluster state, compares it against the cached Git state, and reports (or corrects) any differences.

Installing ArgoCD on Kubernetes

ArgoCD installs as a set of Kubernetes manifests. The recommended method uses the official install.yaml from the ArgoCD project.

# Create the argocd namespace and install all resources
kubectl create namespace argocd
kubectl apply -n argocd -f \
  https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml

Expected output (truncated):

namespace/argocd created
customresourcedefinition.apiextensions.k8s.io/applications.argoproj.io created
customresourcedefinition.apiextensions.k8s.io/applicationsets.argoproj.io created
serviceaccount/argocd-application-controller created
serviceaccount/argocd-server created
deployment.apps/argocd-application-controller created
deployment.apps/argocd-server created
deployment.apps/argocd-repo-server created
deployment.apps/argocd-redis created

Retrieve the auto-generated admin password and access the Web UI:

# Get initial admin password
kubectl -n argocd get secret argocd-initial-admin-secret \
  -o jsonpath="{.data.password}" | base64 -d

# Port-forward the API server
kubectl port-forward -n argocd svc/argocd-server 8080:443

Expected output for the password command:

xxxxxxxxxxxxxx (auto-generated random string)

Open https://localhost:8080 in a browser and log in with username admin and the password from above. Change the password on first login.

Declaring Applications

Applications in ArgoCD are defined as custom resources. This means the GitOps controller itself is configured declaratively — your Application definitions live in Git alongside your infrastructure manifests.

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: myapp-production
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/myorg/myapp-config.git
    targetRevision: main
    path: overlays/production
  destination:
    server: https://kubernetes.default.svc
    namespace: production
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
      allowEmpty: false
    syncOptions:
      - CreateNamespace=true
      - PruneLast=true

Register the application with the cluster:

kubectl apply -f application.yaml

Expected output:

application.argoproj.io/myapp-production created

ArgoCD now watches the overlays/production path. Every commit to main triggers an automatic sync. The CreateNamespace=true option ensures the production namespace is created if it does not exist.

Sync Strategies

Automatic Sync

Automatic sync deploys changes the moment they are committed to the tracked branch. ArgoCD polls Git every three minutes by default and syncs immediately when a change is detected.

syncPolicy:
  automated:
    prune: true
    selfHeal: true

Expected behavior: a commit to main is deployed to the cluster within three minutes. prune: true removes resources that no longer exist in Git. selfHeal: true reverts any manual changes detected on the cluster.

Manual Sync with Approval

For production environments automatic sync may be too aggressive. Removing the automated block makes sync purely manual.

syncPolicy: {}

Trigger a sync through the CLI:

argocd app sync myapp-production

Expected output:

TIMESTAMP                  GROUP        KIND        NAMESPACE    NAME
2026-06-23T10:00:00Z       apps         Deployment  production   myapp-api
2026-06-23T10:00:01Z       v1           Service     production   myapp-api
---
Phase:                        Succeeded
Message:                      successfully synced (1.23s)

Sync Waves

Resources within a single application can be ordered using sync waves. ConfigMaps and Secrets must exist before the Pods that consume them.

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
  annotations:
    argocd.argoproj.io/sync-wave: "-5"
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-api
  annotations:
    argocd.argoproj.io/sync-wave: "0"

Expected behavior: resources with lower sync-wave numbers are applied first. Wave -5 (ConfigMap) is created before wave 0 (Deployment), ensuring configuration exists before the application starts.

Multi-Environment Deployments

ArgoCD supports managing multiple environments from a single Repository using Kustomize overlays or Helm value files.

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: myapp-dev
spec:
  source:
    repoURL: https://github.com/myorg/myapp-config.git
    targetRevision: main
    path: overlays/dev
  destination:
    namespace: dev
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: myapp-production
spec:
  source:
    repoURL: https://github.com/myorg/myapp-config.git
    targetRevision: main
    path: overlays/production
  destination:
    namespace: production
  syncPolicy: {}

Expected behavior: dev auto-syncs on every merge to main. Production requires manual approval, allowing a human to verify changes in dev before promoting.

Generate all environments at once using an ApplicationSet:

cat << 'EOF' | kubectl apply -f -
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: myapp
spec:
  generators:
    - list:
        elements:
          - env: dev
            namespace: dev
          - env: staging
            namespace: staging
          - env: production
            namespace: production
  template:
    metadata:
      name: 'myapp-{{ env }}'
    spec:
      source:
        repoURL: https://github.com/myorg/myapp-config.git
        targetRevision: main
        path: 'environments/{{ env }}'
      destination:
        namespace: '{{ namespace }}'
      syncPolicy:
        automated:
          prune: true
          selfHeal: true
EOF

Expected output:

applicationset.argoproj.io/myapp created

The ApplicationSet generates three Application resources. Adding a new environment is as simple as adding an element to the list generator.

ArgoCD CLI and Web UI

The ArgoCD CLI provides full control over applications, syncs, and settings.

# List all applications
argocd app list

# View application details and health
argocd app get myapp-production

# View diff between Git and live state
argocd app diff myapp-production

# Rollback to a previous deployment
argocd app rollback myapp-production a1b2c3d

# Change admin password
argocd account update-password

Expected output for argocd app get:

Name:               myapp-production
Project:            default
Server:             https://kubernetes.default.svc
Namespace:          production
URL:                https://localhost:8080/applications/myapp-production
Sync Status:        Synced
Health Status:      Healthy

The Web UI shows a visual tree of all Kubernetes resources owned by each application, with color-coded health and sync status. You can trigger syncs, view logs, inspect resource manifests, and roll back from the browser.

Best Practices

RBAC and Projects

ArgoCD projects group applications and enforce access boundaries. Each team should have its own project with explicit source repositories, destination clusters, and allowed namespaces.

apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
  name: team-platform
  namespace: argocd
spec:
  sourceRepos:
    - 'https://github.com/myorg/team-platform-config.git'
  destinations:
    - namespace: 'platform-*'
      server: https://kubernetes.default.svc
  roles:
    - name: admin
      policies:
        - p, proj:team-platform:admin, applications, *, team-platform/*, allow

Secrets Management

Never store plain-text secrets in Git repositories. Use one of these approaches with Docker and Kubernetes:

  • SealedSecrets — encrypts Secret data into a SealedSecret CRD that only the controller in your cluster can decrypt.
  • SOPS — encrypts individual values in YAML files with age, PGP, or cloud KMS.
  • External Secrets Operator — syncs secrets from HashiCorp Vault, AWS Secrets Manager, or Azure Key Vault into Kubernetes Secrets automatically.

Monitoring and Notifications

ArgoCD can send notifications to Slack, email, or Webhooks when syncs fail or applications degrade health. Install the argocd-notifications controller and configure triggers:

apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-notifications-cm
data:
  trigger.on-sync-failed: |
    - description: Application sync failed
      send:
        - slack-on-failure
  template.slack-on-failure: |
    message: |
      Application {{ .app.Name }} sync failed.
      {{ .app.Status.OperationState.Message }}

Additional Practices

  • Pin the ArgoCD version in production — do not use stable tag.
  • Use PruneLast=true to delete resources after new ones are created, reducing downtime.
  • Enable auto sync for dev/staging and manual for production.
  • Monitor the reconciliation loop health via Prometheus metrics exposed by the application controller.
  • Use the DevOps methodology alongside GitOps for full lifecycle automation.

Common Errors

  1. Storing secrets in Git in plain text — Git history is immutable. Anyone with Repository access can see committed secrets. Always encrypt secrets before committing, or use an external secrets operator.

  2. Enabling prune before verifying the configuration — Pruning deletes resources that are removed from Git. If you accidentally delete a manifest file from the Repository, prune: true deletes the corresponding resource from the cluster. Start with prune: false until you validate the setup.

  3. Mixing automatic and manual policies in the same environment — An application with auto-sync enabled but certain resources requiring manual approval creates confusion. Stick to one policy per environment.

  4. Ignoring project RBAC — Without ArgoCD projects, any authenticated user can deploy to any namespace. Always configure projects with explicit source repositories and destination namespaces.

  5. Failing to monitor sync status — A stuck sync (invalid YAML, missing ConfigMap, expired certificate) blocks subsequent deployments. Set up notifications for sync failures and health degradation.

Practice Questions

  1. What is the single source of truth in a GitOps workflow? The Git Repository. The desired state is declared in Git, and the GitOps controller ensures the live environment matches exactly. No change occurs without a corresponding commit.

  2. How does ArgoCD detect and handle configuration drift? ArgoCD continuously compares the live cluster state against the desired state defined in Git. When they differ, it reports the drift and, if selfHeal is enabled, automatically reverts the cluster to match Git.

  3. What is the difference between automatic and manual sync policies? Automatic sync deploys changes as soon as they are pushed to Git and detected by the polling loop. Manual sync requires a human to approve the deployment through the ArgoCD UI or CLI using argocd app sync.

  4. How do sync waves help with application startup order? Sync waves order resource creation by the argocd.argoproj.io/sync-wave annotation value. Resources with lower numbers (e.g., -5) are applied before higher numbers (e.g., 0), ensuring dependencies like ConfigMaps exist before Deployments.

  5. What is the purpose of the prune flag in the sync policy? Prune ensures that resources removed from Git are also deleted from the cluster. It keeps the live state identical to the repo state. Disable it initially to avoid accidental deletions.

Challenge

Set up a complete GitOps workflow from scratch: install ArgoCD on a Kubernetes cluster (local kind or minikube), create a Git Repository with Kubernetes manifests for a web application (Deployment, Service, ConfigMap), configure an Application resource with automated sync and self-healing, promote the application from dev to staging to production using separate Kustomize overlays, manually scale a Deployment to test drift detection, and verify that ArgoCD reverts the change within three minutes.

Real-World Task

Implement a multi-environment GitOps pipeline. Create a Git Repository with three directories (dev, staging, prod) containing Kubernetes manifests for a sample application. Install ArgoCD on a kind cluster. Register each environment as a separate Application — dev with automated sync, production with manual sync. Deploy a change through the full PR-to-production flow: push to dev, verify, promote to staging via a Kustomize overlay, manually approve for production. Test drift by running kubectl scale deployment -n production --replicas=10 and confirm ArgoCD reverts it to the Git-defined count.

Frequently Asked Questions

{{< faq question="What is the difference between GitOps and Infrastructure as Code?">}} Infrastructure as Code (IaC) means defining infrastructure in configuration files. GitOps is an operational model that applies IaC through a Git-centric workflow with automated reconciliation. You can use IaC without GitOps (e.g., running Terraform from a local machine), but GitOps always requires IaC. See the YAML guide for config-file basics. {{< /faq >}}

{{< faq question="Can ArgoCD manage resources outside of Kubernetes?">}} ArgoCD is designed specifically for Kubernetes. For non-Kubernetes resources, tools like Crossplane or Terraform with Git-driven pipelines are more appropriate. ArgoCD can, however, manage custom resources that provision external infrastructure through operators. {{< /faq >}}

{{< faq question="How does ArgoCD handle Helm charts from external repositories?">}} ArgoCD can source Helm charts directly from Helm repositories, OCI registries, or Git repositories. Set source.chart and source.repoURL to the Helm Repository URL, or point to a Git repo containing a Chart.yaml. ArgoCD renders the template server-side in the repo-server component.{{< /faq >}}

{{< faq question="Is ArgoCD compatible with existing CI/CD pipelines?">}} Yes. ArgoCD replaces the deployment step of a pipeline, not the build step. Your CI pipeline builds container images and pushes them to a registry, then updates the image tag in a Git Repository. ArgoCD detects the Git change and deploys the new version to the cluster. {{< /faq >}}

Next Steps

Kubernetes Guide — Master Pods, Deployments, Services, and cluster management.

Docker Guide — Learn container fundamentals, Dockerfile optimization, and image registries.

CI/CD Pipelines — Build automated build-test-deploy pipelines that feed configuration into ArgoCD.

Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro