Container Orchestration advanced ⏱ 75 minutes

ArgoCD: GitOps for Your Homelab Kubernetes

Declarative GitOps continuous delivery. Manage Kubernetes applications through Git with automatic sync.

By homelabbing.io • 2025-12-16
#argocd#gitops#kubernetes#devops#ci-cd

Overview

ArgoCD is a declarative, GitOps continuous delivery tool for Kubernetes that transforms Git repositories into the single source of truth for your infrastructure. Instead of manually running kubectl apply commands, ArgoCD continuously monitors your Git repository and automatically synchronizes the desired state (what’s in Git) with the actual state (what’s running in your cluster).

For homelabbers managing Kubernetes clusters, ArgoCD provides an enterprise-grade workflow that eliminates configuration drift, enables one-click rollbacks, and creates a complete audit trail of all infrastructure changes. Every deployment is tracked in Git history, every change is reviewable through pull requests, and your entire Kubernetes state is version-controlled and reproducible.

What you’ll learn:

  • Install and configure ArgoCD on Kubernetes (k0s, K3s, or any distribution)
  • Understand GitOps principles and workflow
  • Deploy applications from Git repositories
  • Configure sync policies (automatic vs. manual)
  • Manage multi-environment deployments (dev, staging, production)
  • Implement Helm chart deployments via ArgoCD
  • Handle secrets management securely
  • Set up multi-cluster management from single ArgoCD instance
  • Troubleshoot common ArgoCD sync issues

Why ArgoCD?

Instead of SSHing into servers and running deployment commands (imperative), you push changes to Git, and ArgoCD ensures your cluster matches (declarative). This paradigm shift brings:

  • Single source of truth: Git is the authority
  • Audit trail: Every change is a Git commit
  • Easy rollback: Revert Git commit to rollback deployment
  • Disaster recovery: Recreate entire cluster from Git
  • Team collaboration: Code review for infrastructure changes

Prerequisites

Before starting, ensure you have:

  • Running Kubernetes cluster (k0s, K3s, K8s, or any CNCF-conformant)
    • Minimum 2 GB RAM available
    • Minimum 2 CPU cores available
    • Cluster admin access (for ArgoCD installation)
  • kubectl configured to access your cluster
  • Git repository (GitHub, GitLab, Gitea, or any Git server)
    • Public or private repository access
    • SSH keys or personal access tokens for private repos
  • Basic Kubernetes knowledge:
    • Deployments, Services, ConfigMaps
    • Namespaces and RBAC
    • Helm charts (helpful but not required)
  • Understanding of Git:
    • Commits, branches, pull requests
    • Repository management

Recommended cluster:

  • k0s or K3s single-node or multi-node cluster
  • Ingress controller installed (nginx-ingress, Traefik)
  • Storage provisioner configured (OpenEBS, local-path)

If you don’t have a cluster yet, follow our k0s guide or K3s guide first.


Understanding GitOps and ArgoCD

What is GitOps?

GitOps is a paradigm where:

  1. Git is the source of truth: All infrastructure configuration lives in Git
  2. Declarative state: You declare “what you want,” not “how to get there”
  3. Automated convergence: Tools (like ArgoCD) ensure reality matches Git
  4. Pull-based deployment: Cluster pulls changes, not pushed from CI/CD

Traditional deployment:

Developer → CI/CD Pipeline → kubectl apply → Kubernetes
           (push-based)

GitOps deployment:

Developer → Git Repository ← ArgoCD → Kubernetes
           (pull-based)     (monitors & syncs)

Core GitOps Principles

  1. Declarative: Entire system described declaratively
  2. Versioned: Canonical state version-controlled in Git
  3. Immutable: Desired state stored in immutable commits
  4. Pulled automatically: Software agents pull desired state from Git
  5. Continuously reconciled: Agents ensure reality matches desired state

ArgoCD Architecture

┌─────────────────────────────────────────────────────┐
│                  Git Repository                     │
│  (Single Source of Truth)                           │
│  ├── app-1/                                         │
│  │   └── deployment.yaml                            │
│  ├── app-2/                                         │
│  │   └── helm-chart/                                │
│  └── app-3/                                         │
│      └── kustomize/                                 │
└────────────────┬────────────────────────────────────┘
                 │
                 │ (monitors for changes)
                 ↓
