CI/CD für KI-Systeme: GitHub Actions, ECR und GPU-Deployments auf AWS

CI/CD für KI-Systeme: GitHub Actions, ECR und GPU-Deployments auf AWS

Foto von iSawRed auf Unsplash

Dein RAG-System läuft lokal einwandfrei. Die Antworten sind präzise, die Retrieval-Qualität stimmt, die Inferenz ist schnell genug. Dann kommt das Deployment. Der Container braucht zwei Minuten zum Starten, weil das Embedding-Modell in den GPU-Speicher geladen werden muss. Der Health Check schlägt fehl, weil er nach 30 Sekunden aufgibt. Der Load Balancer routet Traffic an einen Container, der noch nicht bereit ist. Rollback.

GPU-basierte KI-Systeme brechen die Annahmen, auf denen Standard-CI/CD-Pipelines aufgebaut sind. Container starten nicht in Sekunden, sondern in Minuten. Images sind nicht 200 MB groß, sondern 2 bis 8 GB. Ein fehlgeschlagenes Deployment bedeutet nicht nur Downtime, sondern potenziell verlorene GPU-Rechenzeit, die pro Stunde abgerechnet wird.

In diesem Artikel zeige ich eine produktionsreife Pipeline für GPU-basierte KI-Systeme auf AWS. Von OIDC-Authentifizierung über ECR Lifecycle-Policies bis zu ECS Rolling Deployments mit Circuit Breaker. Jede Entscheidung wird begründet, jeder Trade-off benannt. Falls du bereits Erfahrung mit RAG-Systemen in Produktion hast, schließt dieser Artikel die Lücke zwischen funktionierendem System und zuverlässigem Deployment.

CI/CD Pipeline für KI-Systeme auf AWS mit GitHub Actions, ECR, ECS Rolling Deployment und Circuit Breaker

Warum CI/CD für KI-Systeme anders ist

Bevor wir in die Implementierung einsteigen, lohnt sich ein Blick auf die fundamentalen Unterschiede. Diese Tabelle fasst zusammen, warum Standard-Pipelines bei GPU-Workloads scheitern:

AspektStandard-AppGPU/KI-System
Container-Start2 bis 5 Sekunden60 bis 120 Sekunden
Health CheckHTTP 200 nach 3sGPU + Modell geladen nach 90s
Image-Größe100 bis 300 MB2 bis 8 GB
Worker-SkalierungHorizontal (N Worker)1 Worker pro GPU (VRAM-Limit)
Rollback-RisikoSekunden DowntimeMinuten GPU-Kosten
SkalierungMehr Worker im ContainerMehr Container (horizontal)

Diese Unterschiede haben direkte Auswirkungen auf jede Komponente der Pipeline: Health-Check-Timeouts müssen angepasst werden, der Load Balancer braucht eine Aufwärmphase, und der Circuit Breaker muss wissen, dass ein langer Start kein Fehler ist.

OIDC: Keine gespeicherten Credentials

Die erste Entscheidung betrifft die Authentifizierung. Viele Teams nutzen langlebige AWS Access Keys in GitHub Secrets. Das funktioniert, ist aber ein Sicherheitsrisiko: Die Keys rotieren nicht automatisch, haben oft zu breite Berechtigungen und müssen manuell verwaltet werden.

Die Alternative ist OIDC (OpenID Connect). GitHub Actions authentifiziert sich direkt bei AWS mit kurzlebigen JWT-Tokens. Keine gespeicherten Credentials, keine Rotation, keine manuelle Verwaltung. Der Token ist nur für die Dauer des Workflow-Runs gültig.

Terraform-Setup

# OIDC Provider: GitHub als Identity Provider registrieren
resource "aws_iam_openid_connect_provider" "github" {
  url = "https://token.actions.githubusercontent.com"
 
  client_id_list = ["sts.amazonaws.com"]
 
  thumbprint_list = [
    "6938fd4d98bab03faadb97b34396831e3780aea1",
    "1c58a3a8518e8759bf075b76b750d4f2df264fcd"
  ]
}
 
# IAM-Rolle, die GitHub Actions annehmen darf
resource "aws_iam_role" "github_actions" {
  name = "github-actions-deploy"
 
  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect = "Allow"
        Principal = {
          Federated = aws_iam_openid_connect_provider.github.arn
        }
        Action = "sts:AssumeRoleWithWebIdentity"
        Condition = {
          StringEquals = {
            "token.actions.githubusercontent.com:aud" = "sts.amazonaws.com"
          }
          StringLike = {
            "token.actions.githubusercontent.com:sub" = "repo:your-org/your-repo:ref:refs/heads/main"
          }
        }
      }
    ]
  })
}

