Docker für Strategien-Deployment.
Wer eine Trading-Strategie schreibt, sollte sie auch in fünf Jahren noch starten können — ohne dass eine kaputte Python-Version, ein verschwundenes Paket oder ein OS-Update zum Stolperstein wird. Docker ist die einfachste, langweiligste und beste Antwort auf dieses Problem. In diesem Artikel zeige ich, wie ich Strategien-Images baue, welche Patterns sich bewähren und welche Anti-Patterns mir in Kundenprojekten immer wieder begegnen.
Warum überhaupt Docker für Trading?
Eine Strategie hat selten weniger als zehn Python-Abhängigkeiten. pandas,
numpy, ein Broker-SDK, vielleicht torch oder
xgboost, dazu eigene Utility-Pakete. Jedes Paket hat seine eigene
Versionspolitik. Was heute auf Ihrem Laptop funktioniert, funktioniert in zwei Jahren
mit einem frischen Python-Setup vielleicht nicht mehr — weil pandas eine
Funktion entfernt oder ein Broker-SDK eine Breaking-Change-Version released hat.
Docker zementiert den Zustand. Ein gebautes Image enthält die exakten Versionen aller Dependencies, die exakte Python-Runtime, die exakten System-Bibliotheken. Wenn das Image heute läuft, läuft es auch in fünf Jahren — solange Sie den Image-Speicher erhalten. Das ist nicht nur Komfort, sondern Compliance: bei Kundenprojekten ist Reproduzierbarkeit oft eine vertragliche Anforderung.
Das richtige Base-Image.
Hier passieren die ersten Fehler. FROM python:3.12 klingt unschuldig,
zieht aber ein 1 GB großes Debian-Image mit hunderten Paketen, die Sie nicht brauchen
und die alle CVEs haben können. Die Alternativen, sortiert nach Größe:
python:3.12-slim: 150 MB, Debian-basiert, gute Balance. Mein Default für die meisten Strategien.python:3.12-alpine: 50 MB, aber Alpine nutzt musl statt glibc.numpy,pandasund Co. müssen kompiliert werden — Build-Zeit explodiert, ML-Pakete können Probleme machen. Nicht empfohlen für Strategien mit ML-Stack.gcr.io/distroless/python3-debian12: 50 MB, keine Shell, keine Tools, nur Python. Beste Security, aber Debugging im Container ist nahezu unmöglich. Für extra-kritische Produktions-Workloads.
Für die Hauptmasse der Trading-Workloads ist python:3.12-slim die richtige
Wahl. Sicher genug, klein genug, und es funktioniert mit allen relevanten Python-Paketen
ohne Verrenkungen.
Multi-Stage-Build.
Das wichtigste Muster für saubere Trading-Images: Multi-Stage-Builds. Ein Build-Stage installiert Dependencies und kompiliert was kompiliert werden muss, ein Runtime-Stage kopiert nur die fertigen Artefakte. Resultat: kleinere Images, weniger Angriffsfläche, schnellere Pulls.
# Dockerfile fuer eine Trading-Strategie
# syntax=docker/dockerfile:1.7
FROM python:3.12-slim AS build
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
PIP_NO_CACHE_DIR=1 \
PIP_DISABLE_PIP_VERSION_CHECK=1
RUN apt-get update && apt-get install --no-install-recommends -y \
build-essential \
git \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY pyproject.toml poetry.lock ./
RUN pip install --upgrade pip poetry==1.8.3 \
&& poetry config virtualenvs.in-project true \
&& poetry install --only=main --no-root --no-interaction
COPY src ./src
RUN poetry install --only=main --no-interaction
# --- Runtime-Stage ---
FROM python:3.12-slim AS runtime
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
PATH="/app/.venv/bin:${PATH}"
RUN apt-get update && apt-get install --no-install-recommends -y \
ca-certificates \
tzdata \
&& rm -rf /var/lib/apt/lists/* \
&& groupadd --gid 10001 trader \
&& useradd --uid 10001 --gid trader --shell /usr/sbin/nologin trader
WORKDIR /app
COPY --from=build --chown=trader:trader /app/.venv /app/.venv
COPY --from=build --chown=trader:trader /app/src /app/src
USER trader
HEALTHCHECK --interval=30s --timeout=5s --start-period=20s --retries=3 \
CMD python -m strategy.healthcheck || exit 1
ENTRYPOINT ["python", "-m", "strategy.run"]
Sechs Punkte, die in diesem Dockerfile wichtig sind. Erstens syntax=docker/dockerfile:1.7
aktiviert moderne BuildKit-Features. Zweitens deterministisch fixierte Versionen
(poetry==1.8.3). Drittens kein Pip-Cache im Image. Viertens ein non-root-User
mit fixer UID — wichtig für Kubernetes-Pod-Security. Fünftens ein eingebauter
Healthcheck. Sechstens ENTRYPOINT statt CMD — der Container
tut genau eine Sache.
Reproduzierbare Builds.
Ein typisches Problem: das Image, das letzte Woche gebaut wurde, lässt sich heute nicht reproduzieren — weil ein transitives Dependency-Paket inzwischen eine neue Patch-Version released hat. Drei Maßnahmen verhindern das:
- Lockfile:
poetry.lockoderrequirements.txtmit Hashes. Damit ist jede Abhängigkeitsversion fixiert. - Base-Image-Pinning per SHA-256: statt
python:3.12-slimschreiben Siepython:3.12-slim@sha256:abc123.... Damit ist auch das Base-Image deterministisch. - Build-Argumente für Git-Hash: jedes gebaute Image bekommt als Label den Git-SHA, aus dem es gebaut wurde. So sehen Sie im Live-Cluster sofort, welcher Code-Stand läuft.
# In Dockerfile
ARG GIT_SHA=unknown
ARG BUILD_TIME=unknown
LABEL org.opencontainers.image.revision="${GIT_SHA}" \
org.opencontainers.image.created="${BUILD_TIME}" \
org.opencontainers.image.source="https://github.com/mg-quant/strategies"
# Beim Build
docker build \
--build-arg GIT_SHA=$(git rev-parse --short HEAD) \
--build-arg BUILD_TIME=$(date -u +%Y-%m-%dT%H:%M:%SZ) \
-t ghcr.io/mg-quant/momentum-v3:$(git rev-parse --short HEAD) \
-t ghcr.io/mg-quant/momentum-v3:latest \
.
docker-compose für lokale Entwicklung.
Bevor eine Strategie in Kubernetes geht, läuft sie meist erst Wochen lokal. Dafür ist
docker-compose immer noch das ehrlichste Werkzeug: einfach genug für
Solo-Entwicklung, mächtig genug für realistische Setups mit Datenbank, Broker-Mock
und Monitoring.
# docker-compose.yml
version: "3.9"
services:
strategy:
build:
context: .
dockerfile: Dockerfile
image: momentum-v3:dev
env_file:
- .env.dev
depends_on:
postgres:
condition: service_healthy
broker-mock:
condition: service_started
volumes:
- ./src:/app/src:ro
ports:
- "8080:8080"
restart: unless-stopped
postgres:
image: postgres:16-alpine
environment:
POSTGRES_PASSWORD: dev
POSTGRES_DB: trading
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 3s
retries: 10
volumes:
- postgres_data:/var/lib/postgresql/data
broker-mock:
image: ghcr.io/mg-quant/ibkr-mock:1.2.0
ports:
- "7497:7497"
prometheus:
image: prom/prometheus:v2.54.1
volumes:
- ./monitoring/prometheus.yml:/etc/prometheus/prometheus.yml:ro
ports:
- "9090:9090"
volumes:
postgres_data:
Wichtig: in der Dev-Umgebung werden Source-Files als Bind-Mount eingebunden
(./src:/app/src:ro). Das ermöglicht Hot-Reload ohne ständigen Rebuild,
der ro-Flag verhindert, dass der Container Files verändert. In Produktion
ist das Image immutable.
Security-Patterns.
Trading-Container haben Zugriff auf Geld. Drei Sicherheitsmaßnahmen, die ich für jeden produktiven Container durchsetze:
- Non-root-User: jeder Container läuft als unprivilegierter User. Niemals als root, auch nicht „nur kurz zum Debuggen“.
- Read-only-Rootfilesystem: im Pod-Spec wird das Root-FS readonly gemounted, nur explizit definierte Volumes sind schreibbar. Damit kann ein kompromittierter Container nicht beliebig Dateien ablegen.
- Image-Scanning: Trivy oder Grype scannt jedes Build-Image vor dem Push in die Registry. Bei Critical-CVEs in produktiven Pfaden bricht der Build ab.
# Im GitHub-Actions-Workflow
- name: Build image
run: docker build -t app:${{ github.sha }} .
- name: Scan image with Trivy
uses: aquasecurity/trivy-action@master
with:
image-ref: "app:${{ github.sha }}"
format: "table"
exit-code: "1"
severity: "CRITICAL,HIGH"
ignore-unfixed: true
Image-Registry und Retention.
Ein praktisches Detail, das oft vergessen wird: Image-Registries kosten Speicher.
Wenn Sie jeden Commit als Image taggen, haben Sie nach einem Jahr mehrere hundert
Images im Registry. Setzen Sie Retention-Policies: alle Images älter als 90 Tage
werden gelöscht, ausgenommen Tags wie release-*, v*.*.*
oder latest. Bei GitHub Container Registry funktioniert das mit einer
Action wie actions/delete-package-versions.
Wann Docker zu viel ist.
Auch wenn ich Docker fast immer empfehle — es gibt Fälle, wo es Overhead ohne Nutzen ist. Ein einmaliges Recherche-Skript, das einmal pro Quartal in JupyterLab läuft? Kein Docker nötig. Ein winziger Bash-Cron, der einmal pro Tag eine E-Mail schickt? Auch nicht. Docker lohnt sich, sobald Code mehrfach deployed wird, mehrere Maschinen sieht, oder eine produktive Rolle spielt. Dann zahlt sich die initiale Disziplin aus.
Stand: Mai 2026, überarbeitet Oktober 2026. Angaben zu Produkten, Preisen, Gesetzen und Fristen können sich seitdem geändert haben; maßgeblich sind die aktuellen Angaben der Anbieter und Behörden.
Sie wollen Ihre Trading-Strategien sauber containerisieren oder einen reproduzierbaren Build-Prozess aufsetzen? Unverbindlich anfragen — wir gehen Dockerfile, Pipeline und Registry-Strategie gemeinsam an. Mehr zu meinem Angebot: Trading-Systeme entwickeln lassen.