Praxisbeispiele und Anwendungsfälle

In dieser praxisorientierten Lerneinheit setzt du eine vollständige CI/CD-Pipeline mit Jenkins auf und lernst dabei die wichtigsten Automatisierungsschritte kennen. Du erfährst anhand konkreter Beispiele, wie Build-Prozesse, Tests und Deployments in der Pipeline automatisiert werden und wie du typische Herausforderungen bei der Implementierung meisterst. Die erworbenen Kenntnisse wendest du direkt in realistischen Szenarien an und kannst sie auf eigene Projekte übertragen.

Einführung

Du hast in den vorherigen Lerneinheiten gelernt, wie Build-Prozesse funktionieren, warum CI/CD wichtig ist und welche Tools es gibt. Jetzt wird es konkret.

Wie setzt du eine vollständige CI/CD-Pipeline auf? Wie automatisierst du das Deployment in die Cloud? Und wie bringst du deine App sicher in den App Store?

Theorie ist wichtig. Aber ohne Praxis bleibt sie abstrakt. In dieser Lerneinheit setzt du vier vollständige Workflows um: Jenkins-Pipelines konfigurieren, Infrastruktur mit Terraform verwalten, Container in Kubernetes deployen und Mobile-Apps mit Fastlane automatisieren.

In dieser Lerneinheit lernst du, wie du die gelernten Konzepte in realen Projekten anwendest und typische Herausforderungen meisterst.

Lernziele

Nach dieser Lerneinheit kannst du:

  • Eine Jenkins CI/CD-Pipeline von Grund auf konfigurieren und Build-Trigger, Security und Error Handling implementieren
  • Infrastructure as Code mit Terraform umsetzen und Cloud-Ressourcen deklarativ verwalten
  • Container-basierte Anwendungen in Kubernetes deployen und dabei Resource Limits und Rollback-Strategien anwenden
  • Mobile-App-Releases mit Fastlane automatisieren und platform-spezifische Anforderungen für iOS und Android umsetzen

Überleitung

Du kennst die Konzepte aus den vorherigen Lerneinheiten. Jetzt geht es darum, sie konkret umzusetzen.

Wir starten mit Jenkins und bauen eine vollständige CI/CD-Pipeline Schritt für Schritt auf.

Jenkins CI/CD-Pipeline: Setup

Jenkins ist ein Open-Source-Automatisierungsserver für CI/CD. In den vorherigen Lerneinheiten hast du gelernt, was CI/CD ist und warum es wichtig ist (siehe Lerneinheit Continuous Integration). Jetzt setzt du es praktisch um.

Was du benötigst:

  • Jenkins-Instanz installiert und lauffähig
  • Git-Repository mit deinem Quellcode
  • Build-Tool (z.B. Maven für Java)
  • Grundlegende Kommandozeilen-Erfahrung

Wichtig: Jenkins nutzt Plugins für Erweiterungen. Stelle sicher, dass Git-Plugin und dein Build-Tool-Plugin installiert sind.

Jenkins: Projekt und Repository konfigurieren

Schritt 1: Neues Projekt erstellen

  1. Öffne Jenkins Dashboard
  2. Klicke auf “Neues Element”
  3. Wähle “Freestyle-Projekt” oder “Pipeline” (empfohlen)
  4. Gib dem Projekt einen Namen