Least-Privilege-Berechtigungen

Die Condition auf den main-Branch ist entscheidend. Ohne diese Einschränkung könnte jeder Branch, jeder Pull Request und jeder Fork in dein AWS-Konto deployen. In einem Team mit mehreren Entwicklern ist das ein Angriffsvektor, der leicht übersehen wird.

# Nur die minimal nötigen Berechtigungen
resource "aws_iam_role_policy" "deploy" {
  name = "deploy-policy"
  role = aws_iam_role.github_actions.id
 
  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Sid    = "ECRAuth"
        Effect = "Allow"
        Action = ["ecr:GetAuthorizationToken"]
        Resource = "*"
      },
      {
        Sid    = "ECRPush"
        Effect = "Allow"
        Action = [
          "ecr:BatchCheckLayerAvailability",
          "ecr:InitiateLayerUpload",
          "ecr:UploadLayerPart",
          "ecr:CompleteLayerUpload",
          "ecr:PutImage"
        ]
        Resource = aws_ecr_repository.ki_api.arn
      },
      {
        Sid    = "ECSUpdate"
        Effect = "Allow"
        Action = [
          "ecs:UpdateService",
          "ecs:DescribeServices",
          "ecs:RegisterTaskDefinition",
          "ecs:DescribeTaskDefinition"
        ]
        Resource = "*"
        Condition = {
          StringEquals = {
            "ecs:cluster" = aws_ecs_cluster.ki_cluster.arn
          }
        }
      },
      {
        Sid    = "PassRole"
        Effect = "Allow"
        Action = ["iam:PassRole"]
        Resource = [
          aws_iam_role.ecs_task_role.arn,
          aws_iam_role.ecs_execution_role.arn
        ]
      }
    ]
  })
}

Der Unterschied zu einem Action = ["ecr:*", "ecs:*"] ist erheblich. Die Policy oben erlaubt exakt vier Aktionen: ECR-Login, Image-Push, ECS-Service-Update und das Weiterreichen der Task-Rollen. Kein Löschen von Repositories, kein Zugriff auf andere Cluster, keine Manipulation von IAM-Rollen.

Dockerfile für GPU-Workloads

FROM python:3.11-slim
 
WORKDIR /app
 
