Docker · Kubernetes · Grafana · ArgoCD · AWS

💡 GitOps Concept

GitOps Flow Developer Git Repository ArgoCD Kubernetes ───────── ────────────── ────── ────────── 1. Write YAML ──push──► manifests/ 2. Review PR │ deployment.yaml watches every 3 min 3. Merge │ service.yaml ────► compares │ configmap.yaml │ desired state (git) │ │ vs │ │ actual state (cluster) │ │ │ if different: │ auto-apply (selfHeal=true) │ or show as OutOfSync │ │ │ ▼ │ kubectl apply changes │ to the cluster
🔑
Core GitOps principle

Never run kubectl apply manually in production. All changes go through Git → Pull Request → Merge → ArgoCD applies automatically. Git history is your audit log.

📦 Installation

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

# Wait for pods to be ready
kubectl wait --for=condition=Ready pod -l app.kubernetes.io/name=argocd-server \
  -n argocd --timeout=120s

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

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

# Open: https://localhost:8080  (login: admin / )

# Install ArgoCD CLI
curl -sSL -o argocd https://github.com/argoproj/argo-cd/releases/latest/download/argocd-linux-amd64
chmod +x argocd && mv argocd /usr/local/bin/

# Login via CLI
argocd login localhost:8080 --username admin --password <PASSWORD> --insecure

📄 Creating an Application

An ArgoCD Application tells ArgoCD which Git repo/path to sync to which cluster/namespace.

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: myapp
  namespace: argocd          # ArgoCD lives here
spec:
  project: default

  source:
    repoURL: https://github.com/myorg/infra.git
    targetRevision: main      # branch, tag, or commit SHA
    path: manifests/myapp     # folder within the repo

  destination:
    server: https://kubernetes.default.svc   # in-cluster
    namespace: myapp

  syncPolicy:
    automated:
      prune: true             # delete resources removed from git
      selfHeal: true          # auto-fix manual kubectl changes
    syncOptions:
      - CreateNamespace=true  # create the namespace if missing
    retry:
      limit: 3
      backoff:
        duration: 5s
        factor: 2
SettingWhat It DoesRecommendation
automated.prune: trueDeletes resources that were removed from GitEnable in production — keeps cluster clean
automated.selfHeal: trueReverts manual kubectl changes automaticallyEnable — enforces Git as source of truth
prune: falseNever deletes resources, even if removed from GitUse during migrations to avoid accidental deletes
CreateNamespace=trueCreates the target namespace if missingEnable for convenience

⌨️ CLI Commands

# ── Applications ────────────────────────────────────────
argocd app list                       # list all apps
argocd app get myapp                  # detailed status
argocd app sync myapp                 # trigger manual sync
argocd app sync myapp --prune         # sync and prune orphaned resources
argocd app diff myapp                 # show what would change
argocd app rollback myapp 3           # rollback to history id 3
argocd app history myapp              # show sync history
argocd app delete myapp               # delete app (not the resources)
argocd app delete myapp --cascade     # delete app AND its k8s resources

# ── Repositories ────────────────────────────────────────
argocd repo add https://github.com/org/infra.git \
  --username git --password mytoken

argocd repo add git@github.com:org/infra.git \
  --ssh-private-key-path ~/.ssh/id_rsa

argocd repo list

# ── Projects ────────────────────────────────────────────
argocd proj list
argocd proj create myproject

# ── Users / RBAC ────────────────────────────────────────
argocd account list
argocd account update-password --current-password old --new-password new

🩺 Sync & Health Status

StatusMeaningAction
SyncedCluster matches Git exactlyNothing — all good
OutOfSyncCluster differs from GitClick Sync or argocd app sync myapp
UnknownCan't determine status (API error)Check ArgoCD server logs
HealthyAll pods running, services respondingNothing
DegradedSome pods crashing or not readykubectl describe pod + check logs
ProgressingRolling update in progressWait or watch with kubectl rollout status
SuspendedApp sync is pausedResume in UI or argocd app resume myapp

📁 Git Repo Structure

infra/
├── apps/                       # ArgoCD Application manifests
│   ├── app-of-apps.yaml        # the root Application
│   ├── myapp.yaml
│   └── monitoring.yaml
│
├── manifests/
│   ├── myapp/
│   │   ├── namespace.yaml
│   │   ├── deployment.yaml
│   │   ├── service.yaml
│   │   └── configmap.yaml
│   │
│   └── monitoring/
│       ├── prometheus/
│       └── grafana/
│
└── README.md

App of Apps Pattern

One root ArgoCD Application that manages all other Applications. Add a new service = add one YAML to apps/.

# apps/app-of-apps.yaml — the root application
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: root
  namespace: argocd
spec:
  source:
    repoURL: https://github.com/myorg/infra.git
    targetRevision: main
    path: apps                 # watches the apps/ directory
  destination:
    server: https://kubernetes.default.svc
    namespace: argocd          # child apps are deployed here
  syncPolicy:
    automated:
      prune: true
      selfHeal: true

⛵ Helm Charts

ArgoCD can deploy Helm charts directly from a repo — no need to run helm install manually.

spec:
  source:
    repoURL: https://prometheus-community.github.io/helm-charts
    chart: kube-prometheus-stack
    targetRevision: "55.5.0"
    helm:
      releaseName: monitoring
      values: |
        grafana:
          adminPassword: "admin"
          service:
            type: NodePort
        prometheus:
          prometheusSpec:
            retention: 30d

📋 Day-to-Day Workflow

1

Make a change

Edit a YAML file in your infra repo. Change image tag, update replicas, add a ConfigMap key, etc.

2

Create a PR

Push to a feature branch. Open a pull request so teammates can review the infrastructure change.

3

Merge to main

After approval, merge the PR. ArgoCD detects the change within 3 minutes (or immediately on webhook push).

4

Watch the sync

In the ArgoCD UI, watch the application sync. Each resource shows green (healthy) or red (error) in real-time.

5

Rollback if needed

If something is wrong, click History and Rollback in the UI, or run argocd app rollback myapp 3. ArgoCD re-applies the previous Git commit's state instantly.

⚠️
selfHeal will overwrite manual changes

With selfHeal: true, any manual kubectl change will be reverted by ArgoCD within minutes. This is the point — but be aware of it during debugging. Disable auto-sync temporarily if needed: argocd app set myapp --sync-policy none