Kein Big Bang, kein Drama: Mit einer Legacy-Applikation in die Cloud
TL;DR – fünf Erkenntnisse
- Iterativ statt Big Bang ist die beste Versicherung gegen Fehlinvestitionen. Nach wenigen Wochen war der erste Teilschritt produktiv. Jeder einzelne Schritt war rollbackfähig. Das hat uns erlaubt, den Plan unterwegs zu ändern, ohne Investitionen abschreiben zu müssen.
- Viele Verzögerungen kamen nicht aus der Technik, sondern aus der Koordination. Abhängigkeiten zu Plattform-Teams, zu Verantwortlichen für Entra, zu Nachbarsystemen, und sogar zur Ferienplanung. Wer eine Cloud-Migration plant, plant auch Organisation, nicht nur Architektur. Das hatten wir unterschätzt.
- Eine Enterprise-Azure-Plattform ist nicht «einfach Azure». Guardrails, Policies und Berechtigungskonzepte der Kundin bestimmen, was tatsächlich möglich ist. Wir waren bei einem Azure-Produkt eines der ersten Projekte auf der Plattform – und haben dafür einen Pioniertribut bezahlt.
- Beginne mit dem, was du ohnehin machen musst. Die ersten beiden Schritte, Dateien raus aus der Datenbank und Keycloak abgelöst, standen unabhängig von der Cloud auf der Liste. Das eine hatte im Betrieb bereits geschmerzt, das andere kostete Wartungsaufwand ohne Gegenleistung. Wer so beginnt, investiert nicht in eine Wette auf die Cloud, sondern erledigt Aufgaben, die ohnehin offen waren. Umgekehrt haben wir GUI und SOAP-Schnittstelle bewusst nicht angetastet.
- Wir haben das Budget leider um rund 30 % überschritten, würden das Vorgehen aber so wählen. Der Mehraufwand kam aus vielen unverhersehbaren Umwegen zusammen, nicht aus einem grossen Fehlschlag. Das grobe Zielbild hat gehalten und das gewählte Vorgehen einen Totalverlust stets verhindert. Weil wertvolle Ergebnisse früh live gingen, war das Geld zu jedem Zeitpunkt nachvollziehbar investiert.
Die Ausgangslage
nxt betreut eine Applikation, die seit über zehn Jahren produktiv im Einsatz ist. In dieser Zeit wurden darin rund 700'000 Fälle erfasst. Diese Applikation hat ein kleines, schlagkräftiges Team, in rund acht Monaten auf Azure migriert. Davor lagen etwa sechs Monate Vorlauf, in dem die Planung entstand: ein bis zwei Wochen für das grobe Zielbild, weitere zwei bis drei Wochen für die Detailplanung, verteilt über das halbe Jahr.
Das ist die Ausgangslage in Kurzform. Bei einem System dieses Alters migriert man nicht nur eine Applikation, sondern auch ein Jahrzehnt an Entscheidungen. Davon ist ein Grossteil nicht dokumentiert und auch niemandem mehr im Detail bekannt.
Unsere Applikation lief vor der Migration auf einer virtuellen Maschine im eigenen Rechenzentrum, speicherte ihre Geschäftsdaten in einer relationalen Datenbank und tauschte mit Umsystemen Daten über Netzlaufwerke sowie direkt über die Datenbank aus. Die Erfassung der Fälle erfolgt über ein Web-GUI und für einige Geschäftskunden über eine SOAP‑Schnittstelle. Beides war durch eine zentrale Web Application Firewall (WAF) geschützt. Die Anmeldung zur Administration lief über eine eigene Keycloak-Instanz.
Auch wenn eine neue Applikation heute nicht mehr so geplant würde, technisch war die Architektur über Jahre solide. Der Auslöser für die Migration war denn auch kein Ausfall, sondern eine Strategie: Die Kundin löst die On-Prem-Infrastruktur ab. Wir haben uns als Zusatz-Ziel gesetzt, gleichzeitig zeitgemässe Standards bei IT- und Datensicherheit sowie eine moderne Überwachung umzusetzen.
Denn ehrlich betrachtet gab es davon einiges nachzuholen:
- Dateien lagen in der Datenbank. Eingehende XML-Dokumente, Bilder und PDFs wurden als Inhalt in der relationalen Datenbank gespeichert. Das hatte in der Vergangenheit bereits zu Problemen geführt.
- Zugangsdaten lagen im Klartext. Datenbank-Passwörter waren in Textdateien auf den Servern gespeichert. Mit Containern ist das ohnehin nicht mehr machbar, aber es entsprach auch vorher nicht länger dem Stand der Technik.
- Logs lagen auf der lokalen Disk. Das Logging übernahm der Applikationsserver, die Logs blieben auf der Maschine. Technische Benachrichtigungen liefen per E-Mail.
- Deployments waren manuell. Es gab nur ein rudimentäres Installations-Skript und Datenbankmigrationen mussten sogar manuell eingespielt werden.
Dazu kam ein struktureller Punkt: Die Applikation war ursprünglich als modulares Produkt für mehrere Kunden konzipiert. Heute ist unsere Kundin die einzige Nutzerin. Diese Modularität brachte also keinen Nutzen mehr, erschwerte aber die Fehlersuche und verteuerte jede Weiterentwicklung.
Warum wir kein Big-Bang-Projekt vorgeschlagen haben
Eine vollständige Migration in einem Zug hatte sich nicht einmal planbar angefühlt. Wie wenig planbar es gewesen wäre, zeigt sich jetzt im Rückblick: Ein Applikationsserver, der nicht zu Entra passt. Datenbanktabellen mit stillen Nutzern. Konzernrichtlinien, deren zusätzliche Restriktionen in keiner Herstellerdokumentation stehen. Jeder einzelne dieser Punkte war zum Zeitpunkt der Planung unsichtbar – und jeder hätte in einem Big-Bang-Projekt mindestens denselben Aufwand verursacht, nur gleichzeitig mit allen anderen. Ein solcher Plan wäre bei einem gewachsenen System keine Prognose, sondern eine Vermutung mit Terminangabe.
Wir haben stattdessen ein Vorgehen in Teilschritten konzipiert, mit zwei harten Regeln:
Erstens: Kein Schritt soll reine Vorleistung sein. Jeder Teilschritt soll für sich alleine stehen können: eine entlastete Datenbank, eine Komponente weniger im Betrieb, ein Deployment ohne Handarbeit. Ein Schritt, der seinen Nutzen erst durch den nächsten entfaltet, entfaltet für sich alleine noch keinen Wert, und ist kein echter Schritt vorwärts.
Zweitens: Der jeweils letzte Schritt muss umkehrbar bleiben. Das reduziert das technische Risiko drastisch und es beschleunigt Entscheidungen. Und das ist der unterschätzte Effekt! Wer weiss, dass er zurück kann, diskutiert kürzer.
Die Reihenfolge haben wir nach zwei Kriterien gewählt: nach Wertbeitrag, und nach Lerneffekt.
Die ersten beiden Schritte, also Dateien raus aus der Datenbank und Keycloak raus aus dem Betrieb, waren Dinge, die wir ohnehin gemacht hätten. Auch ohne Cloud-Migration. Beide hatten längst ihren eigenen Grund: Das eine hatte im Betrieb schon geschmerzt, das andere kostete Wartungsaufwand ohne Gegenleistung.
Genau deshalb waren sie die richtigen Schritte zum Start – sie verschieben nämlich die Risikofrage. Solange die ersten Schritte auch ohne Cloud sinnvoll sind, lautet die Frage an das Projekt nicht mehr «geht das gut?», sondern nur noch «wie weit gehen wir?».
Danach kam der Lerneffekt zum Tragen: Datenbank und File-Ablage sind bewusst früh nach Azure gewandert, obwohl die Applikation selbst noch On-Prem lief. So haben wir Erfahrungen mit Azure SQL und Azure Files gesammelt, mit der zur Verfügung gestellten Plattform, solange ein Rollback noch billig war.
Deep Dive: Dateien raus aus der Datenbank
Eine relationale Datenbank ist ein hervorragendes Werkzeug für strukturierte Geschäftsdaten und ein schlechtes für Dateien. Sie wird gross, Backups werden langsam, Restores werden zum Risiko, und die Kosten steigen überproportional. Neu liegen die Dokumente der Applikation in einem Azure Storage Account als Blob, in der Datenbank steht nur noch eine Referenz darauf.
Im Kern gilt das gleiche Problem für gemeinsam genutzte Netzlaufwerke. Auch sie sind ein bequemer Ort für Dateien. Jedoch setzen sie voraus, dass alle Beteiligten im selben Netz sind, sie bringen kaum Metadaten mit, und weil mehrere Systeme darauf zugreifen, werden sie unbemerkt zum Integrationspunkt. Ein Objektspeicher adressiert viele dieser Punkte – vorausgesetzt, die zugreifenden Systeme können damit umgehen.
Aber genau diese Voraussetzung war bei uns nicht überall gegeben. Für die Dokumente der Applikation ist Blob Storage das Ziel. Eine bestimmte Dateifreigabe liess sich hingegen nicht wirtschaftlich ablösen, weil die betroffenen Systeme auf einen Dateipfad angewiesen sind; dort war ein Share, der über Azure Files bereitgestellt wurde, die Lösung. Dazu später mehr, denn der Entscheid dazu hat uns eine Runde gekostet.
Entscheidend ist aber: Dieser Schritt stand nicht auf der Liste, weil wir in die Cloud wollten. Er stand darauf, weil das Problem uns im Betrieb bereits eingeholt hatte. Wir hätten ihn ohnehin gemacht, die Migration hat ihm lediglich die Priorität gegeben, die er verdiente. Genau das machte ihn zum idealen ersten Schritt: Er hätte sich auch dann gelohnt, wenn danach nichts mehr gekommen wäre.
Identität: Wie ein Detail den Plan umgestellt hat
Auch dieser Schritt war nicht primär eine Konsequenz der Cloud-Migration, sondern eine überfällige Korrektur. Der Wartungsaufwand für die eigene Keycloak-Instanz war real und wiederkehrend (Patches, Betrieb, Know-how) und ihm stand kein Nutzen gegenüber, der dies rechtfertigte.
Dazu kam eine Anforderung, die den Fall endgültig entschieden hat: Die Sicherheitsvorgaben verlangten Multi-Faktor- Authentifizierung für Mitarbeitende. Diese hätten wir in Keycloak eigenständig umsetzen müssen – mit einem für die Anwender unerfreulichen Ergebnis. Wer sich morgens schon an einem verwalteten Firmengerät angemeldet hat, möchte für eine interne Fachapplikation nicht einen extra zweiten Faktor verwalten.
Mit Entra entfällt diese Arbeit nicht nur, sie kehrt sich um: Die Anforderung ist erfüllt, weil der Konzern sie zentral erfüllt, und gleichzeitig wird die Anmeldung für die Mitarbeitenden bequemer. Sie melden sich von verwalteten Geräten ohne erneute Eingabe von Benutzername und Passwort an. Dass zusätzlich eine ganze Komponente aus dem Betrieb verschwindet, ist dann fast schon nur noch das Tüpfchen auf dem «i»: Denn eine Komponente, die es nicht mehr gibt, verursacht keine Kosten mehr. Und Identität ist selten der Ort, an dem eine Fachapplikation sich differenzieren sollte.
Als Hauptrisiko hatten wir die Koordination mit den Entra-Verantwortlichen eingeschätzt. Gekommen ist es anders. Und zwar aus einer Ecke, die wir nicht auf dem Radar hatten: Die eingesetzte Version des Applikationsservers WildFly funktionierte nicht mit Entra über OIDC. Sie erwartete Parameter, die in dieser Form nur Keycloak lieferte.
Damit stand ein Upgrade des Applikationsservers plötzlich am Anfang statt weiter hinten im Plan. Und dieses Upgrade zwang uns dazu, Admin- und Applikationsteile zu trennen. Auch das ein Umbau, der für eine deutlich spätere Phase vorgesehen war. Das Debugging war mühsam und hat wesentlich mehr Zeit gekostet als geschätzt.
Die Datenbankmigration
Ein Azure SQL Server ersetzt die Microsoft SQL Server On-Prem-Datenbank. Übergangsweise, während die Applikation noch im Rechenzentrum auf ihrer VM lief. Migriert haben wir mit einem eigenen Skript. Alles, was wir über die Eigenheiten dieses Datenmodells gelernt haben, steckt im Skript. Damit liess sich die Migration beliebig oft üben, in der Testumgebung verifizieren und am Ende ohne Improvisation ausführen. Für den Import und die Neuberechnung der Indizes haben wir die Datenbank-Leistung temporär hochgesetzt und später wieder reduziert; eine Möglichkeit, die es im eigenen Rechenzentrum nicht gibt.
Das Verhalten von Azure SQL selbst war unspektakulär, und das ist eine gute Nachricht. Die Überraschung lag anderswo: Beim Vergleich der Datenmodelle tauchten Tabellen und Views auf, die niemand im Projektteam bewirtschaftete, die aber von einer externen Integration benötigt wurden.
Das ist genau die Sorte Entscheidung aus einem der undokumentierten Jahre. Die Lektion daraus ist unbequem und allgemeingültig: Bei einem gewachsenen System gehört dir dein Datenmodell weniger, als du denkst. Eine Datenbank, die als Integrationspunkt mitgenutzt wird, hat Schnittstellencharakter.
Sicherheit und Betrieb
Hier liegt der Teil des Nutzens, der sich am schwersten in einer Zahl ausdrücken lässt und für einen Krankenversicherer trotzdem viel zählt:
- Secrets im Azure Key Vault. Die Passwörter in Textdateien sind weg. Zugriffe sind feingranular geregelt und protokollierbar.
- Managed Identities. Der Zugriff auf Azure-Dienste läuft ohne hinterlegte Zugangsdaten. Das ist das eigentliche Zielbild, denn ein Secret, das nicht existiert, kann nicht entwendet werden.
- Engere Berechtigungen und bessere Kostentransparenz als Nebeneffekte der Umstellung. Es ist nun genau nachvollziehbar, was welcher Teil des Systems kostet.
Beim Monitoring gilt eine ehrliche Zwischenbilanz: Der Nutzen ist noch nicht messbar. Weil der Compute aktuell noch nicht migriert ist, arbeitet das Team aus Gewohnheit weiter mit den On-Prem-Logs. Neue Werkzeuge werden eben nicht durch Bereitstellung wirksam, sondern durch Umstellung von Gewohnheiten. Und dieser Teil steht noch an.
Von GitLab zu Azure DevOps – und Infrastruktur als Code
Der Applikationscode ist von GitLab in die Azure-DevOps-Umgebung der Kundin gewandert. Der Effekt ist bemerkenswert: Die Kunding erhält die vollständige Kontrolle über das Projekt und die Abhängigkeit von uns als Lieferant sinkt. Wir haben das aktiv empfohlen. Eine Zusammenarbeit soll fortgesetzt werden, weil sie sich bewährt, und nicht, weil ein Ausstieg zu aufwendig wäre.
Unterschätzt haben wir dabei den Aufwand: Die beiden Werkzeuge folgen unterschiedlichen Konzepten, entsprechend war das keine Portierung, sondern ein Neubau der Build- und Deployment-Pipelines. Und im Kleinen zeigte sich dasselbe Muster wie bei der Applikation selbst: Die neue Umgebung erfüllte stillschweigende Annahmen nicht, die über Jahre niemand als Annahme wahrgenommen hatte. Solche Abweichungen fallen nicht bei der Planung auf, sondern wenn ein Ergebnis unerklärlich ausfällt. Bei diesem Schritt halfen AI-Agenten massiv, weil sie problemlos zwischen den Konzepten übersetzen konnten.
Die Infrastruktur selbst wird vollständig über Code definiert. Konkret heisst das: Niemand klickt Ressourcen im Azure-Portal zusammen. Die gesamte Umgebung ist in Textdateien beschrieben. Und wer etwas daran ändern will, passt diese Beschreibung an. Damit existiert für die Infrastruktur dasselbe, was für den Programmcode seit Jahren selbstverständlich ist: eine vollständige Historie. Jede Änderung ist datiert, einer Person zugeordnet und mit einer Begründung versehen. So lässt sie sich auch jederzeit rückgängig machen. Und die Frage «warum ist diese Einstellung so, wie sie ist?» hat somit fast immer eine Antwort.
Der Nutzen liegt in drei Eigenschaften, die im Betrieb den Unterschied machen: Parität zwischen Test- und Produktionsumgebung, Reproduzierbarkeit, und nachvollziehbare Änderungen. Das klingt nach Ordnungsliebe, ist aber eine Risikofrage. Wenn die Testumgebung der Produktion nicht entspricht, testet man etwas anderes als das, was man ausliefert. Und eine Umgebung, die aus Code neu erstellt werden kann, verliert ihren Charakter als Unikat, das niemand anzufassen wagt.
Was uns wirklich Zeit gekostet hat
Die grössten Verzögerungen lagen nicht primär in der Cloud-Technologie, sondern bei Schnittstellen, Plattformvorgaben und Koordination. Alle Beteiligten, sowohl bei den Nachbarsystemen als auch bei uns, haben ausgesprochen konstruktiv zusammengearbeitet.
Die Enterprise-Plattform ist nicht Azure. Die Dienste verhalten sich genau so, wie der Hersteller es beschreibt. Jedoch ist auf einer konzernweiten Plattform mit Policies, Guardrails und Berechtigungskonzepten nicht alles davon erlaubt oder es gibt zusätzliche Verschärfungen. Diese stehen in keiner Produktdokumentation, und der Aufwand liegt darin, sie zu finden. Beim Azure Application Gateway, das künftig den Zugriff auf die Applikation absichert, waren wir eines der ersten Projekte auf der Plattform. Bis öffentlicher und privater Verkehr wie gewünscht funktionierten, brauchte es deutlich mehr Iterationen als geplant. Die Architekturentscheidung war und ist trotzdem richtig; der Pioniertribut wurde einmal bezahlt, der Nutzen bleibt, auch für künftige andere Projekte.
Eine Architekturentscheidung basierte auf falschen Annahmen. In frühen Architekturgesprächen wurde gemeinsam entschieden, ganz auf Azure Files zu verzichten und Blob Storage als einziges Ziel für alle Dateien zu verwenden. Also auch für die erwähnte Dateifreigabe zu den Umsystemen. In der Umsetzung zeigte sich, dass das nicht tragfähig ist: Für diesen einen Austauschweg bleibt ein Azure-Files-basierter Share nötig, weil die Umstellung der beteiligten Systeme auf Blob-Zugriffe in keinem Verhältnis zum Nutzen gestanden hätte. Wir haben eine Runde verloren. Weil der Schritt klein war, und frühzeitig entdeckt wurde, war der Verlust klein.
Koordination ist kein Overhead, sondern Arbeit. Abstimmungen mit Verantwortlichen für Entra, mit dem Plattform-Team und mit dem Team des nachgelagerten Datenaufbereitungs-Systems liessen sich im Voraus nicht zuverlässig abschätzen. In der Summe haben sie deutlich mehr Zeit gebunden, als wir erwartet hatten.
Ferien sind ein Projektrisiko. Über die Sommermonate waren Schlüsselpersonen abwesend, was Entscheidungen verzögerte. Damit das Projekt nicht stillstand, wurden Teile parallelisiert: Mehrere Teilprojekte waren gleichzeitig in Arbeit und mussten untereinander sowie mit dem tatsächlichen Zustand der Software abgeglichen werden. Dies erhöhte die kognitive Last im Team deutlich. Warten wäre nicht besser gewesen, aber der Preis der Parallelisierung ist nicht vernachlässigbar.
Was diese Punkte verbindet: Geschätzter Aufwand und Kalenderzeit sind nicht dasselbe. Eine Aufgabe, für die zwei Wochen Arbeit anfallen, ist nicht nach zwei Wochen fertig, wenn zwischendurch auf eine Antwort, eine Freigabe oder ein anderes Team gewartet wird.
Weshalb es mehr gekostet hat
Wir haben das Budget um rund 30% überschritten. Zustande kam das nicht durch einen grossen Fehlschlag, sondern durch unerwartete Mehraufwände links und rechts: viele kleine Umwege, die sich summiert haben. Einzelne Entscheide mussten wir unterwegs korrigieren, und die Schätzung war am Ende unsere. Und wer schätzt, trägt die Abweichung mit. Was uns rückblickend bestätigt: Das grobe Zielbild hat gehalten. Falsch eingeschätzt haben wir nicht das Wohin, sondern wie steil der Weg dorthin zeitweise werden würde.
Zwei Aspekte ordnen die Zahl ein:
Erstens war bereits nach wenigen Wochen wertvolle Arbeit produktiv. Es gab keinen Zeitpunkt, an dem viel Geld ausgegeben und nichts geliefert war. Bei einem Big-Bang-Projekt hätte eine Überschreitung von 30% eine ganz andere Bedeutung, denn dort steht der Nutzen erst am Ende. Siehe dazu auch «Ein Franken heute ist mehr Wert als einer morgen».
Zweitens verteilen sich die Kosten bewusst über mehrere Budgetperioden. Das macht den Mehraufwand nicht kleiner, aber es verändert die Finanzierungslogik: Es braucht keine einmalige Grossinvestition, über die einmal und endgültig entschieden wird. Der Parallelbetrieb von On-Prem und Azure kostet in der Übergangsphase doppelt. Das ist der eingekaufte Preis für ein jederzeit mögliches Rollback, und wir halten ihn für gut angelegt.
Fazit
Die Empfehlung, die wir aus diesem Projekt mitnehmen, ist unspektakulär: Geh in kleinen Schritten und liefere früh und oft. Kleine, eigenständig wertvolle Schritte haben sich in diesem Projekt als wirksame Absicherung gegen Fehlinvestitionen erwiesen.
Das Vorgehen ist einfach zu erklären, aber anspruchsvoll vorzubereiten. Man muss die Abhängigkeiten im System erkennen, um zu sehen, welche Teile sich einzeln herauslösen lassen. Und man muss aus dem Gesamtvorhaben Lieferpakete schneiden, die klein genug für einen überschaubaren Zeitraum und trotzdem gross genug für einen erkennbaren Nutzen sind. Diese Arbeit fällt vor dem ersten Handgriff an und wer sie überspringt, landet automatisch beim Big Bang, weil dann alles mit allem zusammenhängt.
Kleine Schritte haben uns frühe Lehren gebracht. Jede der Überraschungen, die wir oben beschrieben haben, ist einzeln aufgetaucht. Aber stets zu einem Zeitpunkt, an dem sie höchstens ein Problem war, aber noch keine Krise. Fast durchgehen konnten wir darauf reagieren, dass wir den Plan anpassten, statt Geleistetes abzuschreiben.
Damit ändert sich, was ein Plan überhaupt leisten muss. Er muss nicht die richtige Reihenfolge für die nächsten zwölf Monate treffen, denn das kann er bei einem System ab einer bestimmten Grösse und Komplexität nicht. Er muss dafür sorgen, dass ein falscher Schritt schnell erkannt wird, gut korrigiert werden kann, und somit günstig bleibt. Das ist ein deutlich niedrigerer Anspruch, dafür ist er erfüllbar.