# System-Dependencies für ML-Libraries
RUN apt-get update && apt-get install -y --no-install-recommends \
    build-essential \
    && rm -rf /var/lib/apt/lists/*
 
# Dependencies zuerst (Docker Layer Cache)
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
 
# Application Code
COPY . .
 
# Gunicorn mit GPU-optimierten Parametern
CMD ["gunicorn", "app:create_app()", \
     "--bind", "0.0.0.0:8000", \
     "--workers", "1", \
     "--timeout", "120", \
     "--max-requests", "1000", \
     "--max-requests-jitter", "50"]

Warum diese Parameter?

ParameterWertBegründung
workers1Ein GPU-Modell belegt den gesamten VRAM. Zwei Worker würden doppelten Speicher brauchen, den eine einzelne GPU nicht hat. Horizontale Skalierung erfolgt über ECS (mehr Container), nicht über mehr Worker.
timeout120RAG-Queries mit Retrieval, Reranking und Generation brauchen bei komplexen Dokumenten bis zu 30 Sekunden. Mit Sicherheitspuffer: 120 Sekunden.
max-requests1000Nach 1000 Requests wird der Worker neugestartet. Das verhindert Memory-Fragmentierung, die bei langlebigen Python-Prozessen mit ML-Libraries auftritt. PyTorch und Transformers allokieren und deallokieren GPU-Speicher nicht immer sauber.
max-requests-jitter50Verhindert, dass alle Worker gleichzeitig neustarten, wenn mehrere Container laufen.

Warum python:3.11-slim statt eines CUDA-Base-Images? CUDA-Images sind 4 bis 6 GB groß. Wenn die GPU-Treiber auf dem Host installiert sind (was bei ECS GPU-Instances der Fall ist), reicht ein schlankes Python-Image. Die CUDA-Runtime wird über den --gpus-Flag beim Container-Start vom Host durchgereicht. Das reduziert die Image-Größe erheblich und beschleunigt Build und Push.

ECR: Image-Management mit Lifecycle-Policies

Repository mit Terraform

resource "aws_ecr_repository" "ki_api" {
  name                 = "ki-rag-api"
  image_tag_mutability = "MUTABLE"
 
  image_scanning_configuration {
    scan_on_push = true
  }
 
  encryption_configuration {
    encryption_type = "AES256"
  }
}

MUTABLE Tags erlauben es, das latest-Tag bei jedem Push zu überschreiben. Für On-Demand Tasks (Batch-Verarbeitung, Ingestion) ist das wichtig: Der Task referenziert immer latest und bekommt automatisch die neueste Version.

Lifecycle-Policy

GPU-Images sind groß. Ohne Lifecycle-Policy sammeln sich schnell Hunderte Gigabyte an veralteten Images an:

resource "aws_ecr_lifecycle_policy" "ki_api" {
  repository = aws_ecr_repository.ki_api.name
 
  policy = jsonencode({
    rules = [
      {
        rulePriority = 1
        description  = "Untagged Images nach 7 Tagen entfernen"
        selection = {
          tagStatus   = "untagged"
          countType   = "sinceImagePushed"
          countUnit   = "days"
          countNumber = 7
        }
        action = {
          type = "expire"
        }
      },
      {
        rulePriority = 2
        description  = "Maximal 10 tagged Images behalten"
        selection = {
          tagStatus     = "tagged"
          tagPatternList = ["*"]
          countType     = "imageCountMoreThan"
          countNumber   = 10
        }
        action = {
          type = "expire"
        }
      }
    ]
  })
}

Bei einem 4 GB Image und täglichen Deployments spart diese Policy ca. 120 GB pro Monat. Das klingt wenig, aber ECR berechnet $0.10 pro GB pro Monat. Ohne Policy wächst der Speicher linear und kostet nach einem Jahr über $500 pro Repository.

ECS Rolling Deployment mit Circuit Breaker

Service-Definition

resource "aws_ecs_service" "ki_api" {
  name            = "ki-rag-api"
  cluster         = aws_ecs_cluster.ki_cluster.id
  task_definition = aws_ecs_task_definition.ki_api.arn
  desired_count   = 2
  launch_type     = "EC2"
 
  deployment_minimum_healthy_percent = 100
  deployment_maximum_percent         = 200
 
  deployment_circuit_breaker {
    enable   = true
    rollback = true
  }
 
  load_balancer {
    target_group_arn = aws_lb_target_group.ki_api.arn
    container_name   = "ki-rag-api"
    container_port   = 8000
  }
 
  ordered_placement_strategy {
    type  = "spread"
    field = "attribute:ecs.availability-zone"
  }
}

Was bei einem Deployment passiert

  1. Neue Task-Definition registrieren: ECS erstellt eine neue Revision mit dem aktualisierten Image-Tag
  2. Neue Tasks starten: ECS startet neue Tasks parallel zu den bestehenden (maximum_percent = 200 erlaubt doppelte Kapazität)
  3. Health Check abwarten: Die neuen Tasks durchlaufen den Health Check (bis zu 120 Sekunden)
  4. Traffic umleiten: Der ALB routet Traffic erst nach erfolgreichem Health Check an die neuen Tasks
  5. Alte Tasks stoppen: Die alten Tasks werden erst gestoppt, nachdem die neuen gesund sind

deployment_minimum_healthy_percent = 100 bedeutet: Es gibt zu keinem Zeitpunkt weniger gesunde Tasks als die gewünschte Anzahl. Kein Benutzer erlebt einen Ausfall während des Deployments.

Circuit Breaker: Wenn drei aufeinanderfolgende Tasks den Health Check nicht bestehen, stoppt ECS das Deployment und rollt automatisch auf die vorherige Task-Definition zurück. Ohne Circuit Breaker würde ECS endlos neue Tasks starten und terminieren, was GPU-Kosten verursacht, ohne Fortschritt zu machen.

Health Checks für GPU-Services

Der Health Check ist die kritischste Komponente bei GPU-Deployments. Ein Standard-Health-Check (GET /health mit 30s Timeout) versagt hier, weil er nicht unterscheiden kann zwischen "Container startet noch" und "Container ist kaputt".

Application-Level Health Check

from fastapi import FastAPI
import torch
 
app = FastAPI()
 
models_loaded = False
 
@app.on_event("startup")
async def load_models():
    global models_loaded
    # Modelle in GPU-Speicher laden
    # Embedding-Modell, Reranker, etc.
    models_loaded = True
 
@app.get("/health")
async def health_check():
    checks = {
        "gpu_available": torch.cuda.is_available(),
        "gpu_memory_allocated": torch.cuda.memory_allocated() > 0,
        "models_loaded": models_loaded,
    }
 
    if all(checks.values()):
        return {"status": "healthy", "checks": checks}
 
    return {"status": "unhealthy", "checks": checks}, 503

Dieser Endpoint prüft drei Dinge: Ist eine GPU verfügbar? Wird GPU-Speicher genutzt (Modelle geladen)? Hat der Startup-Prozess alle Modelle erfolgreich geladen? Erst wenn alle drei Bedingungen erfüllt sind, meldet der Container "healthy".

ECS Task Definition mit startPeriod

resource "aws_ecs_task_definition" "ki_api" {
  family                   = "ki-rag-api"
  requires_compatibilities = ["EC2"]
  network_mode             = "bridge"
  execution_role_arn       = aws_iam_role.ecs_execution_role.arn
  task_role_arn            = aws_iam_role.ecs_task_role.arn
 
  container_definitions = jsonencode([
    {
      name      = "ki-rag-api"
      image     = "${aws_ecr_repository.ki_api.repository_url}:latest"
      cpu       = 2048
      memory    = 8192
      essential = true
 
      portMappings = [
        {
          containerPort = 8000
          hostPort      = 0
          protocol      = "tcp"
        }
      ]
 
      healthCheck = {
        command     = ["CMD-SHELL", "curl -f http://localhost:8000/health || exit 1"]
        interval    = 15
        timeout     = 10
        retries     = 8
        startPeriod = 120
      }
 
      resourceRequirements = [
        {
          type  = "GPU"
          value = "1"
        }
      ]
 
      logConfiguration = {
        logDriver = "awslogs"
        options = {
          "awslogs-group"         = "/ecs/ki-rag-api"
          "awslogs-region"        = var.aws_region
          "awslogs-stream-prefix" = "ecs"
        }
      }
 
      secrets = [
        {
          name      = "OPENAI_API_KEY"
          valueFrom = "${aws_secretsmanager_secret.openai_key.arn}"
        }
      ]
    }
  ])
}

startPeriod = 120 gibt dem Container 120 Sekunden Zeit, bevor der erste Health Check zählt. Während dieser Grace Period werden fehlgeschlagene Health Checks ignoriert. Das ist essentiell für GPU-Container, die Modelle laden müssen. Ohne startPeriod würde ECS den Container nach wenigen fehlgeschlagenen Checks als ungesund markieren und terminieren, obwohl er noch startet.

ALB Slow Start

resource "aws_lb_target_group" "ki_api" {
  name     = "ki-rag-api"
  port     = 8000
  protocol = "HTTP"
  vpc_id   = var.vpc_id
 
  health_check {
    path                = "/health"
    healthy_threshold   = 2
    unhealthy_threshold = 5
    timeout             = 10
    interval            = 15
    matcher             = "200"
  }
 
  slow_start = 60
 
  stickiness {
    type    = "lb_cookie"
    enabled = false
  }
}

slow_start = 60 bedeutet: Nachdem ein Target als gesund registriert wird, erhält es 60 Sekunden lang linear steigenden Traffic. Statt sofort 50% der Last zu bekommen, startet es bei nahezu 0% und wird langsam hochgefahren. Das gibt dem GPU-Container Zeit, CUDA-Kernels zu kompilieren und Caches aufzuwärmen. Ohne Slow Start kann der erste Schwung an Requests zu Timeouts führen, weil die initiale GPU-Inferenz langsamer ist als nachfolgende.

Doppelte Absicherung: ECS Health Checks schützen auf Container-Ebene (startet der Container überhaupt?), ALB Slow Start schützt auf Traffic-Ebene (bekommt der Container zu viel Last, bevor er bereit ist?). Beide Mechanismen sind unabhängig und ergänzen sich.

Zwei Deployment-Patterns: Service vs. Task

Nicht jeder GPU-Workload braucht ein Rolling Deployment. Die Wahl des Patterns hängt vom Anwendungsfall ab:

AspektECS Service (API)ECS RunTask (Batch)
VerfügbarkeitAlways-On (24/7)On-Demand
DeploymentRolling Update + Circuit BreakerKein Deployment nötig
Image-TagCommit-SHA (reproduzierbar)latest (immer aktuell)
Triggerecs:UpdateServiceEventBridge Schedule / Webhook
Skalierungdesired_count anpassenParallele Tasks starten
KostenKontinuierlich (GPU reserviert)Nur bei Ausführung

API-Service: Für die RAG-API, die Anfragen in Echtzeit beantwortet. Rolling Update mit Circuit Breaker stellt sicher, dass kein Benutzer einen Ausfall erlebt. Das Image wird über den Commit-SHA referenziert, damit exakt nachvollziehbar ist, welcher Code läuft.

Batch-Task: Für die Ingestion-Pipeline, die Dokumente verarbeitet und in die Vektordatenbank schreibt. Der Task referenziert latest und bekommt bei jedem Start automatisch die neueste Version. Kein explizites Deployment nötig. Der Task wird per EventBridge-Schedule (z.B. täglich um 2:00 Uhr) oder per Webhook (neues Dokument hochgeladen) gestartet.

Die komplette GitHub Actions Pipeline

name: Deploy KI-API
 
on:
  push:
    branches: [main]
 
permissions:
  id-token: write   # OIDC Token anfordern
  contents: read     # Repository auschecken
 
env:
  AWS_REGION: eu-central-1
  ECR_REPOSITORY: ki-rag-api
  ECS_CLUSTER: ki-cluster
  ECS_SERVICE: ki-rag-api
 
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4
 
      - name: Configure AWS Credentials (OIDC)
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789012:role/github-actions-deploy
          aws-region: ${{ env.AWS_REGION }}
 
      - name: Login to Amazon ECR
        id: ecr-login
        uses: aws-actions/amazon-ecr-login@v2
 
      - name: Build, Tag, Push
        env:
          ECR_REGISTRY: ${{ steps.ecr-login.outputs.registry }}
          IMAGE_TAG: ${{ github.sha }}
        run: |
          docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
          docker tag $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG \
                     $ECR_REGISTRY/$ECR_REPOSITORY:latest
          docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
          docker push $ECR_REGISTRY/$ECR_REPOSITORY:latest
 
      - name: Update ECS Task Definition
        id: task-def
        env:
          ECR_REGISTRY: ${{ steps.ecr-login.outputs.registry }}
          IMAGE_TAG: ${{ github.sha }}
        run: |
          TASK_DEF=$(aws ecs describe-task-definition \
            --task-definition ki-rag-api \
            --query 'taskDefinition' \
            --output json)
 
          NEW_TASK_DEF=$(echo $TASK_DEF | jq \
            --arg IMAGE "$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG" \
            '.containerDefinitions[0].image = $IMAGE |
             del(.taskDefinitionArn, .revision, .status,
                 .requiresAttributes, .compatibilities,
                 .registeredAt, .registeredBy)')
 
          NEW_ARN=$(aws ecs register-task-definition \
            --cli-input-json "$NEW_TASK_DEF" \
            --query 'taskDefinition.taskDefinitionArn' \
            --output text)
 
          echo "task_def_arn=$NEW_ARN" >> $GITHUB_OUTPUT
 
      - name: Deploy to ECS
        run: |
          aws ecs update-service \
            --cluster $ECS_CLUSTER \
            --service $ECS_SERVICE \
            --task-definition ${{ steps.task-def.outputs.task_def_arn }} \
            --force-new-deployment
 
      - name: Wait for Deployment
        run: |
          aws ecs wait services-stable \
            --cluster $ECS_CLUSTER \
            --services $ECS_SERVICE

Die zwei Zeilen unter permissions sind das Herzstück der OIDC-Integration. id-token: write erlaubt GitHub Actions, einen JWT-Token beim OIDC-Provider anzufordern. contents: read wird für den Checkout benötigt. Ohne diese Permissions-Deklaration schlägt die OIDC-Authentifizierung fehl.

Der Workflow baut das Image, taggt es mit Commit-SHA und latest, pusht beide Tags, registriert eine neue Task-Definition mit dem SHA-Tag und aktualisiert den Service. aws ecs wait services-stable wartet, bis das Rolling Deployment abgeschlossen ist. Wenn der Circuit Breaker auslöst, schlägt dieser Schritt fehl und der Workflow wird als fehlgeschlagen markiert.

Secrets-Management

Secrets gehören nicht in Umgebungsvariablen und schon gar nicht in den Terraform-State. AWS Secrets Manager bietet eine saubere Lösung:

# Secret erstellen (Wert wird manuell oder per CLI gesetzt)
resource "aws_secretsmanager_secret" "openai_key" {
  name = "ki-rag-api/openai-api-key"
}
 
# ECS Execution Role darf Secrets lesen
resource "aws_iam_role_policy" "execution_secrets" {
  name = "secrets-access"
  role = aws_iam_role.ecs_execution_role.id
 
  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect = "Allow"
        Action = [
          "secretsmanager:GetSecretValue"
        ]
        Resource = aws_secretsmanager_secret.openai_key.arn
      }
    ]
  })
}

Der Ablauf ist: ECS startet den Container. Die Execution Role holt den Secret-Wert aus Secrets Manager und injiziert ihn als Umgebungsvariable in den Container. Der Secret-Wert erscheint weder im Terraform-State noch in den Container-Logs noch im GitHub Actions Log. Die einzige Stelle, an der der Wert existiert, ist im laufenden Container-Prozess.

Rollback-Strategien

Drei Ebenen von Rollback, je nach Situation:

Automatisch (Circuit Breaker): ECS erkennt, dass die neuen Tasks nicht gesund werden, und rollt auf die vorherige Task-Definition zurück. Kein manuelles Eingreifen nötig. Das passiert typischerweise bei fehlerhaftem Code oder inkompatiblen Model-Versionen.

Manuell (Task-Definition-Revision): Jedes Deployment erstellt eine neue Revision. Wenn du auf eine bestimmte Version zurückrollen willst:

# Aktuelle Revisionen anzeigen
aws ecs list-task-definitions \
  --family-prefix ki-rag-api \
  --sort DESC \
  --max-items 5
 
# Auf eine bestimmte Revision zurückrollen
aws ecs update-service \
  --cluster ki-cluster \
  --service ki-rag-api \
  --task-definition ki-rag-api:42 \
  --force-new-deployment

Image-Level (Commit-SHA): Da jedes Image mit dem Commit-SHA getaggt wird, kannst du exakt nachvollziehen, welcher Code in welcher Revision läuft. Das macht Debugging bei Produktionsproblemen deutlich einfacher als ein generisches latest-Tag.

Rollback-TypTriggerDauerEingriff
Circuit BreakerAutomatisch bei 3x Failure2 bis 5 MinutenKeiner
Task-DefinitionManuell per CLI3 bis 5 MinutenEin Befehl
Commit-SHAManuell per Pipeline5 bis 10 MinutenGit revert + Push

Fazit

GPU-basierte KI-Systeme erfordern drei grundlegende Anpassungen gegenüber klassischen CI/CD-Pipelines:

  1. Zeitliche Anpassung: Health Checks, Grace Periods und Slow Start müssen auf GPU Cold Starts ausgelegt sein. 120 Sekunden statt 30, 60 Sekunden Slow Start statt sofortige Last.

  2. Sicherheitsnetz: Der Circuit Breaker fängt fehlgeschlagene Deployments automatisch ab. In Kombination mit ALB Slow Start entsteht ein doppeltes Sicherheitsnetz, das GPU-Kosten bei fehlerhaften Releases minimiert.

  3. Image-Management: Lifecycle-Policies und eine klare Tagging-Strategie (Commit-SHA + latest) verhindern Kostenwachstum und ermöglichen präzises Rollback.

Die OIDC-Authentifizierung und Least-Privilege-Policies sind keine GPU-spezifischen Themen, aber sie bilden das Fundament für eine sichere Pipeline. Wer Serverless-Deployments auf AWS kennt, wird die Parallelen bei IAM-Rollen und Secrets-Management erkennen.

Im nächsten Artikel gehen wir einen Schritt weiter: die komplette RAG-Infrastruktur auf AWS mit GPU-Clustern, Auto-Scaling und Terraform-Modulen. Wenn du bereits an RAG-Evaluation und Testing arbeitest, schließt die Infrastruktur den Kreis von der Entwicklung über das Testing bis zum produktionsreifen Betrieb.


Sie deployen GPU-basierte KI-Systeme auf AWS und brauchen Unterstützung bei Architektur oder CI/CD? Kontaktieren Sie mich für eine unverbindliche Beratung.