┌─────────────────────────────────────────────────────┐
│              ArgoCD Components                      │
│  ├── API Server (Web UI + API)                     │
│  ├── Repository Server (Git interaction)           │
│  ├── Application Controller (Sync logic)           │
│  └── Redis (Cache)                                  │
└────────────────┬────────────────────────────────────┘
                 │
                 │ (applies changes via kubectl)
                 ↓
┌─────────────────────────────────────────────────────┐
│           Kubernetes Cluster                        │
│  ├── Namespace: app-1                              │
│  ├── Namespace: app-2                              │
│  └── Namespace: app-3                              │
└─────────────────────────────────────────────────────┘

Components:

  • API Server: Exposes Web UI and API, handles authentication
  • Repository Server: Clones and caches Git repositories
  • Application Controller: Monitors applications, compares Git vs. cluster state
  • Redis: Caches repository data for performance

Installation and Initial Setup

Step 1: Create ArgoCD namespace

# Create namespace
kubectl create namespace argocd

# Verify
kubectl get namespace argocd

Step 2: Install ArgoCD

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

# Wait for pods to be ready (may take 2-3 minutes)
kubectl wait --for=condition=ready pod --all -n argocd --timeout=300s

# Verify installation
kubectl get pods -n argocd

# Expected output:
# NAME                                 READY   STATUS    RESTARTS   AGE
# argocd-application-controller-0      1/1     Running   0          2m
# argocd-dex-server-xxx                1/1     Running   0          2m
# argocd-redis-xxx                     1/1     Running   0          2m
# argocd-repo-server-xxx               1/1     Running   0          2m
# argocd-server-xxx                    1/1     Running   0          2m

Step 3: Access ArgoCD UI

Option A: Port Forward (Quick Access)

# Forward ArgoCD server port to localhost
kubectl port-forward svc/argocd-server -n argocd 8080:443

# Access UI at: https://localhost:8080
# (Accept self-signed certificate warning)

Option B: Ingress (Production Access)

# argocd-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: argocd-server
  namespace: argocd
  annotations:
    nginx.ingress.kubernetes.io/ssl-passthrough: "true"
    nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
spec:
  ingressClassName: nginx
  rules:
  - host: argocd.homelab.local
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: argocd-server
            port:
              number: 443
  tls:
  - hosts:
    - argocd.homelab.local
    secretName: argocd-server-tls
# Apply ingress
kubectl apply -f argocd-ingress.yaml

# Add to /etc/hosts
echo "192.168.1.10 argocd.homelab.local" | sudo tee -a /etc/hosts

# Access at: https://argocd.homelab.local

Step 4: Get initial admin password

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

# Output: random-generated-password

# Login to ArgoCD:
# Username: admin
# Password: <output-from-above-command>

Step 5: Change admin password (recommended)

# Install ArgoCD CLI
curl -sSL -o argocd-linux-amd64 https://github.com/argoproj/argo-cd/releases/latest/download/argocd-linux-amd64
sudo install -m 555 argocd-linux-amd64 /usr/local/bin/argocd
rm argocd-linux-amd64

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

# Update password
argocd account update-password

# Delete initial secret (optional, for security)
kubectl -n argocd delete secret argocd-initial-admin-secret

Creating Your First GitOps Repository

Repository Structure

Create a Git repository with this structure:

homelab-gitops/
├── apps/
│   ├── nginx/
│   │   ├── deployment.yaml
│   │   ├── service.yaml
│   │   └── ingress.yaml
│   ├── postgres/
│   │   └── statefulset.yaml
│   └── wordpress/
│       └── helm-chart/
├── infrastructure/
│   ├── namespaces/
│   │   └── namespaces.yaml
│   └── ingress-nginx/
│       └── values.yaml
└── README.md

Example Application: Nginx

Create apps/nginx/deployment.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
  namespace: default
  labels:
    app: nginx
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.25-alpine
        ports:
        - containerPort: 80
        resources:
          requests:
            memory: "64Mi"
            cpu: "100m"
          limits:
            memory: "128Mi"
            cpu: "200m"

Create apps/nginx/service.yaml:

