Nicht selten betreiben Unternehmen geschäftskritische Anwendungen, die zehn oder sogar 20 Jahre alt sind. Diese Legacy-Systeme verursachen jedoch zunehmend Probleme im Betrieb. Alte Bibliotheken und komplexe Abhängigkeiten erschweren die Wartung und Skalierung. Container-Technologien wie etwa Docker ermöglichen es, Anwendungen samt ihrer Abhängigkeiten in reproduzierbaren Images zu kapseln. Somit lassen sich Legacy-Apps isolieren, modernisieren und Schritt für Schritt in eine Container-basierte Umgebung überführen.
Docker trennt Anwendungen konsequent vom zugrundeliegenden System. Statt Software direkt auf einem Server zu installieren, packen IT-Profis die Anwendung, Laufzeitumgebung und Abhängigkeiten in ein Image. Docker startet daraus anschließend Container. In diesen isolierten Laufzeitumgebungen wird die Software ausgeführt.
Daten und Anwendung sind getrennt
In der Praxis entsteht daraus eine klar gegliederte Architektur: Oben arbeitet die Legacy-Anwendung im Container, darunter stellt der Docker-Host Rechenleistung, Netzwerk und Speicher bereit. Persistente Daten liegen nicht im Container selbst, sondern in Volumes oder in einer angebundenen Datenbank. Der Container lässt sich jederzeit neu starten, wobei geschäftskritische Daten erhalten bleiben.
Diese Trennung ermöglicht Reproduzierbarkeit. Ein Image enthält exakt definierte Versionen von Bibliotheken, Werkzeugen und Laufzeitumgebungen. Wenn Sie ein Image einmal gebaut haben, lässt sich diese Umgebung auf jedem Docker-Host identisch starten. Gerade bei Legacy-Software hilft dieses Prinzip, da viele Altsysteme empfindlich auf Versionsänderungen einzelner Komponenten reagieren.
Docker trennt Anwendungen konsequent vom zugrundeliegenden System. Statt Software direkt auf einem Server zu installieren, packen IT-Profis die Anwendung, Laufzeitumgebung und Abhängigkeiten in ein Image. Docker startet daraus anschließend Container. In diesen isolierten Laufzeitumgebungen wird die Software ausgeführt.
Daten und Anwendung sind getrennt
In der Praxis entsteht daraus eine klar gegliederte Architektur: Oben arbeitet die Legacy-Anwendung im Container, darunter stellt der Docker-Host Rechenleistung, Netzwerk und Speicher bereit. Persistente Daten liegen nicht im Container selbst, sondern in Volumes oder in einer angebundenen Datenbank. Der Container lässt sich jederzeit neu starten, wobei geschäftskritische Daten erhalten bleiben.
Diese Trennung ermöglicht Reproduzierbarkeit. Ein Image enthält exakt definierte Versionen von Bibliotheken, Werkzeugen und Laufzeitumgebungen. Wenn Sie ein Image einmal gebaut haben, lässt sich diese Umgebung auf jedem Docker-Host identisch starten. Gerade bei Legacy-Software hilft dieses Prinzip, da viele Altsysteme empfindlich auf Versionsänderungen einzelner Komponenten reagieren.
Technisch nutzt Docker dafür Funktionen des Linux-Kernels. Namespaces isolieren Prozesse, Netzwerke und Dateisysteme voneinander. Control Groups begrenzen Ressourcen wie CPU oder Arbeitsspeicher. Anders als virtuelle Maschinen starten Container kein vollständiges Betriebssystem, sondern teilen sich den Kernel des Hostsystems.
Sicherer Umgang mit Secrets
Viele Legacy-Anwendungen speichern Datenbankpasswörter, API-Schlüssel oder Zertifikate direkt in Konfigurationsdateien. In klassischen Serverinstallationen scheint dieses Vorgehen bequem, führt in Container-Umgebungen jedoch zu Sicherheitsrisiken. Sobald IT-Verantwortliche ein Image erstellen, wandern diese Dateien in das Container-Image. Jede Person mit Zugriff auf die Registry kann diese Informationen auslesen.
Moderne Container-Plattformen trennen deshalb Anwendungscode und Geheimnisse strikt. Sie stellen Passwörter oder Tokens erst zur Laufzeit bereit, etwa über Secret-Managementsysteme oder spezielle Container-Mechanismen. Bei einer Migration müssen IT-Verantwortliche prüfen, wie eine Anwendung ihre Zugangsdaten verwaltet. Häufig ist es sinnvoll, Konfigurationen anzupassen und sensible Daten aus dem Code oder aus Images zu entfernen.
Performance und potenzielle Engpässe
Container verursachen grundsätzlich nur sehr wenig Overhead. Da sie keinen eigenen Kernel starten, benötigen sie weniger Ressourcen als virtuelle Maschinen. In den meisten Szenarien laufen Anwendungen in Containern nahezu mit nativer Geschwindigkeit. Trotzdem existieren Fälle, in denen Container-Architekturen Einfluss auf die Leistung nehmen. Besonders I/O-intensive Anwendungen reagieren empfindlich auf zusätzliche Abstraktionsschichten im Storage-System. Auch Netzwerkvirtualisierung kann minimalen Overhead erzeugen.
Für klassische Webanwendungen oder das API spielt dieser Unterschied kaum eine Rolle. Datenbankserver oder Anwendungen mit extrem vielen Schreib- operationen erfordern jedoch eine genaue Analyse. In solchen Fällen entscheidet oft die konkrete Storage-Architektur über die tatsächliche Performance.
Dynamische Netzwerke für Legacy-Software
Auch Netzwerkkonzepte verändern sich mit Docker. Legacy-Anwendungen arbeiten häufig mit statischen IP-Adressen oder festen Hostnamen. Container-Umgebungen setzen dagegen auf dynamische Netzwerke. Docker erstellt virtuelle Netzwerke, in denen Container über interne DNS-Namen miteinander kommunizieren. Diese Architektur vereinfacht die Skalierung und das Deployment, verlangt aber gelegentlich Anpassungen an bestehenden Anwendungen. Besonders ältere Software erwartet oft feste Infrastrukturparameter, die in einer dynamischen Container-Welt nicht mehr existieren.
Der erste Schritt führt daher nicht ins Dockerfile, sondern in die Bestandsaufnahme. Sie sollten zunächst klären, wie die Anwendung Daten ablegt, Konfigurationen einliest und mit anderen Systemen kommuniziert. Erst auf dieser Grundlage lässt sich die Migration belastbar planen. Docker liefert dafür ein starkes Werkzeug, ersetzt aber keine gründliche Analyse der bestehenden Infrastruktur.
Dockerfile mit Healthcheck erstellen
Nach der Analyse beginnt die eigentliche Containerisierung. Ziel dieses Schritts ist die Definition einer reproduzierbaren Laufzeitumgebung. Im Zentrum steht das Dockerfile (Listing 1). Darin legen Sie das Basis-Image, Abhängigkeiten, Anwendungscode, den Startbefehl und idealerweise den Healthcheck fest.
Das Dockerfile bildet die bisherige Laufzeitumgebung in kontrollierter Form nach. Das Basis-Image definiert die Systemgrundlage, die Installationsschritte bringen die benötigten Pakete ins Image und CMD legt den Startprozess fest. Der Healthcheck ergänzt eine standardisierte Zustandsprüfung für den Betrieb, die viele Legacy-Anwendungen bislang nicht mitbringen.
Bei älteren Anwendungen empfiehlt sich ein pragmatisches Vorgehen. Sie sollten zunächst die bestehende Umgebung möglichst exakt reproduzieren. Erst danach lohnt sich die Optimierung, etwa durch kleinere Basis-Images, weniger Layer oder Multi-Stage-Builds. Aus dem Dockerfile entsteht anschließend ein versionierbares Image. Mit den "build"- und "run"-Kommandos bauen und starten Sie das Docker-Image für die Legacy-Anwendung:
docker build -t legacy-app:1.0 .
docker run -d -p 8080:8080 --name legacy-app legacy-app:1.0
Die Containerisierung bildet das Fundament der Migration. Sobald eine Anwendung stabil in einem Container läuft, lassen sich weitere Aspekte wie Persistenz, Konfigurationsmanagement oder Security-Hardening angehen.
Daten aus dem Container auslagern
Volumes und Bind Mounts speichern Daten außerhalb des Containers und binden sie während der Laufzeit ein. Ein Docker-Volume für eine Legacy-Anwendung legen Sie wie folgt an:
docker volume create legacy-data
Anschließend lässt sich dieses Volume beim Start eines Containers einbinden:
docker run -d
-p 8080:8080
-v legacy-data:/var/lib/app
legacy-app:1.0
Docker mountet das Volume in das Verzeichnis "/var/lib/app". Die Anwendung schreibt dort Daten, ohne dass diese beim Neustart verloren gehen. Selbst wenn der Admin den Container löscht, bleiben die Daten erhalten. Alternativ nutzen wir Bind Mounts. Dabei bindet Docker ein vorhandenes Verzeichnis des Hostsystems direkt in den Container ein. Dieser Ansatz erleichtert vor allem Debugging oder Backups:
docker run -d
-p 8080:8080
-v /srv/legacy-data:/var/lib/app
legacy-app:1.0
Die Anwendung arbeitet im Container mit dem erwähnten Verzeichnis "/var/lib/app", während die Daten tatsächlich auf dem Hostsystem unter "/srv/legacy-data" liegen. Sie können dort Logs prüfen oder Dateien sichern, ohne den Container zu betreten.
Konfiguration über Umgebungsvariablen
Neben Daten betrifft Persistenz auch die Konfiguration. Viele Legacy-Systeme speichern Konfigurationswerte in lokalen Dateien. Diese enthalten oft Parameter wie Datenbankverbindungen, Ports oder API-Endpunkte. In Container- Umgebungen gehört die Konfiguration nicht in das Image, sondern wird zur Laufzeit übergeben. Docker verwendet dafür meist Umgebungsvariablen, hier ein Beispiel:
docker run -d
-p 8080:8080
-e DB_HOST=db.internal
-e DB_USER=appuser
-e DB_PASSWORD=secret
legacy-app:1.0
Die Anwendung liest diese Werte beim Start aus der Umgebung und verbindet sich mit der Datenbank. Dieses Vorgehen erlaubt es, ein Image in unterschiedlichen Infrastrukturen zu betreiben – etwa in Entwicklung, Test und Produktion – ohne den Code anzupassen.
Sensiblen Daten wie Passwörtern müssen Sie jedoch besondere Aufmerksamkeit schenken, insbesondere in automatisierten Deployments. Docker unterstützt Secrets beispielsweise in Swarm-Umgebungen. Dabei speichert das System sensible Informationen verschlüsselt und stellt sie dem Container erst während der Laufzeit zur Verfügung. Ein Beispiel für das Anlegen eines Secrets sieht so aus:
Ein Service kann dieses Secret anschließend einbinden:
docker service create
--name legacy-app
--secret db_password
legacy-app:1.0
Docker stellt das Secret innerhalb des Containers als Datei bereit. Die Anwendung liest es aus, ohne dass das Passwort im Image oder in der Konfiguration sichtbar erscheint.
Die Container-Architektur erlaubt das Überführen einer Legacy-Anwendung nach Docker.
Schwachstellen prüfen und Container absichern
Sobald eine Legacy-Anwendung stabil im Container läuft und Sie Daten sowie Konfiguration getrennt haben, rückt die Sicherheit in den Fokus. Container verbessern die Isolation, lösen Sicherheitsprobleme jedoch nicht automatisch. Ohne gezielte Maßnahmen schaffen Container-Images neue Angriffsflächen, etwa durch veraltete Bibliotheken, unnötige Werkzeuge oder unsichere Benutzerrechte.
Ein wirkungsvoller Schritt besteht in der Wahl eines minimalen Basis-Images. Viele Standard-Images enthalten Programme, die eine Anwendung nicht benötigt. Jede zusätzliche Komponente erhöht die Angriffsfläche und verlängert die Updatezyk- len. IT-Admins greifen daher zu schlanken Varianten wie "debian:slim", "alpine" oder Distroless-Images. Diese enthalten nur die notwendigsten Komponenten der Laufzeitumgebung. So könnte demnach ein minimales Dockerfile aufgebaut sein:
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["python", "app.py"]
Der Parameter "--no-cache-dir" verhindert, dass der Paketmanager Cachedateien im Image speichert. Neben der Image-Größe spielt die Benutzerkonfiguration eine wichtige Rolle. Standardmäßig starten viele Container-Prozesse mit Root-Rechten. Wenn eine Anwendung eine Sicherheitslücke enthält, kann ein Angreifer potenziell auf Systemressourcen zugreifen. Wir empfehlen daher das Least-Privilege-Prinzip: Ein Container sollte nur die Rechte erhalten, die er zwingend benötigt. Das Dockerfile definiert dazu einen eigenen Benutzer:
RUN useradd -m appuser
USER appuser
Der Container startet anschließend unter diesem Benutzerkonto statt als Root. Beim Start lassen sich zudem Linux-Capabilities einschränken, um spezielle Kernelrechte zu entziehen:
docker run -d
--cap-drop ALL
--cap-add NET_BIND_SERVICE
-p 8080:8080
legacy-app:1.0
Hier entfernt Docker zunächst alle Kernelrechte ("--cap-drop ALL"). Der Parameter "--cap-add" erlaubt danach nur noch das Binden an Netzwerkports.
Ein weiterer Baustein sind Image-Scans. Scanner wie Trivy, Clair oder Grype analysieren Images automatisch auf bekannte Schwachstellen. Trivy prüft neben Betriebssystempaketen auch Abhängigkeiten aus Paketmanagern wie npm, pip oder Maven. Einen Scan führen Sie mit folgendem Befehl durch:
trivy image legacy-app:1.0
Trivy listet Schwachstellen nach Paket, Version und Schweregrad auf. So erkennen IT-Profis, ob ein Basis-Image veraltet ist oder kritische CVEs vorliegen. Gerade bei Legacy-Anwendungen ist dies wichtig, da ältere Laufzeitumgebungen oft jahrelang ungeprüft bleiben.
Neben der Anwendung erfordert der Docker-Host Aufmerksamkeit. Da sich Container den Kernel teilen, könnten Angreifer bei Kernelschwachstellen aus dem Container ausbrechen. Es empfehlen sich daher folgende Maßnahmen:
- Host regelmäßig patchen
- Nur benötigte Dienste auf dem Docker-Host betreiben
- Container-Logs und Aktivitäten zen-tral überwachen
- Netzwerkzugriffe segmentieren
Sicherheitsprofile wie AppArmor oder SELinux können Container zusätzlich einschränken. Die Containerisierung bietet die Gelegenheit, alte Bibliotheken zu aktualisieren oder gründlich zu isolieren. Wenn Sie Images klein halten, Rechte einschränken und Scans automatisieren, schaffen Sie eine solide Grundlage für den produktiven Betrieb.
Produktivbetrieb erfordert eine Registry
Ein Container, der lokal auf dem Notebook eines Admins funktioniert, stellt noch keine produktionsreife Infrastruktur dar. Erst mit klaren Build-Prozessen, einer zentralen Image-Verwaltung und kontrollierten Deployments entsteht eine stabile Betriebsumgebung. Ein essenzielles Element ist dabei eine Con- tainer-Registry. Sie dient als Ablage für Images und funktioniert ähnlich wie ein Paket-Repository für Software. IT-Profis laden dort Images hoch und stellen sie anschließend anderen Systemen oder Deployment-Pipelines zur Verfügung.
Viele Unternehmen betreiben dafür eine eigene Registry innerhalb der Infrastruktur. Typische Produkte sind beispielsweise Harbor, die GitLab-Container-Registry oder eine private Docker-Registry. Eine interne Registry bietet Vorteile: IT-Teams behalten die Kontrolle über ihre Images, können Sicherheitsrichtlinien durchsetzen und vermeiden Abhängigkeiten von externen Diensten.
Nach einem erfolgreichen Build lädt die CI-Pipeline das Image in die Registry hoch. Von dort beziehen es anschließend Test-, Staging- und Produktivumgebungen. Auf diese Weise entsteht ein nachvollziehbarer Workflow. Jede Version der Anwendung liegt als eigenes Image vor und lässt sich jederzeit erneut starten.
Wichtig bleibt dabei die Versionsstrategie. Tags wie "latest" helfen im Alltag kaum weiter, da sie den tatsächlichen Stand eines Deployments verschleiern. Sinnvoller sind klar versionierte Images wie 1.0, 1.1 oder 2.0. Verursacht eine neue Version Probleme, kann das Team gezielt auf die vorherige Fassung zurückgehen. Genau dieses Rollback zählt zu den größten praktischen Vorteilen Container-basierter Deployments. Statt ein mühsames Downgrade auf dem Server durchzuführen, startet der Betrieb einfach wieder den zuletzt stabilen Stand.
Vom Compose-Setup zur Orchestrierung
Viele Legacy-Anwendungen bestehen nicht nur aus einem einzelnen Dienst. Häufig arbeiten Webserver, Applikation und Datenbank zusammen. Für solche Szenarien eignet sich Docker Compose, da wir mehrere Container in einer zen- tralen Datei beschreiben und gemeinsam starten können. Das erleichtert die Verwaltung in kleineren Umgebungen, in denen noch keine Orchestrierungsplattform wie Kubernetes zum Einsatz kommt.
Listing 2 zeigt ein Beispiel einer Anwendung mit Docker Compose. Darin definiert Compose eine Anwendung und eine dazugehörige Datenbank. Beide Dienste starten gemeinsam, die Applikation erreicht die Datenbank über den Servicenamen "db", und das Datenbankverzeichnis liegt auf einem separaten Volume. So beschreiben Sie die komplette Umgebung an einer zentralen Stelle und können sie konsistent hochfahren.
Listing 2: Anwendung mit Docker Compose
version: "3.8"
services:
app:
image: legacy-app:1.0
ports:
- "8080:8080"
environment:
DB_HOST: db
db:
image: postgres:15
volumes:
- db-data:/var/lib/postgresql/data
volumes:
db-data:
Mit zunehmender Größe der Infrastruktur stoßen Compose-Setups jedoch an Grenzen. Funktionen wie automatisches Scheduling, horizontale Skalierung oder Selbstheilung fehlen in klassischen Docker-Installationen. Hierfür eignen sich Container-Orchestrierungsplattformen wie Kubernetes.
Kubernetes übernimmt viele Aufgaben des Container-Betriebs direkt in der Plattform. Das System verteilt Container auf mehrere Nodes, überwacht laufende Pods und startet fehlerhafte Instanzen selbst neu. Zudem organisiert Kubernetes Services, Konfigurationen, Secrets und persistente Speicher deutlich strukturierter als ein reines Compose-Setup. Rolling Updates, Service-Discovery und automatische Skalierung gehören hier zum Standard.
Fazit
Docker modernisiert keine Legacy-Anwendung von selbst, aber die Technologie schafft eine reproduzierbare Betriebsgrundlage. IT-Verantwortliche können Abhängigkeiten kapseln, Deployments standardisieren und gewinnen mehr Kontrolle über gewachsene Systeme. Der Erfolg hängt dabei weniger vom Werkzeug als vom methodischen Vorgehen ab.
Wenn Sie Daten, Konfiguration und Sicherheitsfragen früh trennen, können Sie auch ältere Anwendungen stabil in Container migrieren. IT-Abteilungen müssen keine Anwendung neu entwickeln, um erste Modernisierungsschritte einzuleiten. Oft reicht es aus, die bestehende Software in ein reproduzierbares Image zu überführen, den Betrieb zu standardisieren und Risiken im Deployment zu senken.