GitOps with ArgoCD: The Complete Guide to Kubernetes Deployment Automation



GitOps with ArgoCD: The Complete Guide to Kubernetes Deployment Automation

GitOps has become the de facto standard for managing Kubernetes deployments. At its core, ArgoCD stands as the most adopted GitOps tool, providing a declarative approach to continuous deployment that treats Git as the single source of truth.

DevOps Pipeline Photo by Growtika on Unsplash

What is GitOps?

GitOps is an operational framework that applies DevOps best practices for infrastructure automation:

  • Declarative: Entire system described declaratively in Git
  • Versioned: Complete history of changes
  • Automated: Changes automatically applied
  • Self-healing: System corrects drift automatically

Why ArgoCD?

ArgoCD has emerged as the leader in GitOps tooling:

FeatureArgoCDFluxJenkins X
UI Dashboard✅ Excellent⚠️ Basic⚠️ Basic
Multi-cluster✅ Native✅ Native❌ Limited
RBAC✅ Fine-grained⚠️ Basic⚠️ Basic
Sync Waves✅ Yes⚠️ Limited❌ No
Community15k+ stars6k+ stars4k+ stars

Installing ArgoCD

Quick Installation

# Create namespace
kubectl create namespace argocd

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

# Wait for pods
kubectl wait --for=condition=Ready pods --all -n argocd --timeout=300s

Access the UI

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

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

Core Concepts

Applications

An Application defines the source repository and target cluster:

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

ApplicationSets

For managing multiple environments or clusters:

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: my-app-set
  namespace: argocd
spec:
  generators:
    - list:
        elements:
          - cluster: production
            url: https://prod.k8s.example.com
          - cluster: staging
            url: https://staging.k8s.example.com
  template:
    metadata:
      name: 'my-app-'
    spec:
      project: default
      source:
        repoURL: https://github.com/org/my-app-config
        targetRevision: main
        path: 'kubernetes/overlays/'
      destination:
        server: ''
        namespace: my-app

Kubernetes Cluster Photo by Luke Chesser on Unsplash

Repository Structure Best Practices

Monorepo Approach

├── apps/
│   ├── frontend/
│   │   ├── base/
│   │   │   ├── deployment.yaml
│   │   │   ├── service.yaml
│   │   │   └── kustomization.yaml
│   │   └── overlays/
│   │       ├── development/
│   │       ├── staging/
│   │       └── production/
│   └── backend/
│       ├── base/
│       └── overlays/
├── infrastructure/
│   ├── cert-manager/
│   ├── ingress-nginx/
│   └── monitoring/
└── argocd/
    ├── applications/
    └── projects/

Helm with ArgoCD

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: prometheus
  namespace: argocd
spec:
  source:
    repoURL: https://prometheus-community.github.io/helm-charts
    chart: kube-prometheus-stack
    targetRevision: 55.5.0
    helm:
      releaseName: prometheus
      values: |
        grafana:
          enabled: true
          adminPassword: ${GRAFANA_PASSWORD}
        prometheus:
          prometheusSpec:
            retention: 30d
            storageSpec:
              volumeClaimTemplate:
                spec:
                  resources:
                    requests:
                      storage: 50Gi
  destination:
    server: https://kubernetes.default.svc
    namespace: monitoring

Advanced Patterns

Sync Waves and Hooks

Control deployment order:

apiVersion: v1
kind: Namespace
metadata:
  name: my-app
  annotations:
    argocd.argoproj.io/sync-wave: "-1"
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: database
  annotations:
    argocd.argoproj.io/sync-wave: "0"
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: backend
  annotations:
    argocd.argoproj.io/sync-wave: "1"
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: frontend
  annotations:
    argocd.argoproj.io/sync-wave: "2"

Pre/Post Sync Hooks

apiVersion: batch/v1
kind: Job
metadata:
  name: db-migration
  annotations:
    argocd.argoproj.io/hook: PreSync
    argocd.argoproj.io/hook-delete-policy: HookSucceeded
spec:
  template:
    spec:
      containers:
        - name: migrate
          image: my-app:latest
          command: ["./migrate.sh"]
      restartPolicy: Never

Multi-Cluster Management

# Add external cluster
argocd cluster add my-external-cluster --name production

# Application targeting external cluster
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: production-app
spec:
  destination:
    server: https://production.k8s.example.com
    namespace: default

Security Best Practices

RBAC Configuration

apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-rbac-cm
  namespace: argocd
data:
  policy.csv: |
    # Developers can sync apps in dev namespace
    p, role:developer, applications, get, */*, allow
    p, role:developer, applications, sync, dev/*, allow
    
    # SRE team has full access
    p, role:sre, applications, *, */*, allow
    p, role:sre, clusters, *, *, allow
    
    # Bind groups to roles
    g, dev-team, role:developer
    g, sre-team, role:sre
  policy.default: role:readonly

Secret Management with External Secrets

apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: my-app-secrets
spec:
  refreshInterval: 1h
  secretStoreRef:
    kind: ClusterSecretStore
    name: aws-secrets-manager
  target:
    name: my-app-secrets
  data:
    - secretKey: DATABASE_URL
      remoteRef:
        key: my-app/production
        property: database_url

Monitoring ArgoCD

Prometheus Metrics

apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: argocd-metrics
  namespace: argocd
spec:
  selector:
    matchLabels:
      app.kubernetes.io/name: argocd-server
  endpoints:
    - port: metrics

Key Metrics to Monitor

# Sync status
argocd_app_info{sync_status="OutOfSync"}

# Health status
argocd_app_info{health_status!="Healthy"}

# Sync duration
histogram_quantile(0.95, argocd_app_sync_duration_seconds_bucket)

# API server requests
rate(argocd_app_reconcile_count[5m])

CI/CD Integration

GitHub Actions Workflow

name: Deploy to Production

on:
  push:
    branches: [main]
    paths:
      - 'kubernetes/**'

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Install ArgoCD CLI
        run: |
          curl -sSL -o argocd https://github.com/argoproj/argo-cd/releases/latest/download/argocd-linux-amd64
          chmod +x argocd
          sudo mv argocd /usr/local/bin/
      
      - name: Sync Application
        run: |
          argocd login $ \
            --username admin \
            --password $ \
            --insecure
          
          argocd app sync my-app --prune
          argocd app wait my-app --health

Troubleshooting Common Issues

Application Stuck in Progressing

# Check sync status
argocd app get my-app

# View detailed sync result
argocd app sync my-app --dry-run

# Force refresh
argocd app get my-app --hard-refresh

Resource Tracking Issues

# Add tracking annotation
metadata:
  annotations:
    argocd.argoproj.io/tracking-id: my-app:apps/Deployment:my-namespace/my-deployment

Conclusion

GitOps with ArgoCD provides a robust, scalable approach to Kubernetes deployment automation. By treating Git as the single source of truth, teams gain:

  • Complete audit trail of all changes
  • Easy rollbacks via git revert
  • Self-healing infrastructure that corrects drift
  • Developer-friendly workflows using familiar Git operations

Start small with a single application, then expand to manage your entire infrastructure declaratively.


Have questions about ArgoCD? Drop them in the comments!

이 글이 도움이 되셨다면 공감 및 광고 클릭을 부탁드립니다 :)