apiVersion: v1
kind: Service
metadata:
  name: nginx
  namespace: default
spec:
  selector:
    app: nginx
  ports:
  - port: 80
    targetPort: 80
  type: ClusterIP

Create apps/nginx/ingress.yaml:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: nginx
  namespace: default
spec:
  ingressClassName: nginx
  rules:
  - host: nginx.homelab.local
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: nginx
            port:
              number: 80

Push to Git:

cd homelab-gitops
git init
git add .
git commit -m "Add nginx application"
git remote add origin https://github.com/yourusername/homelab-gitops.git
git push -u origin main

Deploying Applications with ArgoCD

Method 1: Web UI

Step 1: Create new application

  1. Login to ArgoCD UI
  2. Click ”+ New App” button
  3. Fill in application details:

General:

  • Application Name: nginx
  • Project: default
  • Sync Policy: Manual (change to automatic later)

Source:

  • Repository URL: https://github.com/yourusername/homelab-gitops
  • Revision: HEAD (or specific branch/tag)
  • Path: apps/nginx

Destination:

  • Cluster URL: https://kubernetes.default.svc (in-cluster)
  • Namespace: default
  1. Click “Create”

Step 2: Sync application

  1. Click on the nginx application
  2. Click “Sync” button
  3. Review changes
  4. Click “Synchronize”

ArgoCD will apply all YAML files in apps/nginx/ to your cluster.

Step 3: Verify deployment

# Check pods
kubectl get pods -l app=nginx

# Check service
kubectl get svc nginx

# Check ingress
kubectl get ingress nginx

# Test application
curl http://nginx.homelab.local

Method 2: ArgoCD CLI

# Create application via CLI
argocd app create nginx   --repo https://github.com/yourusername/homelab-gitops   --path apps/nginx   --dest-server https://kubernetes.default.svc   --dest-namespace default   --sync-policy manual

# List applications
argocd app list

# Get application details
argocd app get nginx

# Sync application
argocd app sync nginx

# Watch sync progress
argocd app wait nginx --health

Method 3: Declarative (GitOps for ArgoCD itself!)

Create argocd-apps/nginx-app.yaml:

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: nginx
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/yourusername/homelab-gitops
    targetRevision: HEAD
    path: apps/nginx
  destination:
    server: https://kubernetes.default.svc
    namespace: default
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
    - CreateNamespace=true
# Apply ArgoCD application
kubectl apply -f argocd-apps/nginx-app.yaml

# ArgoCD will automatically sync

Sync Policies and Automation

Manual Sync vs. Automatic Sync

Manual Sync:

  • Changes in Git don’t automatically deploy
  • Requires manual “Sync” button click or CLI command
  • Good for: Production environments, critical applications

Automatic Sync:

  • ArgoCD polls Git (default: every 3 minutes)
  • Automatically syncs when changes detected
  • Good for: Development environments, infrastructure

Configuring Automatic Sync

Via Web UI:

  1. Click application → App Details
  2. Click “Edit”
  3. Under Sync Policy, select “Automatic”
  4. Enable options:
    • Prune Resources: Delete resources removed from Git
    • Self Heal: Revert manual changes to Git state

Via YAML:

spec:
  syncPolicy:
    automated:
      prune: true      # Delete resources not in Git
      selfHeal: true   # Revert manual kubectl changes
    syncOptions:
    - CreateNamespace=true  # Auto-create namespace if missing

Via CLI:

# Enable automatic sync
argocd app set nginx --sync-policy automated

# Enable pruning
argocd app set nginx --auto-prune

# Enable self-healing
argocd app set nginx --self-heal

Sync Windows (Scheduled Deployments)

Restrict syncing to specific time windows:

spec:
  syncPolicy:
    syncOptions:
    - CreateNamespace=true
    automated:
      prune: true
      selfHeal: true
    # Only sync during maintenance windows
    syncWindows:
    - kind: allow
      schedule: '0 2 * * *'  # Daily at 2 AM
      duration: 1h
      applications:
      - nginx

Working with Helm Charts

ArgoCD natively supports Helm charts without requiring Helm CLI.

Deploying Helm Chart from Git

Repository structure:

