Skip to content
Zero-Downtime Deployment auf AWS: Praktischer Leitfaden mit GitHub Actions und GitLab CI/CD
← ← Zurück zu Gedanken Cloud

Zero-Downtime Deployment auf AWS: Praktischer Leitfaden mit GitHub Actions und GitLab CI/CD


Du hast deine Anwendung auf AWS migriert — React auf CloudFront, Node.js auf EC2 mit Auto Scaling, PostgreSQL auf RDS, Redis auf ElastiCache. Die Infrastruktur steht. Aber jetzt kommt die unvermeidliche Frage: Wie deployest du, ohne dass die Seite ausfällt?

Wenn jedes Deploy einige Sekunden (oder Minuten) Downtime bedeutet, verlierst du Nutzer, Vertrauen und Geld. Zero-Downtime Deployment ist kein Luxus — es ist Standard. In diesem Artikel gehen wir zwei AWS-Deployment-Strategien durch (Rolling und Blue/Green), vergleichen sie und zeigen, wie du sie mit GitHub Actions oder GitLab CI/CD integrierst.

Warum fällt die Anwendung beim Deploy aus?

Auf einem klassischen VPS sieht das Deploy meist so aus: Du verbindest dich per SSH, führst git pull aus, npm install, startest den Node.js-Prozess neu. Zwischen Stopp des alten Prozesses und Start des neuen reagiert die Anwendung nicht. Vielleicht 5 Sekunden, vielleicht 30 — je nach Build- und Startup-Zeit.

Bei AWS mit ALB und Auto Scaling Group ist das anders. Du hast mehrere EC2-Instanzen hinter einem Load Balancer. Der Trick ist, die Instanzen nacheinander (oder in Batches) zu aktualisieren, sodass immer mindestens ein Teil davon Traffic bedient. Dafür gibt es zwei Hauptstrategien.

Strategie 1: Rolling Deployment

Beim Rolling Deployment werden die Instanzen nacheinander (oder in Batches) innerhalb derselben Auto Scaling Group aktualisiert.

Der Ablauf: AWS CodeDeploy nimmt die neue Codeversion und schickt sie an die erste EC2-Instanz. Der ALB nimmt diese Instanz aus der Rotation (Deregistration), der Code wird aktualisiert, die App startet neu, dann fügt der ALB sie wieder hinzu, sobald sie den Health Check besteht. Der Prozess wiederholt sich für jede Instanz.

Praktisch: Hast du 4 Instanzen, bedienen zu jedem Zeitpunkt mindestens 3 Traffic. Nutzer merken nichts.

Vorteile: Du brauchst keine zusätzlichen Ressourcen (die Infrastruktur wird nicht verdoppelt), die Konfiguration ist einfach, und die Kosten bleiben gleich. Nachteile: Das Deploy dauert länger (jede Instanz wird sequenziell aktualisiert), und für einige Minuten laufen zwei Versionen der App gleichzeitig — du musst sicherstellen, dass sie kompatibel sind.

CodeDeploy-Konfiguration für Rolling: In der Deployment Group setzt du den Typ auf „In-place" und wählst die Auto Scaling Group. Unter „Deployment settings" wählst du CodeDeployDefault.OneAtATime für maximale Sicherheit oder CodeDeployDefault.HalfAtATime für Geschwindigkeit. Der ALB übernimmt Deregistration/Registration automatisch.

Strategie 2: Blue/Green Deployment

Blue/Green ist die Premium-Strategie. Statt bestehende Instanzen zu aktualisieren, erstellst du einen komplett neuen Satz Instanzen (die „grüne" Umgebung) mit der neuen Version, testest sie und schaltest dann den gesamten Traffic vom alten Satz (die „blaue" Umgebung) auf den neuen um.

Der Ablauf: CodeDeploy erstellt eine neue Auto Scaling Group mit Instanzen, die die neue Version laufen. Die neuen Instanzen registrieren sich bei einer separaten Target Group des ALB. Sobald alle neuen Instanzen die Health Checks bestehen, leitet der ALB den Traffic von der alten Target Group zur neuen — sofort. Geht etwas schief, ist Rollback ein einfacher Wechsel zurück zur ursprünglichen Target Group.

