TechLead
Lesson 22 of 25
5 min read
Cloud & Kubernetes

GitOps with ArgoCD

Implement GitOps principles using ArgoCD for declarative, Git-based continuous delivery to Kubernetes clusters

What is GitOps?

GitOps is an operational framework that uses Git as the single source of truth for declarative infrastructure and applications. With GitOps, the entire system state is described in Git, and an automated process ensures the live system matches the desired state in the repository. Any drift is detected and corrected automatically.

GitOps Principles

  • Declarative: The entire system described declaratively (YAML/Helm/Kustomize)
  • Versioned & Immutable: Desired state stored in Git with full history
  • Pulled Automatically: Agents pull desired state from Git and apply it (pull-based, not push-based)
  • Continuously Reconciled: Agents continuously compare actual vs desired state and correct drift

ArgoCD Overview

ArgoCD is a declarative, GitOps continuous delivery tool for Kubernetes. It monitors your Git repository for changes and automatically synchronizes the cluster state to match. ArgoCD supports plain YAML manifests, Helm charts, Kustomize, and Jsonnet.

Installing ArgoCD

# Install ArgoCD
kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml

# Wait for ArgoCD to be ready
kubectl wait --for=condition=available --timeout=300s deployment/argocd-server -n argocd

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

# Access ArgoCD UI
kubectl port-forward svc/argocd-server -n argocd 8080:443

# Install ArgoCD CLI
brew install argocd  # macOS

# Login to ArgoCD
argocd login localhost:8080 --username admin --password <password> --insecure

# Change the admin password
argocd account update-password

Creating an ArgoCD Application

# argocd-application.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: my-web-app
  namespace: argocd
  finalizers:
    - resources-finalizer.argocd.argoproj.io
spec:
  project: default
  source:
    repoURL: https://github.com/myorg/k8s-manifests.git
    targetRevision: main
    path: apps/my-web-app/overlays/production
  destination:
    server: https://kubernetes.default.svc
    namespace: production
  syncPolicy:
    automated:
      prune: true      # Delete resources not in Git
      selfHeal: true   # Auto-fix drift from desired state
      allowEmpty: false # Don't sync if no resources found
    syncOptions:
    - CreateNamespace=true
    - ApplyOutOfSyncOnly=true
    retry:
      limit: 5
      backoff:
        duration: 5s
        factor: 2
        maxDuration: 3m

Kustomize-based GitOps Structure

# Repository structure for GitOps:
# k8s-manifests/
#   apps/
#     my-web-app/
#       base/
#         deployment.yaml
#         service.yaml
#         kustomization.yaml
#       overlays/
#         staging/
#           kustomization.yaml
#           replicas-patch.yaml
#         production/
#           kustomization.yaml
#           replicas-patch.yaml
#           hpa.yaml
# base/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - deployment.yaml
  - service.yaml

# base/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-web-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: my-web-app
  template:
    metadata:
      labels:
        app: my-web-app
    spec:
      containers:
      - name: app
        image: ghcr.io/myorg/my-web-app:latest
        ports:
        - containerPort: 3000
        resources:
          requests:
            cpu: 100m
            memory: 128Mi
# overlays/production/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: production
resources:
  - ../../base
  - hpa.yaml
patches:
  - path: replicas-patch.yaml
images:
  - name: ghcr.io/myorg/my-web-app
    newTag: "1.5.0"    # Pin to specific version

# overlays/production/replicas-patch.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-web-app
spec:
  replicas: 5

Helm-based ArgoCD Application

# argocd-helm-app.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: nginx-ingress
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://kubernetes.github.io/ingress-nginx
    chart: ingress-nginx
    targetRevision: 4.9.0
    helm:
      values: |
        controller:
          replicaCount: 2
          resources:
            requests:
              cpu: 100m
              memory: 128Mi
          metrics:
            enabled: true
  destination:
    server: https://kubernetes.default.svc
    namespace: ingress-nginx
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
    - CreateNamespace=true

ArgoCD CLI Operations

# List applications
argocd app list

# Get application details
argocd app get my-web-app

# Sync an application manually
argocd app sync my-web-app

# View application history
argocd app history my-web-app

# Rollback to a previous version
argocd app rollback my-web-app 2

# Diff: compare live state to desired state
argocd app diff my-web-app

# Delete an application
argocd app delete my-web-app

Key Takeaways

  • GitOps uses Git as the single source of truth for infrastructure and application state
  • ArgoCD continuously reconciles the cluster state with the desired state in Git
  • Use Kustomize overlays to manage environment-specific configurations
  • Auto-sync with self-heal and prune ensures drift is automatically corrected
  • Separate application code repos from deployment manifest repos for cleaner GitOps

Continue Learning