Veröffentlicht am

ArgoCD Tutorial: GitOps für Kubernetes einrichten

Teilen:
Authors

TL;DR

  • ArgoCD synchronisiert Ihren Kubernetes-Cluster automatisch mit Git-Repositories und ermoeglicht deklarative GitOps-Deployments
  • Installation in wenigen Minuten via kubectl, mit UI, CLI und automatischer Synchronisation
  • Unterstuetzt Kustomize, Helm Charts, Multi-Cluster-Deployments und das App-of-Apps-Pattern
  • Sync-Waves und Hooks ermoeglichen kontrollierte Deployment-Reihenfolgen mit Pre-/PostSync-Jobs
  • Best Practices: Separate Repos fuer Code und Config, Image Updater, RBAC fuer Teams und Notifications

ArgoCD: GitOps für Kubernetes

ArgoCD ist der beliebteste GitOps-Controller für Kubernetes. Er synchronisiert Ihren Cluster automatisch mit Git - Änderungen am Repository werden automatisch deployed. In diesem Tutorial richten wir ArgoCD ein und deployen eine erste Anwendung.

Was ist GitOps?

┌──────────────┐     ┌──────────────┐     ┌──────────────┐
Git      │────▶│    ArgoCD    │────▶│  Kubernetes  (Source of  (Controller)   (Cluster)Truth)    │     │              │     │              │
└──────────────┘     └──────────────┘     └──────────────┘

Änderung im GitArgoCD erkennt DiffAutomatisches Deployment

Vorteile:

  • Git als Single Source of Truth
  • Automatische Deployments
  • Einfaches Rollback (git revert)
  • Audit-Trail durch Git-Historie
  • Keine kubectl-Zugriffe für Entwickler nötig

Teil 1: ArgoCD installieren

Quick Install

# Namespace erstellen
kubectl create namespace argocd

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

# Warten bis alle Pods laufen
kubectl wait --for=condition=Ready pods --all -n argocd --timeout=300s

Initial Password abrufen

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

Zugriff auf UI

Option A: Port-Forward (schnell, temporär)

kubectl port-forward svc/argocd-server -n argocd 8080:443
# Browser: https://localhost:8080
# User: admin
# Password: siehe oben

Option B: LoadBalancer (Production)

kubectl patch svc argocd-server -n argocd -p '{"spec": {"type": "LoadBalancer"}}'

Option C: Ingress (empfohlen)

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.example.de
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: argocd-server
            port:
              name: https
  tls:
  - hosts:
    - argocd.example.de
    secretName: argocd-tls

ArgoCD CLI installieren

# macOS
brew install argocd

# Linux
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/

# Login
argocd login localhost:8080

Teil 2: Repository verbinden

Öffentliches Repository

Kein Setup nötig - ArgoCD kann direkt darauf zugreifen.

Privates Repository (SSH)

# SSH Key als Secret hinzufügen
argocd repo add git@github.com:myorg/myapp.git \
  --ssh-private-key-path ~/.ssh/id_rsa

Oder deklarativ:

apiVersion: v1
kind: Secret
metadata:
  name: private-repo
  namespace: argocd
  labels:
    argocd.argoproj.io/secret-type: repository
stringData:
  type: git
  url: git@github.com:myorg/myapp.git
  sshPrivateKey: |
    -----BEGIN OPENSSH PRIVATE KEY-----
    ...
    -----END OPENSSH PRIVATE KEY-----

GitHub App (empfohlen für Organisationen)

apiVersion: v1
kind: Secret
metadata:
  name: github-app-repo
  namespace: argocd
  labels:
    argocd.argoproj.io/secret-type: repository
stringData:
  type: git
  url: https://github.com/myorg/myapp.git
  githubAppID: "12345"
  githubAppInstallationID: "67890"
  githubAppPrivateKey: |
    -----BEGIN RSA PRIVATE KEY-----
    ...
    -----END RSA PRIVATE KEY-----

Teil 3: Erste Application erstellen

Repository-Struktur

myapp-gitops/
├── apps/                    # ArgoCD Applications
│   ├── production.yaml
│   └── staging.yaml
├── base/                    # Basis-Manifeste
│   ├── deployment.yaml
│   ├── service.yaml
│   └── kustomization.yaml
└── overlays/               # Umgebungs-Overrides
    ├── production/
    │   ├── kustomization.yaml
    │   └── replicas-patch.yaml
    └── staging/
        └── kustomization.yaml