Vorteile: Sofortiger Rollback (die alten Instanzen laufen noch), du kannst die grüne Umgebung testen, bevor du den Traffic umschaltest, du läufst nie zwei Versionen gleichzeitig. Nachteile: Für einige Minuten zahlst du doppelt (zwei Instanz-Sätze laufen parallel), und das Setup ist komplexer.

Rolling vs. Blue/Green — Wann was?

Rolling Deployment passt für Anwendungen, die zwei Versionen gleichzeitig tolerieren, kleine Teams, die Einfachheit wollen, und Situationen, in denen das Budget zählt (keine zusätzlichen Ressourcen).

Blue/Green ist die richtige Wahl für Anwendungen mit strengen SLAs, wenn du sofortigen Rollback brauchst (unter 1 Minute), oder wenn du die neue Version manuell validieren willst, bevor du umschaltest.

Für unsere Node.js + PostgreSQL + Redis-Anwendung lautet die praktische Empfehlung: Starte mit Rolling Deployment. Es ist einfacher, günstiger und deckt 90 % der Anforderungen. Wechsle zu Blue/Green, wenn du einen konkreten Grund hast — z. B. eine Datenbankmigration, die vor dem Cutover getestet werden muss.

Das Herzstück: AWS CodeDeploy

Unabhängig von der Strategie orchestriert AWS CodeDeploy den Deployment-Prozess auf den EC2-Instanzen. Du konfigurierst es einmal und triggerst es dann aus GitHub Actions oder GitLab CI/CD.

CodeDeploy nutzt eine appspec.yml-Datei im Projekt-Root, die definiert, was in jeder Deployment-Phase passiert:

version: 0.0
os: linux
files:
  - source: /
    destination: /home/app/myapp
hooks:
  BeforeInstall:
    - location: scripts/stop_server.sh
      timeout: 60
  AfterInstall:
    - location: scripts/install_dependencies.sh
      timeout: 120
  ApplicationStart:
    - location: scripts/start_server.sh
      timeout: 60
  ValidateService:
    - location: scripts/health_check.sh
      timeout: 60

Die Skripte tun genau das, was du erwartest: stop_server.sh stoppt den Node.js-Prozess (graceful shutdown), install_dependencies.sh führt npm ci --production aus, start_server.sh startet die App, und health_check.sh prüft, ob der /health-Endpoint mit 200 antwortet.

Ein kritischer Punkt: Graceful Shutdown. Wenn der ALB eine Instanz aus der Rotation nimmt, ermöglicht die Einstellung deregistration_delay (Standard 300 Sekunden), dass laufende Requests abgeschlossen werden. Stelle sicher, dass deine Node.js-App das SIGTERM-Signal korrekt behandelt — beende aktive Requests, schließe DB- und Redis-Verbindungen, dann beende.

Integration mit GitHub Actions

Voller Ablauf: Push auf Branch main → GitHub Actions führt Tests aus → Build wird gepackt und auf S3 hochgeladen → CodeDeploy wird getriggert → EC2-Instanzen werden aktualisiert.

# .github/workflows/deploy.yml
name: Deploy to Production

on:
  push:
    branches: [main]

permissions:
  id-token: write
  contents: read

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
      - run: npm ci
      - run: npm test

  deploy:
    needs: test
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Configure AWS Credentials (OIDC)
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ secrets.AWS_DEPLOY_ROLE_ARN }}
          aws-region: eu-central-1

      - name: Package and upload to S3
        run: |
          zip -r app-${{ github.sha }}.zip . -x '.git/*'
          aws s3 cp app-${{ github.sha }}.zip \
            s3://my-deploy-bucket/app-${{ github.sha }}.zip

      - name: Trigger CodeDeploy
        run: |
          aws deploy create-deployment \
            --application-name my-app \
            --deployment-group-name production \
            --s3-location bucket=my-deploy-bucket,key=app-${{ github.sha }}.zip,bundleType=zip \
            --description "Deploy ${{ github.sha }}"