Schritt 2: Git-Repository verbinden

  1. Navigiere zu “Quellcode-Management”
  2. Wähle “Git”
  3. Gib die Repository-URL ein (z.B. https://github.com/username/projekt.git)
  4. Security: Nutze Jenkins Credentials Store für Authentifizierung statt Passwörter im Klartext
withCredentials([usernamePassword(credentialsId: "github-creds", usernameVariable: "USER", passwordVariable: "PASS")]) {
  // Zugriff mit Credentials
}

Jenkins: Triggers und Build konfigurieren

Schritt 3: Build-Trigger einrichten

Automatisiere den Pipeline-Start bei Code-Änderungen:

  • Poll SCM: Jenkins prüft regelmäßig auf Änderungen (H/5 * * * * = alle 5 Minuten)
  • Webhook (empfohlen): GitHub/GitLab informiert Jenkins sofort bei Push

Schritt 4: Build-Schritt definieren

Für Maven-Projekte:

mvn clean install

Für Node.js:

npm install
npm run build

Wie funktioniert das? Der Build-Schritt wird nach jedem Trigger ausgeführt. Jenkins lädt den Code herunter und führt die Commands aus.

Jenkins: Post-Build und Security

Schritt 5: Post-Build-Aktionen

  • Artefakte archivieren: Speichere Build-Outputs (z.B. .jar, .war Dateien)
  • Test-Reports: Zeige JUnit/Mocha Test-Ergebnisse an
  • Benachrichtigungen: Sende E-Mails bei Fehlern

Schritt 6: Security Best Practices

Wichtig: Speichere NIEMALS Secrets (Passwörter, API-Keys) im Code oder als Plain-Text in Jenkins.

Richtig: Nutze Jenkins Credentials:

environment {
  DOCKER_CREDS = credentials("docker-hub-creds")
}

Warum ist das wichtig? Credentials werden verschlüsselt gespeichert und nicht im Build-Log angezeigt.

Jenkinsfile: Pipeline mit Error Handling

Pipeline-Projekte nutzen eine Jenkinsfile, die im Repository liegt. Das hat zwei Vorteile: Versionierung der Pipeline und Code Review für Build-Konfiguration.

pipeline {
  agent any
 
  stages {
    stage("Build") {
      steps {
        sh "npm install"
        sh "npm run build"
      }
    }
 
    stage("Test") {
      steps {
        sh "npm test"
      }
    }
 
    stage("Deploy") {
      steps {
        script {
          try {
            sh "./deploy.sh production"
          } catch (Exception e) {
            echo "Deployment failed: ${e.message}"
            throw e
          }
        }
      }
    }
  }
 
  post {
    failure {
      mail to: "team@example.com",
           subject: "Build ${env.BUILD_NUMBER} failed",
           body: "Check ${env.BUILD_URL}"
    }
  }
}

Der post-Block definiert Aktionen nach dem Build. Bei failure wird automatisch eine E-Mail verschickt. Das try-catch im Deploy-Stage fängt Fehler ab und gibt eine klare Fehlermeldung aus.

Terraform: Infrastructure as Code

Jenkins baut deine App. Aber wo läuft sie? Auf Servern in der Cloud. Und wie richtest du diese Server ein? Manuell per Klick? Nein. Mit Code.

Terraform ist ein Tool für Infrastructure as Code (IaC). Du beschreibst deine Infrastruktur (Server, Netzwerke, Datenbanken) in Konfigurationsdateien. Terraform erstellt sie automatisch.

Vorteile von IaC:

  • Reproduzierbar: Infrastruktur jederzeit neu aufsetzen
  • Versioniert: Änderungen nachvollziehbar wie bei Code
  • Automatisiert: Deployment ohne manuelle Schritte
  • Dokumentiert: Konfiguration = lebende Dokumentation

Terraform nutzt die HashiCorp Configuration Language (HCL), eine deklarative Sprache. Du definierst den Soll-Zustand, Terraform kümmert sich um den Ist-Zustand.

Terraform: Provider und Resources

Jede Terraform-Konfiguration besteht aus zwei Hauptteilen: Provider (Verbindung zur Cloud) und Resources (die Infrastruktur selbst).

# Provider: Verbindung zu AWS
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}
 
provider "aws" {
  region = "eu-central-1"
}
 
# Resource: Eine S3 Bucket erstellen
resource "aws_s3_bucket" "app_storage" {
  bucket = "meine-app-storage"
 
  tags = {
    Environment = "Production"
    ManagedBy   = "Terraform"
  }
}

Der Provider definiert, mit welcher Cloud-Plattform du arbeitest (AWS, Azure, GCP). Resources sind die konkreten Infrastruktur-Komponenten: Server, Datenbanken, Netzwerke.

Terraform: State Management und Workflow

Terraform speichert den aktuellen Infrastruktur-Zustand in einer State-Datei. Diese Datei ist kritisch: Terraform vergleicht sie mit deiner Konfiguration, um Änderungen zu erkennen.

Terraform Workflow:

  1. terraform init - Initialisiert Projekt, lädt Provider herunter
  2. terraform plan - Zeigt geplante Änderungen (ohne sie auszuführen)
  3. terraform apply - Führt Änderungen aus, aktualisiert State
  4. terraform destroy - Löscht alle verwalteten Ressourcen

Best Practice: Remote State

terraform {
  backend "s3" {
    bucket = "terraform-state-storage"
    key    = "prod/infrastructure.tfstate"
    region = "eu-central-1"
  }
}

Speichere den State niemals lokal im Team-Kontext. Nutze ein Remote Backend (S3, Azure Storage) für gemeinsamen Zugriff und Versionierung.

Terraform: EC2-Server automatisch erstellen

Jetzt konkret: Ein EC2-Server in AWS mit Terraform. Statt eine veraltete AMI-ID hart zu codieren, nutzen wir eine Data Source, um die aktuellste Ubuntu-Version automatisch zu finden.