Basis-Manifeste

base/deployment.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
spec:
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
      - name: myapp
        image: myregistry/myapp:latest
        ports:
        - containerPort: 8080
        resources:
          requests:
            cpu: 100m
            memory: 128Mi
          limits:
            cpu: 200m
            memory: 256Mi

base/service.yaml:

apiVersion: v1
kind: Service
metadata:
  name: myapp
spec:
  selector:
    app: myapp
  ports:
  - port: 80
    targetPort: 8080

base/kustomization.yaml:

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

Production Overlay

overlays/production/kustomization.yaml:

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: production
resources:
  - ../../base
patches:
  - path: replicas-patch.yaml
images:
  - name: myregistry/myapp
    newTag: v1.2.3

overlays/production/replicas-patch.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
spec:
  replicas: 3

ArgoCD Application

apps/production.yaml:

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: myapp-production
  namespace: argocd
  finalizers:
    - resources-finalizer.argocd.argoproj.io
spec:
  project: default
  source:
    repoURL: https://github.com/myorg/myapp-gitops.git
    targetRevision: main
    path: overlays/production
  destination:
    server: https://kubernetes.default.svc
    namespace: production
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
      - CreateNamespace=true
      - PruneLast=true
    retry:
      limit: 5
      backoff:
        duration: 5s
        factor: 2
        maxDuration: 3m

Application deployen

# Via kubectl
kubectl apply -f apps/production.yaml

# Oder via CLI
argocd app create myapp-production \
  --repo https://github.com/myorg/myapp-gitops.git \
  --path overlays/production \
  --dest-server https://kubernetes.default.svc \
  --dest-namespace production \
  --sync-policy automated

Teil 4: Sync-Strategien

Manual Sync

spec:
  syncPolicy: {}  # Keine automatische Synchronisation
# Manuell synchronisieren
argocd app sync myapp-production

Automated Sync

spec:
  syncPolicy:
    automated:
      prune: true      # Löscht Ressourcen die nicht mehr in Git sind
      selfHeal: true   # Stellt Zustand wieder her bei manuellen Änderungen

Sync Waves

Kontrollierte Reihenfolge beim Deployment:

# ConfigMap zuerst
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
  annotations:
    argocd.argoproj.io/sync-wave: "-1"

---
# Dann Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
  annotations:
    argocd.argoproj.io/sync-wave: "0"

---
# Zuletzt Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: myapp
  annotations:
    argocd.argoproj.io/sync-wave: "1"

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: myapp:v1.2.3
        command: ["./migrate.sh"]
      restartPolicy: Never

Hook Types:

  • PreSync: Vor dem Sync
  • Sync: Während des Sync
  • PostSync: Nach erfolgreichem Sync
  • SyncFail: Nach fehlgeschlagenem Sync

Teil 5: App of Apps Pattern

Verwalten Sie alle Applications mit einer Meta-Application:

Struktur

argocd-apps/
├── apps.yaml           # Meta-Application
└── apps/
    ├── myapp-prod.yaml
    ├── myapp-staging.yaml
    ├── monitoring.yaml
    └── ingress.yaml

Meta-Application

apps.yaml:

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: applications
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/myorg/argocd-apps.git
    targetRevision: main
    path: apps
  destination:
    server: https://kubernetes.default.svc
    namespace: argocd
  syncPolicy:
    automated:
      prune: true
      selfHeal: true

Einzelne Applications

apps/monitoring.yaml:

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: monitoring
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://prometheus-community.github.io/helm-charts
    chart: kube-prometheus-stack
    targetRevision: 55.5.0
    helm:
      values: |
        grafana:
          adminPassword: admin123
        prometheus:
          retention: 7d
  destination:
    server: https://kubernetes.default.svc
    namespace: monitoring
  syncPolicy:
    automated:
      prune: true
    syncOptions:
      - CreateNamespace=true

Teil 6: Helm Charts mit ArgoCD

Helm Repository

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:
      releaseName: nginx-ingress
      values: |
        controller:
          replicaCount: 2
          service:
            type: LoadBalancer
  destination:
    server: https://kubernetes.default.svc
    namespace: ingress-nginx
  syncPolicy:
    automated:
      prune: true
    syncOptions:
      - CreateNamespace=true

