DevOps2024-10-2810 min readBy Abhishek Nair - Fractional CTO für Deep Tech & AI

Moderne Docker-Bereitstellungsstrategien für die Produktion

#Docker#DevOps#CI/CD

Image failed to load

Please refresh the page

Docker-Bereitstellung im Produktionsbetrieb: Ein Leitfaden für Architekten für das Jahr 2025

Basierend auf über 15 Jahren Erfahrung mit der Bereitstellung containerisierter Systeme in großem Maßstab in den Bereichen Full-Stack, KI/ML, IoT und Robotik

Nachdem ich containerisierte Bereitstellungen für alles von Hochfrequenz-Handelsplattformen bis hin zu Flotten autonomer Roboter entworfen habe, habe ich gelernt, dass Docker-Bereitstellungen im Produktionsbetrieb weit mehr erfordern als nur das Schreiben einer Dockerfile. Dieser umfassende Leitfaden fasst die hart erarbeiteten Erkenntnisse aus realen Bereitstellungen zu umsetzbaren Strategien für 2025 und darüber hinaus zusammen.

Inhaltsverzeichnis

  1. Moderne mehrstufige Build-Muster
  2. Sicherheitsorientiertes Container-Design
  3. Zustandsprüfungen und Selbstheilung
  4. Umgebungskonfiguration & Geheimnisse
  5. Produktionsprotokollierung & Beobachtbarkeit
  6. Orchestrierung: Kubernetes vs. Docker Swarm
  7. Domänenspezifische Bereitstellungen
  8. Skalierungsarchitektur-Muster
  9. CI/CD-Integration & GitOps
  10. Überwachung & Fehlerbehebung
  11. Zukunftssichere Bereitstellung