# Data Source: Aktuellstes Ubuntu AMI finden
data "aws_ami" "ubuntu" {
  most_recent = true
  owners      = ["099720109477"]
 
  filter {
    name   = "name"
    values = ["ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*"]
  }
}
 
# EC2 Instance erstellen
resource "aws_instance" "web_server" {
  ami           = data.aws_ami.ubuntu.id
  instance_type = "t3.micro"
 
  tags = {
    Name = "WebServer"
  }
}

Data Sources holen Informationen aus der Cloud (z.B. neueste AMIs, verfügbare Zonen). So bleibt deine Konfiguration aktuell, ohne manuelle Anpassungen.

⏳ Lädt Dataview-Inhalt...

Kubernetes: Continuous Deployment

Du hast gelernt, wie Jenkins deine App baut und testet. Jetzt geht es um Continuous Deployment: Die App automatisch in Produktion bringen.

Kubernetes ist die Standard-Plattform für Container-Orchestrierung (siehe Lerneinheit Continuous Integration für Docker-Grundlagen). Statt Container manuell zu starten, deklarierst du den Soll-Zustand in YAML-Dateien. Kubernetes sorgt dafür, dass er eingehalten wird.

CD-Pipeline mit Kubernetes:

  1. Build: Jenkins baut Docker-Image
  2. Push: Image wird in Registry gepusht (Docker Hub, AWS ECR)
  3. Deploy: Jenkins triggert Kubernetes-Update
  4. Rollout: Kubernetes startet neue Pods, stoppt alte (Zero-Downtime)

Der Vorteil: Deployment ist reproduzierbar, automatisiert und kann bei Problemen automatisch zurückgerollt werden.

Dockerfile: Production-Ready Image

Bevor Kubernetes deine App deployen kann, brauchst du ein Docker-Image. Hier ein produktionsreifes Dockerfile mit Multi-Stage Build und Node.js 20 LTS (Node.js 14 ist seit April 2023 End-of-Life).

# Build Stage
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build
 
# Production Stage
FROM node:20-alpine
WORKDIR /app
RUN addgroup -g 1001 -S nodejs && adduser -S nodejs -u 1001
COPY --from=builder --chown=nodejs:nodejs /app/dist ./dist
COPY --from=builder --chown=nodejs:nodejs /app/node_modules ./node_modules
USER nodejs
EXPOSE 3000
CMD ["node", "dist/index.js"]

Multi-Stage Build reduziert Image-Größe (nur Production-Dependencies). Non-Root User erhöht Sicherheit.

Kubernetes: Deployment mit Resource Limits

Ein Kubernetes Deployment definiert, wie deine App laufen soll. Wichtig: Resource Limits verhindern, dass ein Pod den gesamten Cluster lahmlegt.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: web-app
  template:
    metadata:
      labels:
        app: web-app
    spec:
      containers:
      - name: web-app
        image: myregistry/web-app:v1.2.0
        ports:
        - containerPort: 3000
        resources:
          requests:
            memory: "128Mi"
            cpu: "100m"
          limits:
            memory: "256Mi"
            cpu: "500m"
        livenessProbe:
          httpGet:
            path: /health
            port: 3000
          initialDelaySeconds: 10

Requests = garantierte Ressourcen. Limits = Maximum. livenessProbe = Kubernetes startet Pod neu, falls er nicht antwortet.

kubectl: Deployment-Workflow

kubectl ist das Kommandozeilen-Tool für Kubernetes. Hier der typische Workflow für ein Deployment:

# 1. Deployment anwenden
kubectl apply -f deployment.yaml
 
# 2. Status prüfen
kubectl get deployments
kubectl get pods
 
# 3. Rollout-Status verfolgen
kubectl rollout status deployment/web-app
 
# 4. Logs ansehen
kubectl logs -f deployment/web-app
 
# 5. Bei Problemen: Rollback
kubectl rollout undo deployment/web-app
 
# 6. Neue Version deployen (Image-Update)
kubectl set image deployment/web-app web-app=myregistry/web-app:v1.3.0

Kubernetes verwaltet das Rollout automatisch: Neue Pods werden gestartet, alte gestoppt. Zero-Downtime garantiert. Bei Fehler (z.B. Image nicht gefunden): Automatischer Rollback.

Mobile CI/CD: Besondere Herausforderungen

Mobile-Apps haben andere Anforderungen als Web-Apps. Du kannst nicht einfach deployen. Du musst durch den App Store Review-Prozess.

Herausforderungen:

  • Code Signing: iOS-Apps müssen mit Apple-Zertifikaten signiert sein
  • Provisioning Profiles: Definieren, auf welchen Geräten die App läuft
  • App Store Submission: Automatischer Upload, aber manuelles Review durch Apple/Google
  • Multiple Builds: Debug, Release, verschiedene Environments
  • Screenshots & Metadata: Müssen mit App-Version synchronisiert werden