Helm Chart aus Git

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: myapp
spec:
  source:
    repoURL: https://github.com/myorg/myapp.git
    path: helm/myapp
    targetRevision: main
    helm:
      valueFiles:
        - values-production.yaml
      parameters:
        - name: image.tag
          value: v1.2.3

Teil 7: Multi-Cluster Deployment

Cluster hinzufügen

# Cluster registrieren
argocd cluster add my-cluster-context

# Liste aller Cluster
argocd cluster list

Application auf Remote-Cluster

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: myapp-eu
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/myorg/myapp-gitops.git
    path: overlays/production
    targetRevision: main
  destination:
    server: https://my-eu-cluster.example.de:6443  # Remote Cluster
    namespace: production

ApplicationSet für Multi-Cluster

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: myapp
  namespace: argocd
spec:
  generators:
  - list:
      elements:
      - cluster: eu-west
        url: https://eu-west.k8s.example.de
      - cluster: us-east
        url: https://us-east.k8s.example.de
  template:
    metadata:
      name: 'myapp-{{cluster}}'
    spec:
      project: default
      source:
        repoURL: https://github.com/myorg/myapp-gitops.git
        targetRevision: main
        path: 'overlays/{{cluster}}'
      destination:
        server: '{{url}}'
        namespace: production

Teil 8: Best Practices

1. Separate Repos für Code und Config

myapp/              # Application Code
  ├── src/
  ├── Dockerfile
  └── .github/workflows/  # Build ImageUpdate GitOps Repo

myapp-gitops/       # Kubernetes Manifeste (ArgoCD watched hier)
  ├── base/
  └── overlays/

2. Image Updater für automatische Updates

# ArgoCD Image Updater installieren
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj-labs/argocd-image-updater/stable/manifests/install.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: myapp
  annotations:
    argocd-image-updater.argoproj.io/image-list: myapp=myregistry/myapp
    argocd-image-updater.argoproj.io/myapp.update-strategy: semver
    argocd-image-updater.argoproj.io/write-back-method: git

3. Notifications einrichten

# Slack Notification
apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-notifications-cm
  namespace: argocd
data:
  service.slack: |
    token: $slack-token
  template.app-sync-status: |
    message: |
      Application {{.app.metadata.name}} sync status: {{.app.status.sync.status}}
  trigger.on-sync-succeeded: |
    - when: app.status.sync.status == 'Synced'
      send: [app-sync-status]

4. RBAC für Teams

apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-rbac-cm
  namespace: argocd
data:
  policy.csv: |
    p, role:frontend-team, applications, get, frontend/*, allow
    p, role:frontend-team, applications, sync, frontend/*, allow
    g, frontend-developers, role:frontend-team
  policy.default: role:readonly

Troubleshooting

Application stuck in "Progressing"

# Events prüfen
argocd app get myapp --show-operation

# Ressourcen-Status
argocd app resources myapp

# Sync erzwingen
argocd app sync myapp --force

Sync failed

# Diff anzeigen
argocd app diff myapp

# Detaillierte Logs
argocd app logs myapp

# Hard Refresh
argocd app get myapp --hard-refresh

"OutOfSync" trotz korrektem Git-State

# Cache leeren
argocd app get myapp --refresh

# Ignorierte Felder prüfen
# Oft: metadata.resourceVersion, status, etc.

Zusammenfassung

AufgabeBefehl
App erstellenargocd app create
Sync startenargocd app sync myapp
Status prüfenargocd app get myapp
Diff anzeigenargocd app diff myapp
Rollbackargocd app rollback myapp
Logsargocd app logs myapp

Nächste Schritte

  1. Heute: ArgoCD installieren und erste Application erstellen
  2. Diese Woche: Bestehende Anwendungen auf GitOps migrieren
  3. Dieser Monat: App of Apps Pattern implementieren

Weiterführende Artikel:


GitOps klingt gut, aber Sie haben keine Zeit für den Aufbau? Als Managed Service Partner implementieren wir ArgoCD für Sie - inklusive Best Practices, Monitoring und Support.

Kubernetes-Beratung gesucht?

Wir helfen deutschen Unternehmen bei der Kubernetes-Implementierung, Migration und Optimierung. DSGVO-konform und praxiserprobt.

📖 Verwandte Artikel

Weitere interessante Beiträge zu ähnlichen Themen