Blog
Containerisierung einer Applikation
Was bringt mir das und wie gehe ich vor?
Mittels Containerisierung lässt sich Programmcode bündeln, verteilt in isolierten Umgebungen ausführen, patchen und skalieren. Die Entwicklung und Bereitstellung von Applikationen wird dabei vereinfacht und modular gegliedert. Trotz all ihrer vielen Vorteile macht eine Containerisierung jedoch nicht immer Sinn, denn der Weg zur optimalen Container-Infrastruktur kann sich ohne Plan als lang und steinig erweisen.
In diesem Blog stellen wir vor, welche Schritte notwendig sind, um eine Applikation zu containerisieren, welche Vorteile dies bietet und zu welchem Zeitpunkt eine Containerisierung in Erwägung gezogen werden kann. Zusätzlich zeigen wir wichtige Aspekte auf, die im Vorgehen der Containerisierung einer Applikation beachtet werden müssen, um die Implementierung und den Betrieb von Containern erfolgreich zu gestalten.
Konzept Containerisierung
Die Containerisierung ermöglicht die Zerlegung von Anwendungen in «Container». Dadurch kann Programmcode innerhalb eines Containers mitsamt seinen Abhängigkeiten (Bibliotheken, Frameworks, sonstige Dateien) als eigenes Softwarepaket gebündelt und als Prozess ausgeführt werden. Die Bündelung eines solchen Softwarepakets erfolgt in Form von Images, welche z.B. über Docker bereitgestellt werden.
Ein weiteres Merkmal von Containern ist deren Einsatz als schlanke Alternative zu herkömmlichen virtuellen Maschinen, weil sie für den Betrieb kein eigenes Betriebssystem benötigen. Sie verwenden für das Ausführen von Prozessen den Betriebssystem-Kernel ihres Host-Systems. Sämtliche Container innerhalb einer Container-Infrastruktur teilen sich dabei den gleichen Kernel eines zentralen Host-Systems, haben aber keinen Zugriff auf ihre Nachbar-Container untereinander.
Durch den geteilten Betriebssystem-Kernel ist sichergestellt, dass eine containerisierte Anwendung jeweils im gleichen Kontext plattformunabhängig ausgeführt werden kann.
Warum Containerisieren?
Es stellt sich nun die Frage, wieso Software-Entwicklungsfirmen überhaupt ihre Applikationen in ihre Einzelteile zerlegen sollen. Der Nutzen muss dabei den Aufwand decken, um den Weg zur Containerisierung rechtfertigen zu können.
Die Containerisierung einer Applikation bietet folgende Vorteile gegenüber dem klassischen, meist monolithischen Ansatz, mit welchem die Applikation in einer oder mehreren virtuellen Maschinen betrieben wird:
- Reduzierte Betriebskosten
Durch das Weglassen eines eigenen Betriebssystems lassen sich Speicherplatz, Rechenleistung und Ressourcen einsparen. Ein Container-Image benötigt lediglich genug Leistung, um die Prozesse innerhalb seines Softwarepakets auszuführen. - Skalierbarkeit
Container lassen sich innerhalb kurzer Zeit starten und stoppen. Sofern für eine Applikation mehr Rechenleistung benötigt wird, können innert kürzester Zeit neue Container durch die Bereitstellung eines Images aufgesetzt werden. Dies ermöglicht einen hohen Grad an Skalierbarkeit. - Portabilität
Durch die Natur der Modularität eines Containers lassen sich diese vereinzelt in neue Infrastrukturen bereitstellen und migrieren. Dies ist z.B. im Fall einer bevorstehenden Cloud-Journey praktisch, in welche Teile einer containerisierten Applikation aus einer On-Premises Landschaft in eine Cloud Umgebung migriert werden. Hierbei soll ebenso erwähnt sein, dass die meisten SaaS-Lösungen auf containerisierten Backend-Softwaremodulen aufbauen. - Performance
Bei herkömmlichen Ansätzen in der Virtualisierung geht immer ein gewisser Teil der Performance eines Systems für den Betrieb des Betriebssystems verloren.
Ein Container ist dazu da, Prozesse auszuführen, für welche er erstellt worden ist. Aufgrund dieser Isolierung kann die gesamte Rechenleistung innerhalb eines Containers auf die Ausführung der Prozesse gelegt werden. - Konsistenz
Angesichts der Tatsache, dass alle Container denselben Betriebssystem-Kernel ihres Host-Systems verwenden, bildet der Kernel zugleich auch dieselbe Basis der Funktionalität und Betriebsumgebung der Container. Somit werden die Entwicklung und Bereitstellung einer Applikation wesentlich vereinfacht, weil deren containerisierten Module in allen Umgebungen gleich funktionieren. - Optimiert für moderne DevOps-Ansätze
Mittels DevOps wird die Prämisse geschaffen, eine kontinuierliche und sofortige Integration von Code in bestehende Umgebungen garantieren zu können. Anhand von Orchestrierungstools wie Kubernetes können DevOps Teams innerhalb kurzer Zeit einzelne Container oder gesamte containerisierte Anwendungen bereitstellen, versionieren und rollbacken. Der gesamte Lebenszyklus einer Applikation kann deshalb mithilfe von DevOps gesteuert und verwaltet werden.
Von Legacy-Applikation zur Container-Infrastruktur
Durch die vielen direkten Vorteile der Containerisierung und den fortlaufenden Drang von Unternehmen zur Modernisierung ihrer Legacy-Systeme, welcher durch Trends wie z.B. Cloud Computing verstärkt wird, stellt sich nun die Frage:
Wieso fangen nicht alle Unternehmen an, ihre Applikationen als Container zu betreiben? Die Beantwortung dieser Frage bildet zugleich den ersten Schritt des Wegs zur Containerisierung einer Applikation.
![Containerisierung einer Applikation](https://www.atrete.ch/wp-content/uploads/2024/04/03-e1714377033720.png)
Analyse- und Planungsphase
Vor der Erwägung einer Containerisierung muss im Voraus Verständnis über die betroffene Applikation geschaffen werden. «Verständnis schaffen» heisst, sich bewusst werden, aus welchen Komponenten die zu migrierende Applikation besteht, wie ihre Architektur aussieht und wie die Komplexität einer Zerlegung eingeschätzt wird. Es macht beispielsweise wenig Sinn, eine hochkomplexe Applikation zu containerisieren, die aus zahlreichen Komponenten inkl. Abhängigkeiten besteht. Ziel einer Containerisierung ist es, den Betrieb und die Verwaltung einer Applikation zu vereinfachen, nicht zu verschlimmbessern.
Um solche Fälle zu vermeiden, ist es wichtig, folgende Fragen zu klären:
- Ist es möglich, die Applikation in logische, funktionale Bereiche zu gliedern?
- Lassen sich diese Bereiche isoliert in einem Container ausführen?
- Aus wie vielen Containern würde die Applikation grob geschätzt bestehen?
Neben den Managementaspekten, welche es bei einer Evaluation einer Containerisierung zu berücksichtigen gibt, gibt es auch Sicherheitsaspekte, auf die Acht gegeben werden muss. Während der geteilte Kernel im Vergleich zu herkömmlichen Betriebssystem-VMs für den Betrieb und die Performance sehr vorteilhaft ist, bildet dieser Infrastruktur-Umstand auch ein erhöhtes Sicherheitsrisiko im Falle einer Cyber-Attacke. So bildet beispielsweise die Angriffsmöglichkeit auf den Kernel des Host-Systems eine Angriffsfläche auf alle Container innerhalb einer containerisierten Applikation desselben Container-Host-Systems.
In der Analysephase ist es zwingend notwendig, solche Konsequenzen und solche Risiken und allfällige Konsequenzen im Voraus gründlich zu analysieren, um entsprechende Sicherheitsmassnahmen treffen zu können.
Auswahl Technologie
Nach einer positiven Evaluation einer Applikation hinsichtlich Containerisierung, steht die Auswahl einer passenden Container-Technologie an. Vor der Auswahl der Technologie muss ebenfalls die Umgebung der Infrastruktur definiert werden: On-Premises oder Cloud?
Die Auswahl zwischen den beiden Optionen hängt von den Anforderungen an die zu containerisierende Applikation ab, welche sich in der Analysephase ergeben. Wichtige Überlegungen hierbei sind zum Beispiel die Anforderungen an die Skalierbarkeit, Sicherheit, Verfügbarkeit und Kosten. Entsprechend wird eine Evaluation der Vor- und Nachteile jeder Umgebung vorausgesetzt, um eine Entscheidung treffen zu können.
Als Container-Technologie werden wir für diesen Blog den Implementierungsgrundsatz wählen, der Docker heisst. Docker ist besonders für seine Einfachheit und Effizienz bekannt und hat sich als Industriestandard für Containerisierung etabliert.
Abhängigkeiten erkennen
Das Identifizieren von Abhängigkeiten der Applikation ist der nächste Schritt in der Analysephase und ist die Voraussetzung für die Definition einer Zielarchitektur. Abhängigkeiten sind Elemente wie externe Bibliotheken, benutzerdefinierte Frameworks oder Konfigurationsdateien, welche Teil des Container-Images bilden. Externe Dienste wie Datenbanken und API-Schnittstellen werden meistens ausserhalb des Containers betrieben. Die Unterscheidung zwischen externen Komponenten und Teilen des Container-Images ist notwendig, um eine containerbasierte Applikation richtig zu konfigurieren.
Daten innerhalb eines Container-Images sind im Vergleich zu bezogenen Daten aus externen Datenbanken und Schnittstellen meistens flüchtig und nicht persistent. Die aufgezählten Abhängigkeiten müssen während der Segmentierung der Applikation in einzelne Services berücksichtigt werden.
Zielarchitektur definieren
Basierend auf der ausgewählten Technologie und den erkannten Abhängigkeiten wird die Zielarchitektur der Container-Infrastruktur definiert. An dieser Stelle möchten wir besonders auf die Wahl des Standorts der Applikationsdaten verweisen. Es ist von zentraler Bedeutung, in der Zielarchitektur festzulegen, welche Art von Daten nach einer möglichen Aufteilung der Applikation wo abgespeichert werden. Eine (containerisierte) Applikation in der Cloud verfügt über andere Anforderungen an die Sicherheit als eine Applikation, welche sich On-Premises befindet. Ein Container, welcher streng vertrauliche Daten innerhalb der Applikation verarbeitet, stellt nicht dieselben Anforderungen an die Sicherheit, wie ein Container, welcher rein das Benutzerinterface eines Webportals hostet.
Priorisierung der Services
Die Resultate aus der Analysephase und die definierte Zielarchitektur ermöglichen eine verlässliche Priorisierung, welche die Reihenfolge der Migration bestehender Services in die neue Container-Infrastruktur vorgibt. Die Priorisierungskriterien stellen sich aus unterschiedlichen Faktoren zusammen. Diese Faktoren müssen entsprechend gewichtet werden. Die Gewichtung orientiert sich dabei anhand der definierten Anforderungen sowie den Eigenschaften der Applikation.
- Relevanz des Services in Bezug auf Geschäftsprozesse
- Technische Komplexität des Serviceaufbaus
- Höhe des geschätzten Aufwands für die Containerisierung
- Grad der Sicherheit
- Etc.
Vorbereiten und Implementieren
Nach Abschluss der Arbeiten in der Analyse- und Planungsphase erfolgt der Übergang zu einer containerbasierten Architektur. Dieser beginnt mit der Installation und dem Aufsetzen der Plattform, definiert gemäss Zielarchitektur. Im Kern dieser Phase steht die Erstellung und Konfiguration der Docker-Images für die einzelnen Container sowie anderen Artefakten, welche die Grundlage für die containerisierte Anwendung bilden.
Containerisierungsprozess
Der Prozess hinter der Erstellung der Container-Images hängt von der ausgewählten Technologie ab. Basierend auf Docker fängt dieser bei der Erstellung einer Datei zur Komposition des Docker-Aufbaus an. Man nennt diese Datei «Dockerfile». Ein «Dockerfile» ist eine textbasierte Konfigurationsdatei in YAML-Notation, welche alle Befehle in einer spezifischen Reihenfolge enthält, um ein Container-Image zu erstellen. Bei der Erstellung des Dockerfile ist es ebenfalls wichtig, dies mit Versionierungs-Tags zu versehen. Durch Versionierungs-Tags können Container-Images mit Informationen versehen werden, welche für Entwickler der Applikation helfen, zwischen Test- oder Produktiv-Images unterscheiden zu können.
Die Container-Images werden, wie in der vorherigen Phase definiert, gemäss den einzelnen Microservices aufgeteilt und gegliedert. Nachdem das Container-Image erfolgreich erstellt worden ist, kann es direkt innerhalb von Docker getestet werden. Nach einer erfolgreichen Testphase kann das Docker-Image entweder an einem speziell für die Zielarchitektur bestimmten Speicherort oder in einer Container Registry gespeichert werden. Die Anzahl der benötigten Docker-Images und Container einer Applikation hängt von der definierten Zielarchitektur und deren Komponenten ab. Die fertigen Container-Images können anschliessend über eine Container Orchestration Plattform als Grundlage für lauffähige Container bereitgestellt werden.
Container Orchestrierung
Ein Container Orchestrierungstool ist ein System für die Verwaltung, das Deployment und den Betrieb von Containern. Mittels Container Orchestration können Container skaliert, organisiert und innerhalb kürzester Zeit auf ihre vorgesehenen Plattformen bereitgestellt werden. Container Orchestrierungstools ermöglichen ebenso das Tracking der Auslastung, der Rechenleistung und der Verfügbarkeit von Containern, weshalb sie auch für deren Monitoring eingesetzt werden. Eines der führenden Orchestrierungstools für Container ist Kubernetes. Kubernetes ermöglicht die Verwaltung von Clustern, die aus Nodes bestehen:
![Kubernetes](https://www.atrete.ch/wp-content/uploads/2024/04/Kubernetes-1024x462.png)
Die Nodes in Kubernetes können physische oder virtuelle Maschinen sein. Sie sind die Arbeitseinheiten, welche die Container ausführen, skalieren und überwachen. Ein Kubernetes-Cluster setzt sich zusammen aus mindestens einem Master-Node, der die Orchestrierung und Verwaltung des Clusters übernimmt, und mehreren Worker-Nodes, auf denen Applikation(en) in Containern laufen.
Die Nutzung von Nodes innerhalb von Kubernetes ermöglicht die Kontrolle über Ressourcen und bietet eine hohe Verfügbarkeit durch Replikation. Durch Features wie automatische Skalierung kann eine Applikation basierend auf ihrer Auslastung dynamisch skaliert werden, um Ressourceneffizienz und optimale Performance zu gewährleisten.
Es ist von zentraler Bedeutung, auf ein Orchestrierungstool beim Aufbau einer containerbasierten Infrastruktur zu setzen, um die Übersicht sämtlicher Container bei vorgesehenem Wachstum einer Applikationslandschaft beibehalten zu können und zu vereinfachen. Da es in der Natur von Orchestrierungstools liegt, etliche manuelle Prozesse bei der Container-Bereitstellung zu automatisieren, sind sie auch perfekt geeignet für die Implementation von modernen DevOps-Ansätzen durch CI/CD Pipelines.
Integration und Betrieb
Integration von CI/CD und Devops durch Orchestration
Der gesamte Containerisierungsprozess lässt sich mithilfe von Container Orchestrierung und CI/CD Pipelines im Tagesbetrieb automatisiert in neue oder bestehende DevOps-Praktiken integrieren. Dies vereinfacht nicht nur das Deployment, sondern auch die Wartung der containerisierten Applikation erheblich. Neue Builds eines Container-Images können durch vorkonfigurierte «Build-Pipelines» innerhalb von wenigen Minuten auf bestehende oder neue Container getestet und produktiv bereitgestellt werden.
Besonders für Verteilungsansätze wie das Blue-Green Deployment eignet sich eine containerisierte Applikation sehr gut, weil Container schnell, konsistent ohne Umbruch im Datenverkehr bereitgestellt werden können. Die Isolation und Sicherheit von Containern minimiert die Fehleranfälligkeit und ermöglicht einfache Rollbacks zu vorherigen Versionen beim Auftreten von Problemen. Darüber hinaus optimieren Container die Ressourcennutzung, was sich als besonders vorteilhaft im Parallelbetrieb von mehreren Versionen einer Anwendung erweist, wie es im Blue-Green Deployment der Fall ist.
![CI/CD und IaC](https://www.atrete.ch/wp-content/uploads/2022/08/2022-08-25-Cloud-CI-CD-1024x640.jpg)
Erfahren Sie mehr über Verteilungsansätze und CI/CD in unserem Blogbeitrag über CI/CD und IaC
CI/CD und IaC
von Thomas Somogyi
Fehlerbehebung durch integriertes Monitoring
Die Vorbereitungen wurden abgeschlossen, die Container-Infrastruktur wurde aufgebaut und die Applikation kann über das Orchestrierungstool verwaltet werden. Nun gilt es, den Betrieb der Applikation zu sichern und zu überwachen, um diese später in den produktiven Tagesbetrieb zu übernehmen.
Hier bietet ein Orchestrierungstool wie Kubernetes eingebaute Monitoring-Funktionalitäten, welche es ermöglichen, Daten und Logs im Tagesbetrieb zu sichern.
Aktive Container sammeln während des Betriebs regelmässig Nutzungsdaten, aus denen sich mittels Analysen Verbesserungspotenziale zur Infrastruktur oder am darunterliegenden Microservice ziehen lassen. Diese Log-Daten können ebenfalls für das Bugfixing des Services durch Entwickler verwendet werden. Aufgrund der Abkapselung und Isolation der Applikation in die einzelnen Container lassen sich Ursachen von Fehlerquellen schnell erkennen und beheben.
Weitere Herausforderungen in der Containerisierung
Im Rahmen eines Kundenprojekts hat die atrete eine schweizerische Bank dabei unterstützt, die Zielarchitektur einer containerbasierten Applikationslandschaft zu definieren. Während dieses Vorhabens haben wir verschiedene Stolpersteine und Herausforderungen gemeistert.
Hier sind einige der gängigsten Fälle, die während der Konzipierungsphase im Projekt aufgetreten sind:
- Die Integration von containerbasierten Applikationen mit Legacy-Systemen stellt oft eine Herausforderung dar, besonders wenn dabei File Transfer Technologien zum Einsatz kommen, die auf Agents basieren. In vielen Fällen sind spezielle Lösungen erforderlich, um diese Technologien für den Einsatz in der Container-Welt anzupassen.
- Container sind in der Regel flüchtig, was bedeutet, dass Daten verloren gehen können, wenn ein Container gelöscht wird. Für Anwendungen, die eine Datenpersistenz benötigen, muss eine Strategie zur Datenspeicherung und -verwaltung ausserhalb der Container entwickelt werden. Eine derartige Strategie sollte sich im Design der Zielarchitektur widerspiegeln.
- Obwohl Container-Technologien bereits seit einiger Zeit eingesetzt werden, sind viele Menschen in deren Handhabung noch nicht versiert und benötigen entsprechende Schulungen, um zu lernen, wie solche Applikationen betrieben werden können. Dies trifft insbesondere auf die erstmalige Einrichtung einer containerbasierten Applikation zu, bei der spezifisches Know-how erforderlich ist.
Unser Fazit
Durch Containerisierung lassen sich Applikationen skalieren, einfacher verwalten und Entwicklungsprozesse im Betrieb weiter automatisieren. Bevor man von diesen Vorteilen profitieren kann, ist ein variabler Initialaufwand notwendig. Dieser Aufwand beschränkt sich darauf, die zu migrierende Applikation zu verstehen, um darüber urteilen zu können, welche Abhängigkeiten, Komponenten und Sicherheitsaspekte von Bedeutung sind. Die Höhe des Aufwands hängt von der Grösse, Komplexität und den Anforderungen an die Applikation ab. Wir denken, dass besonders bei hochkomplexen Applikationen eine Detailstudie zur Machbarkeit einer Containerisierung notwendig ist, bei deren Erarbeitung wir Ihr Unternehmen unterstützen können.
Für die Konzeption und Umsetzung von Containerisierung bestehen Best Practices. Hierbei empfehlen wir auf bewährte Ansätze gängiger Hersteller wie Docker für die Implementation oder Kubernetes für die Orchestrierung zu setzen.
Bei den einzelnen Schritten im Migrationsprozess ist unserer Meinung nach besonders die Zielarchitektur massgebend.
Eine falsche oder fehlerhafte Definition der Container-Infrastruktur kann negative Auswirkungen auf die Implementierung und den langfristigen Betrieb haben. Beispielsweise kann eine erhöhte Komplexität durch zu viele Abhängigkeiten entstehen oder es können Leistungsprobleme durch überdimensionierte Images auftreten. Ausserdem soll für die Auswahl einer Containerisierungs-Technologie geprüft werden, welches unternehmensinterne Knowhow zu welcher Technologie bereits vorhanden ist, um potenzielle Synergieeffekte nutzen zu können. Die Technologieauswahl soll ein Orchestrierungstool enthalten, mit welchem die Container-Infrastruktur modular strukturiert, gemonitort und verwaltet werden kann.
Anhand der Erkenntnisse und Resultate aus der Analyse- und Planungsphase kann ermittelt werden, welches die grössten Vorteile sind, die ein Unternehmen aus der Containerisierung von Applikationen ziehen kann. Eine Container-Infrastruktur lässt sich nach dem Initialaufbau durch ein etabliertes Vorgehen und definierten Richtlinien zukunftssicher ausbauen.