Wichtiger Hinweis zur Authentifizierung: Das Beispiel nutzt OIDC (OpenID Connect) statt Access Keys als Secrets. Du konfigurierst einen Identity Provider in IAM, der GitHub vertraut, und GitHub Actions erhält bei jedem Run temporäre Credentials. Keine Secrets zum Rotieren, kein Leak-Risiko.

Integration mit GitLab CI/CD

Gleiche Logik, andere Syntax. GitLab CI/CD nutzt die Datei .gitlab-ci.yml:

# .gitlab-ci.yml
stages:
  - test
  - deploy

variables:
  AWS_DEFAULT_REGION: eu-central-1

test:
  stage: test
  image: node:20-alpine
  script:
    - npm ci
    - npm test

deploy_production:
  stage: deploy
  image: amazon/aws-cli:latest
  only:
    - main
  before_script:
    - apt-get update && apt-get install -y zip
  script:
    - zip -r app-${CI_COMMIT_SHA}.zip . -x '.git/*'
    - aws s3 cp app-${CI_COMMIT_SHA}.zip
        s3://my-deploy-bucket/app-${CI_COMMIT_SHA}.zip
    - aws deploy create-deployment
        --application-name my-app
        --deployment-group-name production
        --s3-location bucket=my-deploy-bucket,key=app-${CI_COMMIT_SHA}.zip,bundleType=zip
        --description "Deploy ${CI_COMMIT_SHA}"
  environment:
    name: production
    url: https://myapp.example.com

Für die Authentifizierung unterstützt GitLab ebenfalls OIDC mit AWS. Die Alternative ist, AWS_ACCESS_KEY_ID und AWS_SECRET_ACCESS_KEY als geschützte CI/CD-Variablen unter Settings → CI/CD → Variables zu setzen.

GitHub Actions vs. GitLab CI/CD — Schnellvergleich

Beide Plattformen machen ihren Job gut. Die praktischen Unterschiede sind gering: GitHub Actions nutzt YAML mit Job- und Step-Struktur, hat einen reichen Marketplace mit vordefinierten Actions und integriert sich nativ, wenn der Code schon auf GitHub liegt. GitLab CI/CD hat kompakteres YAML, bietet Environments mit visueller Deployment-Nachverfolgung, ein eingebautes Container Registry und eignet sich ideal, wenn du schon im GitLab-Ökosystem bist.

Die Wahl hängt davon ab, wo dein Code liegt, nicht von den CI/CD-Fähigkeiten. Beide können CodeDeploy identisch triggern.

Checkliste vor dem ersten Deploy

Einige Dinge vor dem Produktionsgang: Der /health-Endpoint in deiner Node.js-App muss die DB- und Redis-Verbindung prüfen, nicht nur 200 zurückgeben. Der ALB-Health-Check muss auf diesen Endpoint konfiguriert sein, mit 15 Sekunden Intervall und Threshold 2. Graceful Shutdown muss implementiert sein — die App muss SIGTERM korrekt behandeln. deregistration_delay auf der Target Group sollte mindestens 30 Sekunden sein (Standard 300 ist für die meisten Apps zu viel). Datenbankmigrationen müssen separat vor dem Deploy laufen und rückwärtskompatibel sein. Und last but not least: Ein automatischer Rollback-Mechanismus muss konfiguriert sein — CodeDeploy kann bei fehlgeschlagenem Deployment automatisch zurückrollen.

Fazit

Zero-Downtime Deployment ist keine Raketenwissenschaft — es ist die Kombination aus korrekt konfigurierten AWS-Services (ALB + ASG + CodeDeploy) mit einem CI/CD-Pipeline, der sie orchestriert. Starte mit Rolling Deployment, automatisiere mit GitHub Actions oder GitLab CI/CD und füge Komplexität (Blue/Green) nur hinzu, wenn du sie wirklich brauchst.

Am wichtigsten: Versuche nicht, von Anfang an alles zu machen. Ein funktionierendes Rolling Deployment schlägt ein halb konfiguriertes Blue/Green an jedem Tag der Woche.


Veröffentlicht auf teninvent.ro — TEN INVENT S.R.L. bietet CI/CD-Implementierung und AWS-Infrastruktur-Services. Kontaktiere uns für eine Bewertung deines Deployment-Pipelines.