homelab-gitops/
└── apps/
    └── wordpress/
        ├── Chart.yaml
        ├── values.yaml
        └── templates/
            ├── deployment.yaml
            └── service.yaml

ArgoCD Application:

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: wordpress
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/yourusername/homelab-gitops
    targetRevision: HEAD
    path: apps/wordpress
    helm:
      valueFiles:
      - values.yaml
      parameters:
      - name: replicaCount
        value: "2"
  destination:
    server: https://kubernetes.default.svc
    namespace: wordpress
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
    - CreateNamespace=true

Deploying from Helm Repository

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: grafana
  namespace: argocd
spec:
  project: default
  source:
    chart: grafana
    repoURL: https://grafana.github.io/helm-charts
    targetRevision: 6.50.0
    helm:
      values: |
        adminPassword: admin
        persistence:
          enabled: true
          size: 5Gi
        ingress:
          enabled: true
          hosts:
            - grafana.homelab.local
  destination:
    server: https://kubernetes.default.svc
    namespace: monitoring
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
    - CreateNamespace=true
kubectl apply -f grafana-app.yaml

Managing Secrets with ArgoCD

Problem: Secrets in Git

Never commit secrets in plain text to Git!

# BAD - Secret exposed in Git
apiVersion: v1
kind: Secret
metadata:
  name: db-password
data:
  password: bXlzZWNyZXRwYXNzd29yZA==  # base64 is NOT encryption!

Solution 1: Sealed Secrets

Install Sealed Secrets controller:

# Install Sealed Secrets
kubectl apply -f https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.24.0/controller.yaml

# Install kubeseal CLI
curl -L https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.24.0/kubeseal-0.24.0-linux-amd64.tar.gz | tar xz
sudo install -m 755 kubeseal /usr/local/bin/kubeseal

Create sealed secret:

# Create regular secret (not applied)
kubectl create secret generic db-password   --from-literal=password=supersecret   --dry-run=client -o yaml > secret.yaml

# Seal the secret
kubeseal -f secret.yaml -w sealed-secret.yaml

# Now sealed-secret.yaml can be committed to Git
cat sealed-secret.yaml
# sealed-secret.yaml (safe to commit)
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
  name: db-password
spec:
  encryptedData:
    password: AgBy3i4OJSWK+PiTySYZZA9rO43cGDEq...  # Encrypted

Commit to Git:

git add sealed-secret.yaml
git commit -m "Add sealed database password"
git push

ArgoCD syncs the SealedSecret, and the controller decrypts it into a regular Secret.

Solution 2: External Secrets Operator

Install External Secrets Operator:

helm repo add external-secrets https://charts.external-secrets.io
helm install external-secrets external-secrets/external-secrets -n external-secrets-system --create-namespace

Configure secret store (e.g., Vault, AWS Secrets Manager):

apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
  name: vault-backend
spec:
  provider:
    vault:
      server: "http://vault.default.svc.cluster.local:8200"
      path: "secret"
      version: "v2"
      auth:
        kubernetes:
          mountPath: "kubernetes"
          role: "argocd"

Reference external secret:

apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: db-password
spec:
  refreshInterval: 1h
  secretStoreRef:
    name: vault-backend
    kind: SecretStore
  target:
    name: db-password
  data:
  - secretKey: password
    remoteRef:
      key: database/postgres
      property: password

Solution 3: Git-Crypt (Simple Encryption)

# Install git-crypt
sudo apt install git-crypt

# Initialize encryption in repo
cd homelab-gitops
git-crypt init

# Add secret files to .gitattributes
echo "secrets/*.yaml filter=git-crypt diff=git-crypt" >> .gitattributes

# Now secrets/*.yaml files are encrypted in Git

Multi-Environment Management

Directory Structure for Environments

homelab-gitops/
├── base/
│   └── nginx/
│       ├── deployment.yaml
│       ├── service.yaml
│       └── kustomization.yaml
└── overlays/
    ├── dev/
    │   ├── kustomization.yaml
    │   └── patch-replicas.yaml
    ├── staging/
    │   ├── kustomization.yaml
    │   └── patch-replicas.yaml
    └── production/
        ├── kustomization.yaml
        ├── patch-replicas.yaml
        └── patch-resources.yaml

base/nginx/kustomization.yaml:

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml
- service.yaml

