GitOps Workflow ArgoCD
GitOps mit ArgoCD
GitOps nutzt Git als Single Source of Truth für Infrastructure und Deployments. Lernen Sie ArgoCD für Kubernetes-Deployments einzurichten und zu nutzen.
Was ist GitOps?
┌─────────────────────────────────────────────────────────────┐ │ GITOPS WORKFLOW │ ├─────────────────────────────────────────────────────────────┤ │ │ │ 1. Developer pushed Code │ │ ┌─────────┐ │ │ │ Git │ ← Application Code │ │ │ Repo │ │ │ └────┬────┘ │ │ │ Trigger │ │ ▼ │ │ ┌─────────┐ │ │ │ CI │ Build → Test → Push Image │ │ │Pipeline │ │ │ └────┬────┘ │ │ │ Update Image Tag │ │ ▼ │ │ ┌─────────┐ │ │ │ GitOps │ ← Kubernetes Manifests (Desired State) │ │ │ Repo │ │ │ └────┬────┘ │ │ │ Sync (Pull) │ │ ▼ │ │ ┌─────────┐ ┌────────────┐ │ │ │ ArgoCD │─────►│ Kubernetes │ (Actual State) │ │ │ │ │ Cluster │ │ │ └─────────┘ └────────────┘ │ │ │ │ ArgoCD vergleicht kontinuierlich: │ │ Desired State (Git) ↔ Actual State (Cluster) │ │ │ └─────────────────────────────────────────────────────────────┘
GitOps Prinzipien
| Prinzip | Beschreibung |
|---|---|
| Declarative | Gesamtes System in Git beschrieben |
| Versioned | Alle Änderungen sind versioniert (Git History) |
| Automated | Änderungen werden automatisch angewendet |
| Auditable | Wer hat was wann geändert (Git Log) |
ArgoCD Installation
# ArgoCD im Cluster installieren
kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
# Warten bis Ready
kubectl wait --for=condition=available deployment/argocd-server -n argocd --timeout=300s
# ArgoCD CLI installieren (macOS)
brew install argocd
# Admin Passwort abrufen
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d
# Port-Forward zur UI
kubectl port-forward svc/argocd-server -n argocd 8080:443
# Login via CLI
argocd login localhost:8080 --username admin --password
GitOps Repository Struktur
gitops-repo/
├── apps/ # Application Definitions
│ ├── production/
│ │ ├── frontend.yaml
│ │ ├── backend.yaml
│ │ └── database.yaml
│ └── staging/
│ ├── frontend.yaml
│ ├── backend.yaml
│ └── database.yaml
│
├── base/ # Basis-Manifests (Kustomize)
│ ├── frontend/
│ │ ├── deployment.yaml
│ │ ├── service.yaml
│ │ └── kustomization.yaml
│ └── backend/
│ ├── deployment.yaml
│ ├── service.yaml
│ └── kustomization.yaml
│
├── overlays/ # Environment-spezifische Overrides
│ ├── production/
│ │ ├── frontend/
│ │ │ ├── kustomization.yaml
│ │ │ └── replicas-patch.yaml
│ │ └── backend/
│ │ └── kustomization.yaml
│ └── staging/
│ ├── frontend/
│ │ └── kustomization.yaml
│ └── backend/
│ └── kustomization.yaml
│
└── argocd/ # ArgoCD Konfiguration
├── projects/
│ └── myapp.yaml
└── applicationsets/
└── myapp-set.yaml
ArgoCD Application erstellen
# apps/production/backend.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: backend-production
namespace: argocd
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
project: default
source:
repoURL: https://github.com/myorg/gitops-repo.git
targetRevision: main
path: overlays/production/backend
destination:
server: https://kubernetes.default.svc
namespace: production
syncPolicy:
automated:
prune: true # Entferne Ressourcen die nicht mehr in Git sind
selfHeal: true # Repariere manuelle Änderungen am Cluster
allowEmpty: false
syncOptions:
- CreateNamespace=true
- PrunePropagationPolicy=foreground
retry:
limit: 5
backoff:
duration: 5s
factor: 2
maxDuration: 3m
Kustomize für Environments
# base/backend/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: backend
spec:
replicas: 1
selector:
matchLabels:
app: backend
template:
metadata:
labels:
app: backend
spec:
containers:
- name: backend
image: myapp/backend:latest
ports:
- containerPort: 8080
env:
- name: LOG_LEVEL
value: "info"
# base/backend/kustomization.yaml apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: - deployment.yaml - service.yaml
# overlays/production/backend/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../../base/backend
namespace: production
commonLabels:
environment: production
images:
- name: myapp/backend
newTag: v1.2.3 # Production Version
replicas:
- name: backend
count: 3 # Mehr Replicas in Production
patches:
- patch: |-
- op: replace
path: /spec/template/spec/containers/0/env/0/value
value: "warn"
target:
kind: Deployment
name: backend
ApplicationSet für Multi-Environment
# argocd/applicationsets/myapp-set.yaml
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: myapp
namespace: argocd
spec:
generators:
- list:
elements:
- env: staging
cluster: https://kubernetes.default.svc
replicas: "1"
- env: production
cluster: https://kubernetes.default.svc
replicas: "3"
template:
metadata:
name: 'backend-{{env}}'
spec:
project: default
source:
repoURL: https://github.com/myorg/gitops-repo.git
targetRevision: main
path: 'overlays/{{env}}/backend'
destination:
server: '{{cluster}}'
namespace: '{{env}}'
syncPolicy:
automated:
prune: true
selfHeal: true
CI/CD Integration
# .github/workflows/ci.yml (Application Repo)
name: CI
on:
push:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build and Push Docker Image
run: |
docker build -t myapp/backend:${{ github.sha }} .
docker push myapp/backend:${{ github.sha }}
- name: Update GitOps Repo
run: |
# GitOps Repo klonen
git clone https://x-access-token:${{ secrets.GITOPS_TOKEN }}@github.com/myorg/gitops-repo.git
cd gitops-repo
# Image Tag aktualisieren
cd overlays/staging/backend
kustomize edit set image myapp/backend:${{ github.sha }}
# Commit und Push
git config user.name "CI Bot"
git config user.email "ci@example.com"
git add .
git commit -m "Update backend image to ${{ github.sha }}"
git push
# Image Updater Alternative (automatisch)
# ArgoCD Image Updater überwacht Registry und updated automatisch
# argocd-image-updater Annotations
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: backend
annotations:
argocd-image-updater.argoproj.io/image-list: backend=myapp/backend
argocd-image-updater.argoproj.io/backend.update-strategy: semver
argocd-image-updater.argoproj.io/backend.allow-tags: regexp:^v\d+\.\d+\.\d+$
argocd-image-updater.argoproj.io/write-back-method: git
Sync Strategien
SYNC OPTIONEN
┌────────────────────┬─────────────────────────────────────────┐
│ automated.prune │ Entferne Ressourcen nicht mehr in Git │
├────────────────────┼─────────────────────────────────────────┤
│ automated.selfHeal │ Überschreibe manuelle Cluster-Änderungen│
├────────────────────┼─────────────────────────────────────────┤
│ syncOptions: │ │
│ - Validate=false │ Schema-Validierung überspringen │
│ - PruneLast=true │ Erst erstellen, dann alte löschen │
│ - ApplyOutOfSync │ Nur geänderte Ressourcen anwenden │
└────────────────────┴─────────────────────────────────────────┘
SYNC WAVES (Reihenfolge)
# Annotations für Sync-Reihenfolge
metadata:
annotations:
argocd.argoproj.io/sync-wave: "1" # Niedrigere Werte zuerst
# Beispiel:
# Wave -1: Namespace, ConfigMaps
# Wave 0: Deployments, Services
# Wave 1: Ingress
# Wave 2: Jobs, CronJobs
ArgoCD CLI Befehle
# Apps auflisten argocd app list # App Details argocd app get backend-production # Manueller Sync argocd app sync backend-production # Sync mit Prune argocd app sync backend-production --prune # Diff anzeigen (was würde sich ändern) argocd app diff backend-production # App History argocd app history backend-production # Rollback zu bestimmter Revision argocd app rollback backend-production 5 # App löschen argocd app delete backend-production # Logs einer App argocd app logs backend-production # Ressourcen einer App argocd app resources backend-production
Secrets Management
# Option 1: Sealed Secrets # Verschlüsselte Secrets in Git # kubeseal installieren brew install kubeseal # Secret verschlüsseln kubectl create secret generic db-credentials \ --from-literal=password=secret123 \ --dry-run=client -o yaml | \ kubeseal --format yaml > sealed-secret.yaml # sealed-secret.yaml kann sicher in Git committed werden
# Option 2: External Secrets Operator
# Secrets aus Vault, AWS Secrets Manager, etc.
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: db-credentials
spec:
refreshInterval: 1h
secretStoreRef:
kind: ClusterSecretStore
name: vault
target:
name: db-credentials
data:
- secretKey: password
remoteRef:
key: secret/data/database
property: password
💡 Best Practices:
1. Separates GitOps-Repo für Manifests (nicht im App-Repo)
2. Environment-Branches vermeiden, Kustomize Overlays nutzen
3. Automated Sync nur für nicht-kritische Environments
4. Sealed Secrets oder External Secrets für sensible Daten
5. ApplicationSets für konsistente Multi-Environment Setups
2. Environment-Branches vermeiden, Kustomize Overlays nutzen
3. Automated Sync nur für nicht-kritische Environments
4. Sealed Secrets oder External Secrets für sensible Daten
5. ApplicationSets für konsistente Multi-Environment Setups