Moderne mehrstufige Build-Muster {#modern-multi-stage-builds}

Mehrstufige Builds sind nicht mehr optional – sie sind für Produktionsbereitstellungen unverzichtbar. Hier erfahren Sie, warum und wie Sie sie effektiv einsetzen:

Probleme, die mehrstufige Builds lösen

  1. Image-Aufblähung: Entwicklungsabhängigkeiten sollten nicht in die Produktion gelangen
  2. Angriffsfläche: Build-Tools stellen unnötige Sicherheitsrisiken in der Laufzeit dar
  3. Reproduzierbarkeit: Trennung von Build und Laufzeit für konsistente Bereitstellungen

Produktionsreifes mehrstufiges Muster

# ======================================== # Stufe 1: Build-Umgebung # ======================================== FROM node:20-alpine AS builder # Nur Build-Abhängigkeiten installieren RUN apk add --no-cache python3 make g++ WORKDIR /build # Optimierung des Layer-Cachings: Abhängigkeitsdateien zuerst kopieren COPY package*.json ./ COPY yarn.lock* ./ # ALLE Abhängigkeiten installieren (einschließlich devDependencies) RUN npm ci # Quellcode kopieren COPY . . # Anwendung erstellen RUN npm run build && \ npm prune --production # ======================================== # Stufe 2: Produktions-Laufzeit # ======================================== FROM node:20-alpine # Sicherheit: Nicht-Root-Benutzer erstellen RUN addgroup -g 1001 -S nodejs && \ adduser -S nodejs -u 1001 # Nur Laufzeitabhängigkeiten installieren RUN apk add --no-cache dumb-init WORKDIR /app # Nur Produktionsartefakte kopieren COPY --from=builder --chown=nodejs:nodejs /build/dist ./dist COPY --from=builder --chown=nodejs:nodejs /build/node_modules ./node_modules COPY --from=builder --chown=nodejs:nodejs /build/package.json ./ # Zu Nicht-Root-Benutzer wechseln USER nodejs # dumb-init für korrekte Signalverarbeitung verwenden ENTRYPOINT ["dumb-init", "--"] # Zustandsprüfung HEALTHCHECK --interval=30s --timeout=3s --start-period=40s --retries=3 \ CMD node -e "require('http').get('http://localhost:3000/health', (r) => { process.exit(r.statusCode === 200 ? 0 : 1) })" EXPOSE 3000 CMD ["node", "dist/index.js"]

Fortgeschrittene mehrstufige Techniken

Für Python-/ML-Anwendungen:

# Build-Phase mit vollständiger Conda-Umgebung FROM continuumio/miniconda3:latest AS builder WORKDIR /build COPY environment.yml . RUN conda env create -f environment.yml && \ conda clean -afy # Produktionsphase mit minimaler Laufzeit FROM python:3.11-slim COPY --from=builder /opt/conda/envs/myenv /opt/conda/envs/myenv ENV PATH="/opt/conda/envs/myenv/bin:$PATH" WORKDIR /app COPY . . CMD ["python", "app.py"]

Wichtige Erkenntnisse:

  • Verwenden Sie immer spezifische Versions-Tags, niemals latest
  • Ordnen Sie Layer nach Änderungshäufigkeit (Abhängigkeiten vor Code)
  • Setzen Sie .dockerignore konsequent ein (node_modules, .git, Tests usw.)
  • Ziehen Sie distroless- oder Scratch-Images für maximale Sicherheit in Betracht

Sicherheitsorientiertes Container-Design {#security-first-design}

Sicherheit muss von Anfang an integriert sein. Hier ist mein praxiserprobter Sicherheitsstack:

1. Auswahl und Scannen des Basis-Images

# Verwende Trivy für das Scannen auf Schwachstellen trivy image --severity HIGH,CRITICAL myapp:latest # Verwende Grype für zusätzliche Abdeckung grype myapp:latest # In CI/CD integrieren docker build -t myapp:${CI_COMMIT_SHA} . trivy image --exit-code 1 --severity CRITICAL myapp:${CI_COMMIT_SHA}

Toolauswahl (2025):

  • Trivy: Bester Open-Source-Scanner, schnell, umfassend (OS-Pakete + App-Abhängigkeiten)
  • Grype: Hervorragendes SBOM-gesteuertes Scannen
  • Snyk: Die Wahl für Unternehmen mit Korrekturvorschlägen und CI/CD-Integrationen
  • Docker Scout: Native Docker-Integration, Echtzeit-Einblicke

2. Muster für Nicht-Root-Benutzer

# FALSCH – Ausführung als Root FROM ubuntu:22.04 COPY app /app CMD ["/app/server"] # RICHTIG – Nicht-Root mit korrekten Berechtigungen FROM ubuntu:22.04 RUN groupadd -r appuser && \ useradd -r -g appuser -u 1001 appuser && \ mkdir /app && \ chown -R appuser:appuser /app COPY --chown=appuser:appuser app /app USER appuser WORKDIR /app CMD ["./server"]

3. Schreibgeschütztes Root-Dateisystem

# docker-compose.yml services: api: image: myapp:latest read_only: true tmpfs: - /tmp:noexec,nosuid,size=100m volumes: - ./data:/app/data security_opt: - no-new-privileges:true cap_drop: - ALL cap_add: - NET_BIND_SERVICE

4. Verwaltung von Geheimnissen

Tun Sie dies NIEMALS:

# FALSCH! ENV DB_PASSWORD=mysecretpassword ENV API_KEY=abc123

Produktionsmuster:

# Verwendung von Docker Swarm-Geheimnissen version: '3.8' services: app: image: myapp:latest environment: - NODE_ENV=production - DATABASE_URL_FILE=/run/secrets/db_url secrets: - db_url - api_key deploy: replicas: 3 secrets: db_url: external: true api_key: external: true

Für Kubernetes:

apiVersion: v1 kind: Secret metadata: name: app-secrets type: Opaque stringData: database-url: "postgresql://..." api-key: "..." --- apiVersion: apps/v1 kind: Deployment metadata: name: myapp spec: template: spec: containers: - name: app envFrom: - secretRef: name: app-secrets

Enterprise-Muster: Externe Secret-Manager verwenden

# Verwendung des External Secrets Operators apiVersion: external-secrets.io/v1beta1 kind: SecretStore metadata: name: vault-backend spec: provider: vault: server: "https://vault.company.com" auth: kubernetes: mountPath: "kubernetes" --- apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret metadata: name: app-secrets spec: secretStoreRef: name: vault-backend target: name: app-secrets data: - secretKey: database-url remoteRef: key: secret/data/app/database property: url

5. Signieren und Verifizieren von Images

# Images mit Cosign signieren (Standard 2025) cosign sign --key cosign.key myregistry/myapp:v1.0 # Vor der Bereitstellung verifizieren cosign verify --key cosign.pub myregistry/myapp:v1.0

Zustandsprüfungen und Selbstheilung {#health-checks}

Ordnungsgemäße Zustandsprüfungen machen den Unterschied zwischen einer Verfügbarkeit von 99,9 % und 99,99 %.

Zustandsprüfungen in Dockerfiles

# Einfacher HTTP-Zustandscheck HEALTHCHECK --interval=30s --timeout=3s --start-period=40s --retries=3 \ CMD wget --no-verbose --tries=1 --spider http://localhost:3000/health || exit 1 # Erweiterter Zustandscheck mit Abhängigkeiten HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \ CMD curl -f http://localhost:8080/health/ready || exit 1

Zustands-Endpunkte auf Anwendungsebene

// Express.js-Muster für den Zustandscheck const express = require('express'); const app = express(); let isReady = false; // Liveness: Läuft die Anwendung? app.get('/health/live', (req, res) => { res.status(200).json({ status: 'alive', timestamp: Date.now() }); }); // Bereitschaft: Ist die Anwendung bereit, Datenverkehr zu bedienen? app.get('/health/ready', async (req, res) => { try { // Datenbankverbindung prüfen await db.ping(); // Redis-Verbindung prüfen await redis.ping(); // Externe API-Abhängigkeiten prüfen await checkExternalServices(); res.status(200).json({ status: 'ready', timestamp: Date.now(), dependencies: { db: 'ok', cache: 'ok', apis: 'ok' } }); } catch (error) { res.status(503).json({ status: 'not ready', error: error.message, timestamp: Date.now() }); } }); // Startup: Ist die Initialisierung abgeschlossen? app.get('/health/startup', (req, res) => { if (isReady) { res.status(200).json({ status: 'started' }); } else { res.status(503).json({ status: 'starting' }); } });

Kubernetes-Probes (Produktionsmuster)

apiVersion: apps/v1 kind: Deployment metadata: name: myapp spec: replicas: 3 template: spec: containers: - name: app image: myapp:v1.0 ports: - containerPort: 8080 # Startup-Probe: Gibt der App Zeit zur Initialisierung startupProbe: httpGet: path: /health/startup port: 8080 failureThreshold: 30 periodSeconds: 10 # Liveness-Probe: Neustart bei Fehlerzustand livenessProbe: httpGet: path: /health/live port: 8080 initialDelaySeconds: 0 periodSeconds: 10 timeoutSeconds: 5 failureThreshold: 3 # Bereitschaftsprüfung: Aus dem Dienst entfernen, wenn nicht bereit readinessProbe: httpGet: path: /health/ready port: 8080 initialDelaySeconds: 5 periodSeconds: 5 timeoutSeconds: 3 successThreshold: 1 failureThreshold: 3

Wichtiger Hinweis: Trennen Sie „Liveness“ von „Readiness“. Fehler bei der Liveness führen zum Neustart von Pods; Fehler bei der Readiness entfernen sie lediglich aus den Load Balancern. Ein Fehler in einer Abhängigkeit sollte sich auf die Readiness auswirken, nicht auf die Liveness.


Umgebungskonfiguration & Secrets {#configuration-management}

Konfigurationsmanagement entscheidet über Erfolg oder Misserfolg von Produktionsbereitstellungen. Hier ist die Hierarchie, die ich verwende:

Konfigurationshierarchie

1. Secrets (niemals im Code oder in Konfigurationsdateien)
2. Umgebungsvariablen (deployment-spezifisch)
3. Konfigurationsdateien (als Volumes gemountet)
4. Anwendungsstandardwerte (im Code)

Docker Compose-Produktionsmuster

version: '3.8' services: api: image: ${REGISTRY}/myapp:${VERSION} environment: - NODE_ENV=production - LOG_LEVEL=${LOG_LEVEL:-info} - DATABASE_URL=${DATABASE_URL} env_file: - .env.production secrets: - db_password - jwt_secret configs: - source: app_config target: /app/config/production.yml deploy: replicas: 3 restart_policy: condition: on-failure delay: 5s max_attempts: 3 window: 120s update_config: parallelism: 1 delay: 10s failure_action: rollback monitor: 30s resources: limits: cpus: '2' memory: 2G reservations: cpus: '1' memory: 1G secrets: db_password: external: true jwt_secret: external: true configs: app_config: file: ./config/production.yml

Kubernetes ConfigMap + Secret-Muster

apiVersion: v1 kind: ConfigMap metadata: name: app-config data: app.yml: | server: port: 8080 timeout: 30s features: newFeature: true logging: level: info --- apiVersion: apps/v1 kind: Deployment spec: template: spec: containers: - name: app volumeMounts: - name: config mountPath: /app/config readOnly: true - name: secrets mountPath: /app/secrets readOnly: true volumes: - name: config configMap: name: app-config - name: secrets secret: secretName: app-secrets

Protokollierung und Beobachtbarkeit in der Produktion {#logging-observability}

Protokollierung ist kein optionales Extra. Hier ist mein Produktions-Stack:

Strukturiertes Protokollierungsmuster

// Winston-Konfiguration für die Produktion const winston = require('winston'); const { ElasticsearchTransport } = require('winston-elasticsearch'); const logger = winston.createLogger({ level: process.env.LOG_LEVEL || 'info', format: winston.format.combine( winston.format.timestamp(), winston.format.errors({ stack: true }), winston.format.json() ), defaultMeta: { service: 'myapp', version: process.env.VERSION, environment: process.env.NODE_ENV }, transports: [ // Konsole für Docker-Protokolle new winston.transports.Console({ format: winston.format.combine( winston.format.colorize(), winston.format.simple() ) }), // Elasticsearch für zentralisierte Protokollierung new ElasticsearchTransport({ level: 'info', clientOpts: { node: process.env.ELASTICSEARCH_URL, auth: { username: process.env.ES_USER, password: process.env.ES_PASSWORD } } }) ], exceptionHandlers: [ new winston.transports.File({ filename: 'exceptions.log' }) ], rejectionHandlers: [ new winston.transports.File({ filename: 'rejections.log' }) ] }); // Middleware zur Korrelation von Anfragen app.use((req, res, next) => { req.id = req.headers['x-request-id'] || uuid.v4(); req.logger = logger.child({ requestId: req.id }); next(); });

Docker-Logging-Konfiguration

# docker-compose.yml services: api: image: myapp:latest logging: driver: "json-file" options: max-size: "10m" max-file: "3" labels: "service,environment" labels: service: "api" environment: "production"

Produktions-Observability-Stack (2025)

version: '3.8' services: # Anwendung myapp: image: myapp:latest environment: - OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4318 - OTEL_SERVICE_NAME=myapp - OTEL_RESOURCE_ATTRIBUTES=environment=production,version=${VERSION} depends_on: - otel-collector # OpenTelemetry Collector otel-collector: image: otel/opentelemetry-collector-contrib:latest command: ["--config=/etc/otel-collector-config.yml"] volumes: - ./otel-collector-config.yml:/etc/otel-collector-config.yml ports: - "4317:4317" # OTLP gRPC-Empfänger - "4318:4318" # OTLP HTTP-Empfänger # Prometheus (Metriken) prometheus: image: prom/prometheus:latest volumes: - ./prometheus.yml:/etc/prometheus/prometheus.yml - prometheus-data:/prometheus ports: - "9090:9090" # Grafana (Visualisierung) grafana: image: grafana/grafana:latest environment: - GF_SECURITY_ADMIN_PASSWORD=secret volumes: - grafana-data:/var/lib/grafana - ./grafana/dashboards:/etc/grafana/provisioning/dashboards - ./grafana/datasources:/etc/grafana/provisioning/datasources ports: - "3000:3000" # Loki (Protokolle) loki: image: grafana/loki:latest ports: - "3100:3100" Volumes: - ./loki-config.yml:/etc/loki/local-config.yml - loki-data:/loki # Tempo (Traces) tempo: Image: grafana/tempo:latest Befehl: [ "-config.file=/etc/tempo.yml" ] Volumes: - ./tempo.yml:/etc/tempo.yml - tempo-data:/tmp/tempo # Jaeger (Alternative verteilte Tracing-Lösung) jaeger: image: jaegertracing/all-in-one:latest environment: - COLLECTOR_OTLP_ENABLED=true ports: - "16686:16686" # Jaeger-UI - "14268:14268" # Collector HTTP - "4317:4317" # OTLP gRPC Volumes: prometheus-data: grafana-data: loki-data: tempo-data:

Anwendungsinstrumentierung

// OpenTelemetry-Instrumentierung const { NodeSDK } = require('@opentelemetry/sdk-node'); const { PrometheusExporter } = require('@opentelemetry/exporter-prometheus'); const { OTLPTraceExporter } = require('@opentelemetry/exporter-trace-otlp-http'); const sdk = new NodeSDK({ traceExporter: new OTLPTraceExporter({ url: process.env.OTEL_EXPORTER_OTLP_ENDPOINT + '/v1/traces', }), metricReader: new PrometheusExporter({ port: 9464, }), serviceName: 'myapp', }); sdk.start(); process.on('SIGTERM', () => { sdk.shutdown() .then(() => console.log('Tracing terminated')) .catch((error) => console.log('Error terminating tracing', error)) .finally(() => process.exit(0)); });

Orchestrierung: Kubernetes vs. Docker Swarm {#orchestration-choice}

Die ewige Frage. Hier ist mein Entscheidungsrahmen, nachdem ich beide in der Produktion eingesetzt habe:

Entscheidungsmatrix

FaktorKubernetesDocker Swarm
Teamgröße5+ Entwickler2–4 Entwickler
KomplexitätHoch (steile Lernkurve)Niedrig (Docker-nativ)
ÖkosystemRiesig (über 70 % Marktanteil)Begrenzt, aber stabil
Multi-CloudHervorragendBegrenzt
Ressourcen-OverheadHöherGeringer
Erweiterte FunktionenStatefulSets, Jobs, CronJobs, Custom ResourcesGrundlegende Orchestrierung
Community-SupportUmfangreichBegrenzt
Am besten geeignet fürGroß angelegte, komplexe BereitstellungenKleine bis mittlere Bereitstellungen

Wann sollte man sich für Kubernetes entscheiden?

  • Skalierung: Betrieb von mehr als 50 Diensten oder mehr als 100 Containern
  • Multi-Cloud: Bereitstellung über AWS, GCP und Azure hinweg
  • Erweiterte Muster: Bedarf an Service Mesh, GitOps, benutzerdefinierten Operatoren
  • Teamkompetenz: Ingenieure, die mit K8s vertraut sind
  • Ökosystem: Bedarf an Helm-Charts, Operatoren, CNCF-Tools

Wann sollte man sich für Docker Swarm entscheiden?

  • Einfachheit: Kleines Team, unkomplizierte Bereitstellung
  • Docker-nativ: Man nutzt bereits Docker Compose
  • Begrenzte Ressourcen: Edge-Bereitstellungen, kleine Cluster
  • Schnelle Bereitstellung: Man muss schnell bereitstellen, ohne die Komplexität von K8s
  • Lernkurve: Das Team hat noch keine Erfahrung mit Orchestrierung

Docker Swarm-Produktionskonfiguration

# Swarm initialisieren docker swarm init --advertise-addr <manager-ip># Worker hinzufügen docker swarm join --token <worker-token> <manager-ip>:2377 # Stack bereitstellen docker stack deploy -c docker-compose.yml myapp # Dienst skalieren docker service scale myapp_api=5 # Rollendes Update docker service update --image myapp:v2 myapp_api # Überwachen docker service ls docker service ps myapp_api

Kubernetes-Produktionskonfiguration (K3s für Edge/IoT)

# K3s (Lightweight K8s) installieren curl -sfL https://get.k3s.io | sh - # Anwendung bereitstellen kubectl apply -f deployment.yml # Skalieren kubectl scale deployment myapp --replicas=5 # Rollendes Update kubectl set image deployment/myapp app=myapp:v2 # Überwachen kubectl get pods kubectl top pods kubectl logs -f deployment/myapp

Hybrider Ansatz: K3s/K8s am Edge, K8s in der Cloud

# Edge-K3s-Cluster (ressourcenbeschränkt) apiVersion: v1 kind: Namespace metadata: name: edge-production --- apiVersion: apps/v1 kind: Deployment metadata: name: edge-processor namespace: edge-production spec: replicas: 2 template: spec: containers: - name: processor image: myapp:edge resources: requests: memory: &quot;128Mi&quot; cpu: &quot;100m&quot; limits: memory: &quot;256Mi&quot; cpu: &quot;200m&quot; nodeSelector: node-role.kubernetes.io/edge: &quot;true&quot; tolerations: - key: &quot;node-role.kubernetes.io/edge&quot; operator: &quot;Exists&quot; effect: &quot;NoSchedule&quot;

Domänenspezifische Deployments {#domain-specific}

Full-Stack-Anwendungen {#fullstack}

Frontend + Backend + Datenbank-Muster

version: &#x27;3.8&#x27; services: # Frontend (React/Next.js) frontend: build: context: ./frontend dockerfile: Dockerfile.prod ports: - &quot;80:80&quot; - &quot;443:443&quot; depends_on: - backend volumes: - ./nginx.conf:/etc/nginx/nginx.conf:ro - certbot-certs:/etc/letsencrypt - certbot-webroot:/var/www/certbot deploy: replicas: 2 resources: limits: cpus: &#x27;0.5&#x27; memory: 256M # Backend (Node.js/Python/Go) backend: image: ${REGISTRY}/backend:${VERSION} environment: - NODE_ENV=production - DATABASE_URL=postgresql://postgres:5432/mydb - REDIS_URL=redis://redis:6379 depends_on: - db - redis deploy: replicas: 3 resources: limits: cpus: &#x27;1&#x27; memory: 1G restart_policy: condition: on-failure # Datenbank (PostgreSQL) db: image: postgres:16-alpine Umgebung: POSTGRES_PASSWORD_FILE: /run/secrets/db_password Volumes: - postgres-data:/var/lib/postgresql/data - ./init.sql:/docker-entrypoint-initdb.d/init.sql Geheimnisse: - db_password Bereitstellung: Platzierung: Einschränkungen: - node.labels.db == true # Cache (Redis) redis: Image: redis:7-alpine Befehl: redis-server --appendonly yes Volumes: - redis-data:/data # Hintergrundaufträge (Celery/Bull) worker: image: ${REGISTRY}/backend:${VERSION} command: celery -A app.celery worker --loglevel=info depends_on: - redis - db deploy: replicas: 2 volumes: postgres-data: redis-data: certbot-certs: certbot-webroot: secrets: db_password: external: true

Nginx-Konfiguration für die Produktion

# nginx.conf upstream backend { least_conn; server backend:8080 max_fails=3 fail_timeout=30s; server backend:8080 max_fails=3 fail_timeout=30s; server backend:8080 max_fails=3 fail_timeout=30s; } server { listen 80; server_name example.com www.example.com; # HTTP zu HTTPS umleiten return 301 https://$host$request_uri; } server { listen 443 ssl http2; server_name example.com www.example.com; ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # Moderne SSL-Konfiguration ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5;</manager-ip></worker-token></manager-ip> ssl_prefer_server_ciphers on; # Sicherheits-Header add_header Strict-Transport-Security &quot;max-age=31536000; includeSubDomains&quot; always; add_header X-Frame-Options &quot;SAMEORIGIN&quot; always; add_header X-Content-Type-Options &quot;nosniff&quot; always; add_header X-XSS-Protection &quot;1; mode=block&quot; always; # Statische Dateien location /static { alias /usr/share/nginx/html/static; expires 1y; add_header Cache-Control &quot;public, immutable&quot;; } # API-Proxy location /api { proxy_pass http://backend; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_connect_timeout 30s; proxy_send_timeout 30s; proxy_read_timeout 30s; } # SPA-Fallback location / { root /usr/share/nginx/html; try_files $uri $uri/ /index.html; } }

Bereitstellung von KI-/ML-Modellen {#ai-ml}

GPU-beschleunigte ML-Bereitstellung

# Dockerfile für PyTorch/TensorFlow mit GPU FROM nvidia/cuda:12.1.0-cudnn8-runtime-ubuntu22.04 # Python und Abhängigkeiten installieren RUN apt-get update &amp;&amp; apt-get install -y \ python3.11 \ python3-pip \ &amp;&amp; rm -rf /var/lib/apt/lists/* WORKDIR /app # ML-Frameworks installieren COPY requirements.txt . RUN pip3 install --no-cache-dir -r requirements.txt # Modell und Anwendung kopieren COPY models/ ./models/ COPY app.py . # Nicht-Root-Benutzer RUN useradd -m -u 1001 mluser &amp;&amp; \ chown -R mluser:mluser /app USER mluser # API freigeben EXPOSE 8000 # Mit Gunicorn + Uvicorn-Workern ausführen CMD [&quot;gunicorn&quot;, &quot;app:app&quot;, \ &quot;--workers&quot;, &quot;4&quot;, \ &quot;--worker-class&quot;, &quot;uvicorn.workers.UvicornWorker&quot;, \ &quot;--bind&quot;, &quot;0.0.0.0:8000&quot;, \ &quot;--timeout&quot;, &quot;120&quot;]

Kubernetes-ML-Deployment mit GPU

apiVersion: apps/v1 kind: Deployment metadata: name: ml-inference spec: replicas: 2 template: spec: containers: - name: model-server image: myregistry/ml-model:v1.0 ports: - containerPort: 8000 resources: requests: memory: &quot;4Gi&quot; cpu: &quot;2&quot; nvidia.com/gpu: 1 limits: memory: &quot;8Gi&quot; cpu: &quot;4&quot; nvidia.com/gpu: 1 env: - name: MODEL_PATH value: &quot;/models/my-model&quot; - name: BATCH_SIZE value: &quot;32&quot; volumeMounts: - name: models mountPath: /models readOnly: true livenessProbe: httpGet: path: /health port: 8000 initialDelaySeconds: 60 periodSeconds: 30 readinessProbe: httpGet: path: /ready port: 8000 initialDelaySeconds: 30 periodSeconds: 10 volumes: - name: models persistentVolumeClaim: claimName: model-storage nodeSelector: accelerator: nvidia-tesla-t4 tolerations: - key: nvidia.com/gpu operator: Exists effect: NoSchedule

FastAPI-ML-Serving-Muster

from fastapi import FastAPI, HTTPException from pydantic import BaseModel import torch import numpy as np from typing import List import logging app = FastAPI() # Modell beim Start laden model = None @app.on_event(&quot;startup&quot;) async def load_model(): global model model = torch.load(&#x27;/models/my-model.pth&#x27;) model.eval() logging.info(&quot;Modell erfolgreich geladen&quot;) class PredictionRequest(BaseModel): data: List[List[float]] class PredictionResponse(BaseModel): predictions: List[float] confidence: List[float] @app.post(&quot;/predict&quot;, response_model=PredictionResponse) async def predict(request: PredictionRequest): try: input_tensor = torch.tensor(request.data, dtype=torch.float32) with torch.no_grad(): output = model(input_tensor) predictions = output.argmax(dim=1).tolist() confidence = torch.softmax(output, dim=1).max(dim=1).values.tolist() return PredictionResponse( predictions=predictions, confidence=confidence ) except Exception as e: logging.error(f&quot;Vorhersagefehler: {e}&quot;) raise HTTPException(status_code=500, detail=str(e)) @app.get(&quot;/health&quot;) async def health(): return {&quot;status&quot;: &quot;healthy&quot;, &quot;model_loaded&quot;: model is not None} @app.get(&quot;/metrics&quot;) async def metrics(): # Prometheus-Metrik-Endpunkt return {&quot;requests_total&quot;: 1000, &quot;avg_latency_ms&quot;: 45}

MLOps-Pipeline mit Modell-Registry

version: &#x27;3.8&#x27; services: # MLflow für die Experimentverfolgung mlflow: image: ghcr.io/mlflow/mlflow:latest command: mlflow server --host 0.0.0.0 --backend-store-uri postgresql://mlflow:password@db:5432/mlflow --default-artifact-root s3://mlflow-artifacts Ports: - &quot;5000:5000&quot; Umgebung: - AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID} - AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY} abhängig von: - db # Modellbereitstellung model-server: image: myregistry/ml-model:${MODEL_VERSION} environment: - MLFLOW_TRACKING_URI=http://mlflow:5000 - MODEL_NAME=my-production-model - MODEL_STAGE=Production depends_on: - mlflow deploy: replicas: 3 resources: limits: nvidia.com/gpu: 1

IoT & Edge Computing {#iot-edge}

Edge-Bereitstellung mit K3s

# Dockerfile für ARM64-Edge-Geräte FROM arm64v8/python:3.11-slim # Systemabhängigkeiten installieren RUN apt-get update &amp;&amp; apt-get install -y \ build-essential \ libgpiod2 \ &amp;&amp; rm -rf /var/lib/apt/lists/* WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY . . # Mit Ressourcenbeschränkungen ausführen CMD [&quot;python3&quot;, &quot;edge_processor.py&quot;]

IoT-Stack mit MQTT

version: &#x27;3.8&#x27; services: # MQTT-Broker (Eclipse Mosquitto) mqtt: image: eclipse-mosquitto:2 ports: - &quot;1883:1883&quot; - &quot;9001:9001&quot; volumes: - ./mosquitto.conf:/mosquitto/config/mosquitto.conf - mosquitto-data:/mosquitto/data - mosquitto-logs:/mosquitto/log # IoT-Gateway gateway: image: myregistry/iot-gateway:latest environment: - MQTT_BROKER=mqtt://mqtt:1883 - DEVICE_ID=${DEVICE_ID} - CLOUD_ENDPOINT=${CLOUD_ENDPOINT} depends_on: - mqtt devices: - &quot;/dev/ttyUSB0:/dev/ttyUSB0&quot; privileged: true deploy: resources: limits: cpus: &#x27;0.5&#x27; memory: 256M # Edge Analytics analytics: image: myregistry/edge-analytics:latest environment: - MQTT_BROKER=mqtt://mqtt:1883 - INFLUXDB_URL=http://influxdb:8086 depends_on: - mqtt - influxdb # Zeitreihendatenbank influxdb: image: influxdb:2.7-alpine ports: - &quot;8086:8086&quot; volumes: - influxdb-data:/var/lib/influxdb2 environment: - INFLUXDB_DB=iot_data - INFLUXDB_HTTP_AUTH_ENABLED=true # Grafana zur Visualisierung grafana: image: grafana/grafana:latest ports: - &quot;3000:3000&quot; Volumes: - grafana-data:/var/lib/grafana depends_on: - influxdb Volumes: mosquitto-data: mosquitto-logs: influxdb-data: grafana-data:

Best Practices für Edge Computing

# edge_processor.py – Optimiert für Geräte mit begrenzten Ressourcen import paho.mqtt.client as mqtt import json import logging from collections import deque import time class EdgeProcessor: def __init__(self): self.mqtt_client = mqtt.Client() self.buffer = deque(maxlen=1000) # Ringpuffer self.batch_size = 100 self.last_upload = time.time() def process_sensor_data(self, data): # Edge-Verarbeitung: Rauschen filtern, aggregieren, komprimieren if self.is_valid(data): processed = self.preprocess(data) self.buffer.append(processed) # Batch-Upload in die Cloud if len(self.buffer) &gt;= self.batch_size or \ time.time() - self.last_upload &gt; 300: # 5 min self.upload_batch() def preprocess(self, data): # Leichte Inferenz am Edge ausführen return { &#x27;timestamp&#x27;: data[&#x27;timestamp&#x27;], &#x27;value&#x27;: data[&#x27;value&#x27;], &#x27;anomaly&#x27;: self.detect_anomaly(data[&#x27;value&#x27;]) } def upload_batch(self): if self.buffer: batch = list(self.buffer) self.mqtt_client.publish(&#x27;cloud/data&#x27;, json.dumps(batch)) self.buffer.clear() self.last_upload = time.time()

Robotiksysteme (ROS/ROS2) {#robotics}

ROS2-Docker-Bereitstellung

# Dockerfile für ROS2 Humble FROM ros:humble-ros-base-jammy # Abhängigkeiten installieren RUN apt-get update &amp;&amp; apt-get install -y \ ros-humble-navigation2 \ ros-humble-slam-toolbox \ ros-humble-robot-localization \ python3-colcon-common-extensions \ &amp;&amp; rm -rf /var/lib/apt/lists/* WORKDIR /ros2_ws # Arbeitsbereich kopieren COPY src/ src/ # ROS2-Arbeitsbereich erstellen RUN . /opt/ros/humble/setup.sh &amp;&amp; \ colcon build --symlink-install --cmake-args -DCMAKE_BUILD_TYPE=Release # Einstiegspunkt einrichten COPY ./ros_entrypoint.sh / RUN chmod +x /ros_entrypoint.sh ENTRYPOINT [&quot;/ros_entrypoint.sh&quot;] CMD [&quot;ros2&quot;, &quot;launch&quot;, &quot;my_robot&quot;, &quot;robot.launch.py&quot;]

Verwaltung einer Multi-Roboter-Flotte

version: &#x27;3.8&#x27; services: # ROS-Master / Discovery-Server ros2-discovery: image: ros:humble command: ros2 daemon start network_mode: host environment: - ROS_DOMAIN_ID=0 # Roboter 1 robot1: image: myregistry/robot:v1.0 environment: - ROBOT_ID=robot1 - ROS_DOMAIN_ID=0 - ROBOT_NAMESPACE=/robot1 devices: - /dev/video0:/dev/video0 - /dev/ttyACM0:/dev/ttyACM0 privileged: true network_mode: host # Roboter 2 robot2: image: myregistry/robot:v1.0 environment: - ROBOT_ID=robot2 - ROS_DOMAIN_ID=0 - ROBOT_NAMESPACE=/robot2 devices: - /dev/video1:/dev/video1 - /dev/ttyACM1:/dev/ttyACM1 privileged: true network_mode: host # Flottenmanager fleet-manager: image: myregistry/fleet-manager:latest ports: - &quot;8080:8080&quot; Umgebung: - ROS_DOMAIN_ID=0 Netzwerkmodus: host abhängig von: - ros2-discovery # Visualisierung (RViz) rviz: Image: myregistry/robot:v1.0 Befehl: ros2 run rviz2 rviz2 Umgebung: - DISPLAY=$DISPLAY - ROS_DOMAIN_ID=0 volumes: - /tmp/.X11-unix:/tmp/.X11-unix:rw network_mode: host

Skalierungsarchitektur-Muster {#scaling-patterns}

Horizontale Pod-Autoskalierung (HPA)

apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: myapp-hpa spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: myapp minReplicas: 3 maxReplicas: 20 metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 70 - type: Resource resource: name: memory target: type: Utilization averageUtilization: 80 - type: Pods Pods: Metrik: Name: http_requests_per_second Ziel: Typ: Durchschnittswert Durchschnittswert: „1000“ Verhalten: ScaleDown: Stabilisierungsfenster in Sekunden: 300 Richtlinien: - Typ: Prozent Wert: 50 Zeitraum in Sekunden: 60 scaleUp: stabilizationWindowSeconds: 0 policies: - type: Percent value: 100 periodSeconds: 30 - type: Pods value: 4 periodSeconds: 30 selectPolicy: Max

Vertikale Pod-Autoskalierung (VPA)

apiVersion: autoscaling.k8s.io/v1 kind: VerticalPodAutoscaler metadata: name: myapp-vpa spec: targetRef: apiVersion: &quot;apps/v1&quot; kind: Deployment name: myapp updatePolicy: updateMode: &quot;Auto&quot; resourcePolicy: containerPolicies: - containerName: &#x27;*&#x27; minAllowed: cpu: 100m memory: 128Mi maxAllowed: cpu: 4 memory: 8Gi controlledResources: [&quot;cpu&quot;, &quot;memory&quot;]

Cluster-Autoskalierung (Cloud-Anbieter)

# AWS EKS-Knotengruppe mit automatischer Skalierung apiVersion: eksctl.io/v1alpha5 kind: ClusterConfig metadata: name: production-cluster region: us-west-2 managedNodeGroups: - name: general-purpose instanceType: t3.xlarge minSize: 3 maxSize: 10 desiredCapacity: 5 volumeSize: 100 ssh: allow: false labels: role: general tags: nodegroup-role: general iam: withAddonPolicies: autoScaler: true cloudWatch: true ebs: true - name: gpu-nodes instanceType: g4dn.xlarge minSize: 0 maxSize: 5 desiredCapacity: 0 volumeSize: 200 labels: accelerator: nvidia-tesla-t4 taints: - key: nvidia.com/gpu value: &quot;true&quot; effect: NoSchedule

Service Mesh für erweitertes Traffic-Management

# Istio VirtualService für Canary-Bereitstellung apiVersion: networking.istio.io/v1beta1 kind: VirtualService metadata: name: myapp spec: hosts: - myapp.example.com http: - match: - headers: user-agent: regex: &quot;.*Mobile.*&quot; route: - destination: host: myapp Teilmenge: v2 Gewichtung: 100 - Route: - Ziel: Host: myapp Teilmenge: v1 Gewichtung: 90 - Ziel: Host: myapp Teilmenge: v2 Gewichtung: 10 --- apiVersion: networking.istio.io/v1beta1 kind: DestinationRule metadata: name: myapp spec: host: myapp trafficPolicy: connectionPool: tcp: maxConnections: 100 http: http1MaxPendingRequests: 50 http2MaxRequests: 100 outlierDetection: consecutiveErrors: 5 interval: 30s baseEjectionTime: 30s maxEjectionPercent: 50 subsets: - name: v1 labels: version: v1 - name: v2 labels: version: v2

Skalierungsmuster für Datenbanken

# PostgreSQL mit Replikation version: &#x27;3.8&#x27; services: postgres-primary: image: postgres:16-alpine environment: POSTGRES_PASSWORD_FILE: /run/secrets/db_password POSTGRES_REPLICATION_MODE: master POSTGRES_REPLICATION_USER: replicator POSTGRES_REPLICATION_PASSWORD_FILE: /run/secrets/repl_password volumes: - postgres-primary-data:/var/lib/postgresql/data deploy: placement: constraints: - node.labels.db.primary == true postgres-replica1: image: postgres:16-alpine environment: POSTGRES_PASSWORD_FILE: /run/secrets/db_password POSTGRES_REPLICATION_MODE: slave POSTGRES_MASTER_SERVICE: postgres-primary POSTGRES_REPLICATION_USER: replicator POSTGRES_REPLICATION_PASSWORD_FILE: /run/secrets/repl_password volumes: - postgres-replica1-data:/var/lib/postgresql/data depends_on: - postgres-primary # Schreibgeschützter Verbindungspooler pgbouncer: image: pgbouncer/pgbouncer:latest environment: - DATABASES_HOST=postgres-primary - DATABASES_PORT=5432 - DATABASES_DBNAME=mydb - PGBOUNCER_POOL_MODE=transaction - PGBOUNCER_MAX_CLIENT_CONN=1000 - PGBOUNCER_DEFAULT_POOL_SIZE=25 ports: - &quot;6432:6432&quot;

CI/CD-Integration & GitOps {#cicd-gitops}

GitHub Actions CI/CD-Pipeline

# .github/workflows/deploy.yml name: Build and Deploy on: push: branches: [ main, develop ] pull_request: branches: [ main ] env: REGISTRY: ghcr.io IMAGE_NAME: ${{ github.repository }} jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Tests ausführen run: | docker compose -f docker-compose.test.yml up --abort-on-container-exit docker compose -f docker-compose.test.yml down security-scan: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Image erstellen run: docker build -t ${{ env.IMAGE_NAME}}:${{ github.sha }} . - name: Trivy-Schwachstellenscanner ausführen uses: aquasecurity/trivy-action@master with: image-ref: ${{ env.IMAGE_NAME }}:${{ github.sha }} format: &#x27;sarif&#x27; output: &#x27;trivy-results.sarif&#x27; severity: &#x27;CRITICAL,HIGH&#x27; exit-code: &#x27;1&#x27; - name: Trivy-Ergebnisse auf GitHub Security hochladen uses: github/codeql-action/upload-sarif@v2 if: always() with: sarif_file: &#x27;trivy-results.sarif&#x27; build-and-push: needs: [test, security-scan] runs-on: ubuntu-latest Berechtigungen: Inhalte: Lesen Pakete: Schreiben Schritte: - Verwendet: actions/checkout@v4 - Name: Bei Container Registry anmelden Verwendet: docker/login-action@v3 Mit: Registry: ${{ env.REGISTRY }} Benutzername: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Metadaten extrahieren id: meta uses: docker/metadata-action@v5 with: images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} tags: | type=ref,event=branch type=ref,event=pr type=semver,pattern={{version}} type=semver,pattern={{major}}.{{minor}} type=sha,prefix={{branch}}- - name: Docker-Image erstellen und pushen uses: docker/build-push-action@v5 with: context: . push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max - name: Image mit Cosign signieren run: | cosign sign --yes ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build.outputs.digest }} env: COSIGN_EXPERIMENTAL: &quot;true&quot; deploy-staging: needs: build-and-push if: github.ref == &#x27;refs/heads/develop&#x27; runs-on: ubuntu-latest environment: staging steps: - name: Auf Staging bereitstellen run: | kubectl set image deployment/myapp \ app=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:develop-${{ github.sha }} \ --namespace=staging deploy-production: needs: build-and-push if: github.ref == &#x27;refs/heads/main&#x27; runs-on: ubuntu-latest environment: production steps: - name: Bereitstellung in der Produktionsumgebung run: | kubectl set image deployment/myapp \ app=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }} \ --namespace=production - name: Auf Rollout warten run: | kubectl rollout status deployment/myapp --namespace=production --timeout=5m - name: Smoke-Tests ausführen run: | curl -f https://api.example.com/health || (kubectl rollout undo deployment/myapp --namespace=production &amp;&amp; exit 1)

GitOps mit ArgoCD

# argocd-application.yaml apiVersion: argoproj.io/v1alpha1 kind: Application metadata: name: myapp namespace: argocd spec: project: default source: repoURL: https://github.com/myorg/myapp-k8s-manifests targetRevision: HEAD path: overlays/production kustomize: images: - myregistry/myapp:v1.2.3 destination: server: https://kubernetes.default.svc namespace: production syncPolicy: automated: prune: true selfHeal: true allowEmpty: false syncOptions: - CreateNamespace=true - PrunePropagationPolicy=foreground - PruneLast=true retry: limit: 5 backoff: duration: 5s factor: 2 maxDuration: 3m revisionHistoryLimit: 10

Blue-Green-Bereitstellungsstrategie

# Blue-Green mit Kubernetes apiVersion: v1 kind: Service metadata: name: myapp spec: selector: app: myapp version: blue # Für die Bereitstellung auf „green“ umschalten ports: - port: 80 targetPort: 8080 --- apiVersion: apps/v1 kind: Deployment metadata: name: myapp-blue spec: replicas: 3 selector: matchLabels: app: myapp version: blue template: metadata: labels: app: myapp version: blue spec: containers: - name: app image: myapp:v1.0 --- apiVersion: apps/v1 kind: Deployment metadata: name: myapp-green spec: replicas: 3 selector: matchLabels: app: myapp version: green template: metadata: labels: app: myapp version: green spec: containers: - name: app image: myapp:v2.0

Überwachung & Fehlerbehebung {#monitoring}

Einrichtung der Prometheus-Überwachung

# prometheus.yml global: scrape_interval: 15s evaluation_interval: 15s alerting: alertmanagers: - static_configs: - targets: - alertmanager:9093 rule_files: - /etc/prometheus/alerts/*.yml scrape_configs: - job_name: &#x27;prometheus&#x27; static_configs: - targets: [&#x27;localhost:9090&#x27;] - job_name: &#x27;docker&#x27; docker_sd_configs: - host: unix:///var/run/docker.sock relabel_configs: - source_labels: [__meta_docker_container_name] target_label: container - job_name: &#x27;kubernetes-pods&#x27; kubernetes_sd_configs: - role: pod relabel_configs: - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape] action: keep regex: true - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path] action: replace target_label: __metrics_path__ regex: (.+) - source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port] action: replace regex: ([^:]+)(?::\d+)?;(\d+) replacement: $1:$2 target_label: __address__

Alarmregeln

# alerts.yml groups: - name: application_alerts interval: 30s rules: - alert: HighErrorRate expr: | ( sum(rate(http_requests_total{status=~&quot;5..&quot;}[5m])) / sum(rate(http_requests_total[5m])) ) &gt; 0.05 for: 5m labels: severity: critical annotations: summary: &quot;Hohe Fehlerrate festgestellt&quot; description: &quot;Die Fehlerrate beträgt {{ $value | humanizePercentage }} (Schwellenwert: 5%)&quot; - alert: Hohe Speicherauslastung expr: | ( container_memory_usage_bytes{name!=&quot;&quot;} / container_spec_memory_limit_bytes{name!=&quot;&quot;} ) &gt; 0.9 for: 5m labels: severity: warning annotations: summary: &quot;Container {{ $labels.name }} hoher Speicherverbrauch&quot; description: &quot;Der Speicherverbrauch beträgt {{ $value | humanizePercentage }}&quot; - alert: PodCrashLooping expr: | rate(kube_pod_container_status_restarts_total[15m]) &gt; 0 for: 5m labels: severity: critical annotations: summary: &quot;Pod {{ $labels.namespace }}/{{ $labels.pod }} befindet sich in einer Crash-Schleife&quot; - alert: DeploymentReplicasMismatch expr: | kube_deployment_spec_replicas != kube_deployment_status_replicas_available for: 10m labels: severity: warning annotations: summary: &quot;Deployment {{ $labels.namespace }}/{{ $labels.deployment }} Replikate stimmen nicht überein&quot;

Grafana-Dashboards (bereitgestellt)

# grafana/dashboards/app-dashboard.json (vereinfacht) { &quot;dashboard&quot;: { &quot;title&quot;: &quot;Anwendungsmetriken&quot;, &quot;panels&quot;: [ { &quot;title&quot;: &quot;Anfragefrequenz&quot;, &quot;targets&quot;: [ { &quot;expr&quot;: &quot;sum(rate(http_requests_total[5m])) by (service)&quot; } ] }, { &quot;title&quot;: &quot;Fehlerrate&quot;, &quot;targets&quot;: [ { &quot;expr&quot;: &quot;sum(rate(http_requests_total{status=~\&quot;5..\&quot;}[5m])) by (service)&quot; } ] }, { &quot;title&quot;: &quot;Antwortzeit (p95)&quot;, &quot;targets&quot;: [ { &quot;expr&quot;: &quot;histogram_quantile(0.95, sum(rate(http_request_duration_seconds_bucket[5m])) by (le, service))&quot; } ] } ] } }

Verteilte Ablaufverfolgung

// Einrichtung der OpenTelemetry-Ablaufverfolgung const { NodeSDK } = require(&#x27;@opentelemetry/sdk-node&#x27;); const { getNodeAutoInstrumentations } = require(&#x27;@opentelemetry/auto-instrumentations-node&#x27;); const { OTLPTraceExporter } = require(&#x27;@opentelemetry/exporter-trace-otlp-http&#x27;); const { Resource } = require(&#x27;@opentelemetry/resources&#x27;); const { SemanticResourceAttributes } = require(&#x27;@opentelemetry/semantic-conventions&#x27;); const sdk = new NodeSDK({ resource: new Resource({ [SemanticResourceAttributes.SERVICE_NAME]: &#x27;myapp&#x27;, [SemanticResourceAttributes.SERVICE_VERSION]: process.env.VERSION, environment: process.env.NODE_ENV, }), traceExporter: new OTLPTraceExporter({ url: process.env.OTEL_EXPORTER_OTLP_ENDPOINT + &#x27;/v1/traces&#x27;, }), instrumentations: [ getNodeAutoInstrumentations({ &#x27;@opentelemetry/instrumentation-fs&#x27;: { enabled: false, }, }), ], }); sdk.start();

Debugging von Containern

# Wichtige Debugging-Befehle # Protokolle anzeigen docker logs -f <container-id>kubectl logs -f deployment/myapp kubectl logs -f deployment/myapp --previous # Vorheriger Container # Befehle im Container ausführen docker exec -it <container-id>/bin/sh kubectl exec -it deployment/myapp -- /bin/sh # Ressourcenauslastung prüfen docker stats kubectl top pods kubectl top nodes # Ressourcen beschreiben kubectl describe pod <pod-name>kubectl get events --sort-by=&#x27;.lastTimestamp&#x27; # Netzwerk-Debugging kubectl run -it --rm debug --image=nicolaka/netshoot --restart=Never -- /bin/bash # Im Debug-Pod: # nslookup myservice # curl myservice:8080/health # tcpdump -i any port 8080 # Portweiterleitung kubectl port-forward deployment/myapp 8080:8080 # Dateien aus dem Container kopieren kubectl cp <pod-name>:/app/logs ./local-logs # Cluster-Informationen anzeigen kubectl cluster-info dump

Zukunftssichere Bereitstellungen {#future-trends}

Aufkommende Trends für 2025–2027

1. WebAssembly (Wasm)-Container

# Zukunft: Wasm-basierte Micro-VMs FROM scratch COPY --from=build /app/main.wasm / CMD [&quot;/main.wasm&quot;]

2. eBPF für Observability

  • Tiefgehende Einblicke auf Kernel-Ebene ohne Codeänderungen
  • Bessere Sicherheit und Netzwerküberwachung
  • Tools: Cilium, Falco, Pixie

3. Platform Engineering & Interne Entwicklerplattformen

# Backstage + Kubernetes für Self-Service apiVersion: backstage.io/v1alpha1 kind: Component metadata: name: myapp spec: type: service lifecycle: production owner: team-backend system: core-platform providesApis: - myapi-v1 consumesApis: - auth-api - payment-api

4. Green Computing & CO₂-bewusste Planung

# Workloads basierend auf der CO₂-Intensität planen apiVersion: v1 kind: Pod spec: schedulerName: carbon-aware-scheduler nodeSelector:</pod-name></pod-name></container-id></container-id> Kohlenstoffintensität: niedrig

5. KI-gesteuerte Betriebsabläufe (AIOps)

  • Vorausschauende Skalierung auf Basis von ML-Modellen
  • Erkennung von Anomalien in Metriken/Protokollen
  • Automatisierte Reaktion auf Vorfälle

Checkliste für die Produktionsreife

  • Mehrstufige Builds mit minimalen Basis-Images
  • Nicht-Root-Benutzer in allen Containern
  • Schwachstellenscans in CI/CD
  • Extern verwaltete Geheimnisse (Vault, AWS Secrets Manager)
  • Zustandsprüfungen (Aktivität, Bereitschaft, Start)
  • Definierte Ressourcenanforderungen und -limits
  • Konfigurierte horizontale und vertikale automatische Skalierung
  • Einrichtung von Überwachung und Warnmeldungen
  • Verteilte Tracing-Funktionen implementiert
  • Strukturierte Protokollierung mit Korrelations-IDs
  • Backup- und Disaster-Recovery-Plan
  • Blue-Green- oder Canary-Bereitstellungsstrategie
  • Netzwerkrichtlinien definiert
  • Pod-Sicherheitsstandards durchgesetzt
  • GitOps-Workflow etabliert
  • Dokumentation für Runbooks und Incident Response

Fazit

Produktive Docker-Bereitstellungen im Jahr 2025 erfordern einen ganzheitlichen Ansatz, der weit über das Schreiben von Dockerfiles hinausgeht. Erfolg basiert auf:

  1. Sicherheit als Standard: Nicht-Root-Benutzer, minimale Images, Schwachstellenscans
  2. Observability first: Metriken, Protokolle, Traces vom ersten Tag an
  3. Skalierungsfähige Architektur: Design für horizontale Skalierung mit zustandslosen Diensten
  4. Automatisierung überall: CI/CD, GitOps, Auto-Scaling, Selbstheilung
  5. Domänenspezifische Optimierungen: Passen Sie Ihren Ansatz für Full-Stack, KI/ML, IoT oder Robotik an

Die Landschaft der Container-Orchestrierung entwickelt sich ständig weiter, doch diese Grundprinzipien bleiben unverändert. Ob Sie sich nun wegen seines Ökosystems für Kubernetes oder wegen seiner Einfachheit für Docker Swarm entscheiden – konzentrieren Sie sich darauf, widerstandsfähige, beobachtbare und sichere Systeme aufzubauen.

Denken Sie daran: Die beste Bereitstellungsstrategie ist die, die Ihr Team auch tatsächlich aufrechterhalten kann. Fangen Sie einfach an, messen Sie alles und iterieren Sie auf der Grundlage realer Produktionsdaten.

Bleiben Sie neugierig, lernen Sie weiter und viel Spaß beim Bereitstellen!

Abhishek Nair - Fractional CTO für Deep Tech & AI
Abhishek Nair - Fractional CTO für Deep Tech & AI
Robotics & AI Engineer
About & contact
Why trust this guide?

Follow Me