overlays/production/kustomization.yaml:

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
bases:
- ../../base/nginx
patches:
- patch-replicas.yaml
- patch-resources.yaml
namespace: production

overlays/production/patch-replicas.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  replicas: 5  # Production uses 5 replicas

ArgoCD Applications (one per environment):

# production-nginx.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: nginx-production
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/yourusername/homelab-gitops
    targetRevision: main
    path: overlays/production
  destination:
    server: https://kubernetes.default.svc
    namespace: production
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
# dev-nginx.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: nginx-dev
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/yourusername/homelab-gitops
    targetRevision: develop  # Different branch
    path: overlays/dev
  destination:
    server: https://kubernetes.default.svc
    namespace: dev
  syncPolicy:
    automated:
      prune: true
      selfHeal: true

Multi-Cluster Management

Adding External Cluster

Step 1: Get external cluster credentials

# List clusters in kubeconfig
kubectl config get-contexts

# Add cluster to ArgoCD
argocd cluster add k3s-cluster --name production-cluster

# List registered clusters
argocd cluster list

Step 2: Deploy to external cluster

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: nginx-remote
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/yourusername/homelab-gitops
    targetRevision: HEAD
    path: apps/nginx
  destination:
    name: production-cluster  # External cluster
    namespace: default
  syncPolicy:
    automated:
      prune: true
      selfHeal: true

App of Apps Pattern

Manage multiple applications with one application:

Create apps/applications.yaml:

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: nginx
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/yourusername/homelab-gitops
    targetRevision: HEAD
    path: apps/nginx
  destination:
    server: https://kubernetes.default.svc
    namespace: default
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
---
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: postgres
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/yourusername/homelab-gitops
    targetRevision: HEAD
    path: apps/postgres
  destination:
    server: https://kubernetes.default.svc
    namespace: databases
  syncPolicy:
    automated:
      prune: true
      selfHeal: true

Create root app:

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: root-app
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/yourusername/homelab-gitops
    targetRevision: HEAD
    path: apps
  destination:
    server: https://kubernetes.default.svc
    namespace: argocd
  syncPolicy:
    automated:
      prune: true
      selfHeal: true

Now managing root-app manages all child applications!


Troubleshooting Common Issues

Issue: Application Stuck in “Progressing”

# Get application status
argocd app get <app-name>

# Check sync operation details
argocd app get <app-name> --show-operation

# Describe application in Kubernetes
kubectl describe application <app-name> -n argocd

# Common causes:
# 1. Resource quota exceeded
# 2. Image pull errors
# 3. Invalid YAML syntax

Issue: “OutOfSync” Status

Symptom: Application shows OutOfSync even after sync

Solutions:

# 1. Check for manual changes
kubectl get deployment nginx -o yaml

# 2. Force hard refresh
argocd app get <app-name> --hard-refresh

# 3. Ignore specific fields
# Add to Application spec:
spec:
  ignoreDifferences:
  - group: apps
    kind: Deployment
    jsonPointers:
    - /spec/replicas  # Ignore replica count differences

Issue: Git Repository Connection Failed

# Test repository connectivity
argocd repo add https://github.com/yourusername/homelab-gitops

# For private repositories, add SSH key or token
argocd repo add [email protected]:yourusername/homelab-gitops.git   --ssh-private-key-path ~/.ssh/id_rsa

# Or use HTTPS with token
argocd repo add https://github.com/yourusername/homelab-gitops.git   --username yourusername   --password ghp_yourtoken

Issue: Sync Loops (Continuous Resyncing)

Symptom: Application syncs repeatedly without settling

Solutions:

# Add ignoreDifferences for auto-generated fields
spec:
  ignoreDifferences:
  - group: "*"
    kind: "*"
    jsonPointers:
    - /metadata/annotations/deployment.kubernetes.io~1revision
    - /metadata/managedFields

Issue: Permission Denied

# Check ArgoCD RBAC
kubectl get clusterrole argocd-server -o yaml

# Grant additional permissions
kubectl edit clusterrolebinding argocd-application-controller

Best Practices for Homelab GitOps

1. Separate Git Repositories