Fastlane ist das De-facto-Standard-Tool für Mobile CI/CD. Es automatisiert Code Signing, Build-Prozesse, Screenshots und App Store Submission für iOS und Android.

Fastlane: Moderne Automatisierung

Fastlane nutzt Ruby-Syntax und definiert Lanes (Workflows) in einer Fastfile. Hier ein modernes Beispiel mit match für Code Signing (das veraltete sigh sollte nicht mehr verwendet werden).

default_platform(:ios)
 
platform :ios do
  desc "Push a new beta build to TestFlight"
  lane :beta do
    increment_build_number(xcodeproj: "MyApp.xcodeproj")
    match(type: "appstore", readonly: true)
    build_app(scheme: "MyApp")
    upload_to_testflight
  end
 
  desc "Release to App Store"
  lane :release do
    match(type: "appstore", readonly: true)
    build_app(scheme: "MyApp")
    deliver(submit_for_review: true, automatic_release: false)
  end
end

match synchronisiert Code-Signing-Zertifikate im Team via Git. deliver uploaded automatisch in den App Store.

iOS vs Android: Platform-Unterschiede

iOS und Android haben unterschiedliche Anforderungen an den Build- und Deployment-Prozess.

iOS:

  • Code Signing obligatorisch: Ohne Apple-Zertifikat läuft nichts
  • Provisioning Profiles: Development, Ad-Hoc, App Store (verschiedene Profile für verschiedene Zwecke)
  • TestFlight: Interne und externe Beta-Tests über Apple
  • Review-Prozess: Kann 1-3 Tage dauern

Android:

  • Code Signing einfacher: Selbst-signierte Zertifikate möglich
  • Google Play Console: Direkter Upload ohne langwieriges Review
  • Closed/Open Beta: Flexiblere Test-Tracks als iOS
  • Schnellere Rollouts: Updates können in wenigen Stunden live sein

Fastlane unterstützt beide Plattformen, aber die Konfiguration unterscheidet sich deutlich. iOS ist restriktiver, Android flexibler.

⏳ Lädt Dataview-Inhalt...

Mobile Security: Credentials und Zertifikate

Mobile CI/CD erfordert sensible Daten: Code-Signing-Zertifikate, API-Keys, Provisioning Profiles. Diese NIEMALS ins Repository committen.

Best Practices:

  • Fastlane match: Speichert Zertifikate verschlüsselt in separatem Git-Repository
  • Environment Variables: API-Keys über CI-System injizieren, nicht hardcoden
  • Keychain Access Control: CI-Runner braucht eigenen Keychain für Zertifikate
  • Rotation: Zertifikate regelmäßig erneuern, alte widerrufen
  • Least Privilege: CI-System nur Zugriff auf nötige Ressourcen

Beispiel .gitignore:

*.mobileprovision
*.p12
*.cer
.env.secret
fastlane/report.xml

Automatisierung ohne Kompromisse: Fastlane match löst das Zertifikats-Problem elegant, indem es sie verschlüsselt und versioniert.

Zusammenfassung

Du hast in dieser Lerneinheit den kompletten Weg von Code bis Produktion durchlaufen. Mit Jenkins baust und testest du Anwendungen automatisch - von der Repository-Anbindung über Build-Trigger bis zur Fehlerbehandlung mit try-catch und post-Blöcken. Dabei sicherst du Credentials durch den Jenkins Credentials Store statt Passwörter im Klartext.

Deine gebaute Anwendung läuft auf Infrastruktur, die du mit Terraform als Code definierst. Statt Server manuell zu konfigurieren, beschreibst du sie deklarativ mit HCL: Provider verbinden dich mit der Cloud, Resources definieren die Komponenten, der State wird remote gespeichert und Data Sources halten deine Konfiguration aktuell.

Für Container-basierte Anwendungen übernimmt Kubernetes das Deployment. Du definierst den Soll-Zustand mit Resource Limits und Health Checks, Kubernetes sorgt für Zero-Downtime-Rollouts und automatische Rollbacks bei Problemen. Der kubectl-Workflow gibt dir volle Kontrolle über Deployments.

Mobile Apps haben besondere Anforderungen: Code Signing, Provisioning Profiles, App Store Review. Fastlane automatisiert diese Komplexität mit match für Zertifikate und platform-spezifischen Lanes. Security bleibt dabei gewährleistet durch verschlüsselte Credential-Verwaltung.

Der rote Faden: Automatisierung, Sicherheit und Reproduzierbarkeit prägen alle vier Workflows. Das ist die Grundlage moderner DevOps-Praktiken.