├── homelab-apps/          # Application manifests
├── homelab-infrastructure/ # Infrastructure (ingress, storage)
└── homelab-argocd/        # ArgoCD applications (app of apps)

2. Use Environments with Branches/Directories

Option A: Branch per environment

  • main → production
  • staging → staging
  • develop → development

Option B: Directory per environment (recommended)

overlays/
├── dev/
├── staging/
└── production/

3. Enable Notifications

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

# Configure Slack webhook
apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-notifications-cm
data:
  service.slack: |
    token: xoxb-your-slack-token
  template.app-deployed: |
    message: Application {{.app.metadata.name}} deployed to {{.app.spec.destination.namespace}}
  trigger.on-deployed: |
    - when: app.status.operationState.phase in ['Succeeded']
      send: [app-deployed]

4. Implement Progressive Delivery

Use Argo Rollouts for canary deployments:

kubectl create namespace argo-rollouts
kubectl apply -n argo-rollouts -f https://github.com/argoproj/argo-rollouts/releases/latest/download/install.yaml
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: nginx-rollout
spec:
  replicas: 5
  strategy:
    canary:
      steps:
      - setWeight: 20
      - pause: {duration: 1m}
      - setWeight: 40
      - pause: {duration: 1m}
      - setWeight: 60
      - pause: {duration: 1m}
      - setWeight: 80
      - pause: {duration: 1m}
  template:
    spec:
      containers:
      - name: nginx
        image: nginx:1.25

5. Regular Backups

# Backup ArgoCD configuration
kubectl get applications -n argocd -o yaml > argocd-apps-backup.yaml
kubectl get appprojects -n argocd -o yaml > argocd-projects-backup.yaml

# Since everything is in Git, cluster rebuild is:
# 1. Deploy ArgoCD
# 2. Apply root application
# 3. Wait for sync

Conclusion and Next Steps

ArgoCD brings enterprise-grade GitOps to your homelab, transforming Git into the single source of truth for your Kubernetes infrastructure. By automating synchronization between Git and your cluster, ArgoCD eliminates configuration drift, enables instant rollbacks, and creates a complete audit trail of all changes.

Key Takeaways

  • GitOps paradigm: Git is the source of truth
  • Declarative: Describe desired state, not imperative steps
  • Automated sync: Pull-based deployment from Git
  • Multi-environment: Manage dev, staging, production from one repo
  • Multi-cluster: Control multiple clusters from single ArgoCD
  • Helm support: Native Helm chart deployment
  • Audit trail: Every change tracked in Git history

When to Use ArgoCD

Perfect for:

  • Kubernetes-based homelabs (k0s, K3s, K8s)
  • Teams managing multiple environments
  • Infrastructure-as-code workflows
  • Compliance and audit requirements
  • Multi-cluster management
  • Advanced deployment strategies (canary, blue-green)

Consider alternatives if:

  • Not using Kubernetes (use Ansible, Docker Compose)
  • Single-container deployments (use Portainer, Dockge)
  • Maximum simplicity preferred (kubectl apply works fine)
  1. Set up Git repository with organized structure
  2. Install ArgoCD on Kubernetes cluster
  3. Create first application (manual sync)
  4. Test sync process with small changes
  5. Enable automatic sync for non-critical apps
  6. Implement secrets management (Sealed Secrets)
  7. Add notifications (Slack, Discord, email)
  8. Expand to multi-environment (dev, staging, prod)

Next Steps

Beginner:

  1. Install ArgoCD on k0s/K3s cluster
  2. Create Git repository with sample app
  3. Deploy application via ArgoCD UI
  4. Make change in Git, observe auto-sync

Intermediate:

  1. Set up multi-environment with Kustomize
  2. Implement Sealed Secrets
  3. Configure automatic sync with self-heal
  4. Deploy Helm charts via ArgoCD

Advanced:

  1. Implement app-of-apps pattern
  2. Set up multi-cluster management
  3. Configure Argo Rollouts (progressive delivery)
  4. Integrate with CI/CD pipeline
  5. Implement RBAC and SSO

Resources


Document Version: 1.0 Last Updated: December 16, 2024 Based on: ArgoCD v2.9+ Estimated Completion Time: 90 minutes (basic setup), 12-16 hours (production GitOps workflow)

Happy GitOps-ing!