DevOps-Sportfreunde

Der folgende Artikel knüpft an den Beitrag „Skills, Tools und das richtige Mindset für DevOps“ – JAVAPRO 03-2018[1] an und schlägt die Brücke zwischen den Konzepten und Prinzipien hin zur gelebten Praxis. Wenn man das Thema DevOps mit einer Sportart vergleicht, dann kommt nach der allgemeinen Beschreibung der Spielregeln aus dem vorhergehenden Artikel nun die Wahl einer geeigneten Spieltaktik (Organisation) und Ausrüstung (Technologie). Drei Sportler schildern ihre persönlichen Erfahrungen aus Softwareprojekten.

Beim Thema DevOps werden Ziele angestrebt wie etwa Effizienzsteigerungen, die Erhöhung der Kundenzufriedenheit und Kostenreduktionen. Auf gleicher Augenhöhe gilt es aber die Einführung von transparenten Prozessen, cross-funktionalen Teams und die schnelle Reaktion auf neue Anforderungen im Blick zu haben. All dies sollte im Kontext einer modernen IT stehen, zu der Themen wie Agilität, Microservices und Cloud gehören.

Zwei zentrale Besonderheiten sind hier hervorzuheben: Einerseits bildet die Suche nach einer passenden Organisationsform die Grundlage einer funktionierenden DevOps-Kultur[2]. Des Weiteren erkennt man meistens erst während der Transition die Menge an manuellen, repetitiven Schritten, die zuvor überhaupt nicht dokumentiert waren. Will man diese Punkte einhalten und messbar machen, so kann man folgende drei Aspekte betrachten:

  1. Herausforderungen erkennen: Müssen während der DevOps-Transformation alte Prozesse und Legacy-Produkte aufrechterhalten werden? Wie erlangen alle Entwicklerteams ein Bewusstsein für Betriebsthemen? Wie verhindert man, dass man durch Betriebsthemen den Fokus auf die Feature-Entwicklung verliert? Wie kann man die radikalen Freiheiten aus dem DevOps-Gedanken mit Vorgaben zur IT-Compliance vereinbaren?
  2. Strategien finden: Soll man dedizierte DevOps-Teams als Hub zwischen Entwicklern und klassischen Rechenzentren bilden? Welche Ansprüche hat man an eine Continuous-Integration- und Continuous-Deployment-Pipeline? Wie kann man die Entwicklerteams mit genau den Monitoring-Messpunkten versorgen, die relevant sind?
  3. Verbesserungen anstreben: Was will man mit DevOps erreichen? Sollen die Release-Zyklen kürzer werden (Time-to-market)? Soll die Reaktionsfähigkeit bei Fehlern verbessert werden (Stabilität und Robustheit)? Sollen bereits früh in der Planung von Features Problemzonen im späteren Softwarebetrieb erkannt werden? Soll durch Standardisierung mittels bewährter DevOps-Modelle eine Nachhaltigkeit und hohe Qualität der Wissensbasis erzielt und sollen technische Schulden dadurch vermieden werden?

 

Motiviert durch diese Aspekte beschreiben die folgenden Erfahrungsberichte verschiedene Projekte und ihre jeweils gewählten Ansätze. Die Schilderungen unterscheiden sich einerseits in der Perspektive: Teil 1 blickt auf das Zusammenspiel mehrerer Teams, Teil 2 beschreibt die Erfahrungen eines Entwicklerteams und Teil 3 zielt auf die Auswirkungen für Applikationen. Andererseits führte je Projekt eine andere Organisationsstruktur zum Ziel. Daher enthalten die Erfahrungsberichte jeweils eine graphische Darstellung ihrer Organisationsstrukturen, die sich an der Webseite „DevOps Topologies[3]“ orientiert.

 

Teil 1: Aus der Gesamtprojektsicht

Co-Autor Florian Zierer beschreibt seine Erfahrungen aus einem Projekt, in dem eine DevOps-Transition mit über hundert Entwicklern in vielen Aspekten realisiert werden konnte und in dem weiterhin an dem Optimierungsgedanken festgehalten wird. Es handelte sich um ein Projekt mit circa 40 Applikationen eines großen Web-Portals und dahinterliegenden Backend-Systemen. Es gab etwa zehn Entwicklerteams, die durch zwei sogenannte Enabler-Teams unterstützt wurden, die als Katalysator die Hinführung zu einer DevOps-Kultur ermöglichten.

 

Enabler-Teams als Hub und Adapter

Die Enabler-Teams bestanden aus Personen, die Entwicklererfahrungen hatten, aber auf Betriebsthemen spezialisiert waren. Ihre Aufgabe war es, ein Kommunikations-Hub zwischen den Entwicklerteams zu bilden und eine Adapterrolle zwischen Entwicklern und der eigentlichen Betriebsabteilung einzunehmen, die sich in einem entfernten Rechenzentrum befand. Realisiert wurde dies, indem ein Enabler-Team einerseits das Release- und Change-Management übernahm und andererseits die Prüfung und Filterung von Auffälligkeiten im Produktionsbetrieb im Fokus hatte (inklusive Weiterleitung an die betroffenen Entwicklerteams). Das andere Enabler-Team pflegte und erweiterte die technische Basis der Entwicklungs-, Integrations- und Abnahmeumgebungen. Dazu zählten die standardisierte Orchestrierung etlicher virtueller Server (via Ansible), die einfache Handhabung von CI-Tools (wie etwa Jenkins) und die Bereitstellung von Container-Plattformen (in Form von Docker-Swarm). In (Abb. 1) ist diese Art der Zusammenarbeit graphisch dargestellt.

 

Brückenschlagen zwischen Entwicklern und dem Betrieb. (Abb. 1)

Die Entwicklerteams waren autonome, agile Einheiten, die in der Regel aus fünf bis zehn Entwicklern bestanden und ihr agiles Vorgehensmodell selbst auswählen konnten, sodass es zu ihrer Teamgröße und ihren Anforderungen passte. Scrum wurde hier am meisten eingesetzt, wobei die zwei größten Teams (aus je 15 bis 20 Entwicklern bestehend) sich für Kanban oder Nexus entschieden. Im Projekt wurde Selbstständigkeit stark gefördert, damit die Teams ihren Deployment-Prozess formen und kontrollieren konnten, nämlich wie er am besten für ihr Produkt geeignet war. Dadurch konnte die Grundlage für die agilen Teams geschaffen werden, damit sie durch Selbstverantwortung und Selbstorganisation ein starkes Commitment für ihre Deliverables aufbauen konnten.

Die zuvor erwähnten Enabler-Teams spielten dabei entscheidend zu: In ihrer Rolle als Adapter zum Betrieb sorgten sie dafür, dass Produktionsprobleme nach allgemeinen oder bekannten Problemen vorgefiltert werden konnten. Erst wenn spezifisches, tieferes Wissen aus einer Applikation nötig war, leiteten sie die Probleme an die Teams der betroffenen Applikationen weiter und nahmen so ihre Rolle als Hub zwischen den Entwicklern wahr. Dadurch konnten die Entwicklerteams sich dedizierter mit dem Thema Betrieb befassen und weiterhin den Fokus auf ihr Wertschöpfungs-Commitment legen. Erfahrungen ergaben, dass der Betrieb etwa 10% der Probleme beheben konnte, aber Feedback von den Entwicklern für die restlichen 90% brauchte. Durch die Enabler-Teams als Puffer mit ihren Erfahrungswerten und Voranalysen mussten sich die Entwicklerteams nur mit 10 bis 20% der Produktionsprobleme befassen. Darüber hinaus sorgten die Enabler-Teams für ein homogenes Umfeld in einer heterogenen IT-Landschaft aus Legacy-Systemen und halbautomatischer Plattformen wie etwa Docker-Swarm. Dies war ebenfalls ein wichtiger Baustein, um den Entwicklerteams ein geordnetes Verständnis über den Aufbau der IT-Landschaft als Ganzes zu geben.

 

Beispiele, wie die DevOps-Kultur gedeihen konnte

Hier ein konkretes Beispiel des gelungenen Zusammenspiels im Rahmen einer DevOps-Transition: Ein großes Entwicklerteam stellte im Rahmen einer gut geplanten Umstellung innerhalb eines Jahres alle ihre statischen virtuellen Testserver auf dynamisch skalierbare Docker-Container in einem Docker-Swarm-Cluster um, d.h. für jeden Feature-Branch in der Git-Versionskontrolle wurde automatisch ein Container bereitgestellt. Auf dieser Grundlage konnte ein weiteres großes Team aufbauen und die Erfahrungen und das Wissen wiederverwenden. Dieses Team konnte einen Schritt weiter gehen und dadurch seine Architektur auf Microservices umstellen und eine Continuous-Deployment-Pipeline bis in die Staging-Umgebung realisieren. Ohne die Vorarbeiten des ersten Teams wäre die Umstellung extrem aufwendig gewesen. Dies war ein gutes Beispiel, wie Wissen skalieren konnte. Insbesondere sind diese beiden Teams dadurch einen großen Schritt unabhängiger von den Enabler-Teams geworden und somit einem DevOps-Leitbild näher gerückt. Es gab auch Teams, die den Schritt in die Cloud erprobten. Es gab aber auch Teams, die auf Grund von technologischen Einschränkungen (z.B. durch vorgegebene monolithische Frameworks) nicht ohne weiteres auf Microservices und Container umstellen konnten. Diese Teams erhielten aber die Möglichkeit, eine klassische DevOps-Schiene zu verfolgen, indem sie etwa durch den Einsatz von Ansible oder Puppet ihre statischen virtuellen Maschinen selbst verwalten und somit dennoch ein Verständnis des Betriebs entwickeln konnten. Die Enabler-Teams ermöglichten hier die unbürokratische Bereitstellung von virtuellen Servern und das unkomplizierte Wiederherstellen nach einer destruktiven Änderung durch die Entwickler. Umrahmt wurde dieses Gesamtprojekt durch die Bereitstellung von Messinstrumenten fürs Monitoring (wie etwa SiteScope, Splunk, Prometheus), die es den Entwicklern ermöglichten, ihre Applikationen ganz aus ihrer Expertensichtweise zu beobachten. Natürlich klappte das alles nur durch den hingebungsvollen Einsatz von Entwicklern, die diese Tools bedienen und auf die wesentlichen Messpunkte fokussieren konnten.

 

Fazit aus dieser Transition

An dieser Organisationsform begeisterte vor allem die Dynamik des Wissenstransfers, durch die recht komplexe Technologien zwischen den Teams ausgetauscht werden konnten. Des Weiteren war es sehr wichtig, dass  Entwickler durch die oben erwähnte Filterung von Bug-Tickets von einer Flut an Operationsthemen verschont blieben und sich weiterhin auf die Applikation konzentrieren konnten. Abgerundet wurde dies durch den leichten Zugang zu Messinstrumenten und die Möglichkeit, die Sensoren bei der Überwachung der Applikationen selbst zu konfigurieren. Denn mit jedem neuen Sensor wuchs das Verständnis über die Applikation und das Wissen wie sie sich im Normal- und im Problemfall verhalten sollte. All dies schärfte wiederum den Blick auf das Thema Softwarebetrieb, der durch viele Synergieeffekte mit anderen Entwicklerteams getragen wurde. Ohne eine gelebte offene Organisation wäre dies nicht möglich gewesen.

 

Teil 2: Aus der Sicht eines Entwicklerteams

Co-Autor Christopher Hensel beschreibt nachfolgend seine Erfahrungen aus einem abteilungsübergreifenden, agilen Gesamtprojekt zur DevOps-Transformation und schildert seine konkrete Sicht als Mitglied eines Teams, dessen Schwerpunkte Authentifizierung und Autorisierung waren.

 

Entwicklungsprozess

Das Team arbeitete nach der agilen Methode Kanban, bei der jede durch einen Entwickler begonnene User-Story mithilfe eines zweiten Entwicklers im Refinement besprochen wurde, um für die Umsetzung der Anforderung notwendige Aufgaben zu erfassen. Die Entwicklung selbst erfolgte nach dem Modell des Trunk-Based-Developments. Damit der Trunk immer release-fähig bleiben konnte, wurden kritische Änderungen durch Feature-Toggles geschützt, welche umgebungsspezifisch gesteuert wurden. Standardmäßig waren diese auf der Integrationsumgebung aktiviert, damit die Änderungen im Rahmen der Continuous-Integration frühzeitig ausgerollt und getestet werden konnten. Für die Continuous-Integration war ein Jenkins im Einsatz, den das Team selbst verwaltete. Bei einer neuen Änderung auf dem trunk-Branch wurde automatisch der Continuous-Integration-Prozess als Job auf dem Jenkins gestartet. Dabei wurden das gesamte Projekt gebaut, alle Unit- und Integrationstests ausgeführt und statische Code-Analysen auf einem Sonarserver durchgeführt. Nachdem all diese Schritte erfolgreich waren, konnte das aktuelle Artefakt auf der Integrationsumgebung ausgerollt werden. Am Ende des Entwicklungsprozesses nahm der Product-Owner (PO) die User-Story auf der Integrationsumgebung ab, um sie schließlich für das Deployment auf der Abnahmeumgebung freizugeben.

 

Continuous-Delivery-Prozess

Die DevOps-Transformation betraf das Team erst ab dem Abnahmeschritt maßgeblich, nämlich im Rahmen der Einführung eines Continuous-Delivery-Prozesses mit Hilfe moderner Technologien. Für die Bereitstellung eines Releases auf einer Umgebung mussten die Entwickler vor der Transformation für alle Module, die im Rahmen einer User-Story verändert wurden, Release-Tasks in JIRA erstellen. Insbesondere wurden darin etwaige manuelle Aufgaben vermerkt, die im Rahmen des Deployments auf den Umgebungen nötig waren. Bei der Abnahmeumgebung wurde der Task in die Spalte Abnahme eingeplant verschoben, um dem zuständigen Betriebsverantwortlichen mitzuteilen, dass das Deployment durchzuführen war. Erst nachdem der Betriebsverantwortliche den Task auf die Spalte „Abnahme deployed“ verschoben hatte, wurde der PO benachrichtigt, der die Abnahme in Abstimmung mit dem Fachbereich auf dieser Abnahmeumgebung durchführte. Nach erfolgreicher Abnahme wurden die Schritte für die Demonstrations- und Produktionsumgebung wiederholt.

Die Deployments in Produktion erfolgten dabei mehrmals am Tag. Obwohl die Zusammenarbeit zwischen dem Entwicklerteam und dem zuständigen Betriebsverantwortlichen sehr gut war, mussten manuelle Schritte durch den Betriebsverantwortlichen durchgeführt werden. Hierdurch war das Entwicklerteam auf den Betriebsverantwortlichen angewiesen, um aktuelle oder dringende Änderungen in Produktion auszurollen. Um dieser Einschränkung zu begegnen, erhielten die Entwicklerteams im Rahmen der DevOps-Transformation eine eigene Instanz des Deployment-Werkzeugs, mit dessen Hilfe sie die Artefakte auf allen Umgebungen ausrollen konnten. Verwendet wurde hierfür ein hauseigenes, kommandozeilenbasiertes Deployment-Werkzeug. Damit das Deployment auf allen Umgebungen selbstständig durch das Entwicklerteam erfolgen konnte, war die Verwaltung der Deployment-Konfigurationen für alle Umgebungen durch das Team notwendig. Unter diesen Voraussetzungen konnten weitere Jobs auf dem bereits bestehenden Jenkins erstellt werden, die die Ausführung der Deployments auf den einzelnen Umgebungen mithilfe des Deployment-Werkzeugs durchführten. Im späteren Verlauf wurden die Jobs mit Shell-Skripten erweitert, um komplexere Deployments wie das Deployen mehrerer Instanzen desselben Artefakts zu ermöglichen.

 

Deployment-Pipeline

Darauf aufbauend wurde eine Deployment-Pipeline auf Basis einer Jenkins-Pipeline entwickelt und die Shell-Skripte wurden durch Groovy-Skripte ersetzt, da sich diese besser testen ließen und vorhandenes Wissen über Java im Team genutzt werden konnte. Dies reduzierte den Deployment-Prozess auf ein Minimum und eröffnete den Weg zu Continuous-Delivery. Manuelle Schritte waren lediglich nötig für:

  1. die Freigabe des Deployment-Prozesses auf die einzelnen Umgebungen innerhalb der Jenkins-Pipeline (insbesondere durch den PO auf die Abnahmeumgebung),
  2. spezifische manuelle Schritte zur User-Story, wie etwa die Anpassung der Deployment-Konfiguration oder das Aktivieren von Feature-Toggles.

Diese spezifischen Tasks wurden weiterhin in JIRA in Release-Tasks festgehalten und in der neuen Deployment-Pipeline angezeigt. Dadurch entfiel ein Wechsel in eine zweite Umgebung. Des Weiteren wurden die Release-Tasks für die Module nun durch die Pipeline automatisch angelegt und auf dem Release-Board verschoben. Anhand der Release-Tasks konnte verfolgt werden, welche Änderungen noch zu deployen waren und auf welcher Umgebung sie aktuell umgesetzt waren. Es gab auch die Funktion, das Deployment von bestimmten Modulen zu blockieren, indem der Release-Task des Moduls um ein Label „Deployment blocked“ ergänzt wurde. Es war dann eine zusätzliche, explizite Zustimmung während des Deployments des Moduls notwendig.

Die meisten Verbesserungen wurden im Continuous-Delivery-Prozess durch eine Change-Detection erzielt. Diese erkannte automatisch nach dem Commit die von den Code-Änderungen betroffenen Module und annotierte die entsprechende User-Story mit dem Modul. Dadurch waren an der User-Story alle Module in der entsprechenden Version protokolliert, in der sie herausgebracht werden mussten, um die in der User-Story umgesetzte Funktionalität vollständig zu deployen. Wurden die Änderungen schließlich auf die Produktionsumgebung ausgerollt, so wurde automatisch ein Eintrag im unternehmensweiten Change-Kalender generiert. In Summe haben diese Maßnahmen den Wertschöpfungsprozess, der von der Einplanung bis hin zum Release in Produktion durchlaufen werden musste, um die User-Story herum zentriert.

 

Weitere technische Verbesserungen

Verbesserungen bezogen sich auch auf die Sicherheit des Produkts und die Vereinfachung der administrativen Tätigkeiten. Eine Pipeline prüfte die Abhängigkeiten aller Module auf ihre Aktualität und erstellte automatisch eine User-Story für Major-Release-Updates oder eine weitere, wenn mehr als zehn Minor-Updates für ein Modul vorzunehmen waren. Andere Pipelines wiederum erleichterten das Ausrollen einer neuen Version des Java-Runtime-Environments oder des Servlet-Containers auf allen Systemen eines Produkts. Ebenfalls vereinfacht wurde der Prozess zur Verwaltung von Datenbankänderungen. Bereits vor der DevOps-Transformation wurden alle Schemaänderungen eines Produkts durch Flyway verwaltet. Die Änderungen von Daten einer bestimmten Umgebung mussten jedoch über einen Roboter verwaltet werden, deren Einstellung und Freigabe zuvor nur durch die Betriebsverantwortlichen erfolgen konnte. Im Rahmen der DevOps-Transformation wurde der Selfservice für Datenbankroboter allen Entwicklern zugänglich gemacht, wodurch die Reaktionszeit für dringende Datenbankänderungen verbessert werden konnte.

 

Organisatorische Änderungen

 

Entwickler und der Betrieb arbeiten direkt zusammen. (Abb. 2)

Neben den bereits erläuterten technischen Herausforderungen und Neuerungen mussten organisatorische Aufgaben gelöst und Prozesse angepasst werden, beginnend bei der Organisation der Entwicklerteams. Manche Teams hatten dedizierte DevOps-Personen und in anderen Teams übernahmen alle Entwickler gleichermaßen die DevOps-Rolle. Unabhängig davon wurden jedoch alle Teams durch die Übernahme der DevOps-Rolle mit neuen Aufgaben betraut, um den Betrieb ihrer Anwendungen sicherzustellen. Dazu zählte die Betreuung von Wartungsfenstern, die zuvor durch dedizierte Betriebsverantwortliche erfolgte. Zusätzlich fiel die Erstellung und Verwaltung der Anwendungskonfiguration mittels Configuration-Management-Database (CMDB) in den Aufgabenbereich der Entwicklerteams, durch die definiert wurde, über welche Netze und Zugangsadressen die Anwendung erreichbar sein soll und welcher Zugriffsschutz für die Anwendung benötigt wird. In diesem Zusammenhang mussten Rollen und Rechte erstellt oder angepasst werden, für Themen wie die Verwaltung von Anwendungskonfigurationen, den Zugriff auf Datenbanken oder auch die Verwaltung von Endbenutzern und technischen Benutzern der Anwendungen. Für die Einführung der DevOps-Kultur mussten die Zuständigkeiten neu geklärt werden. Zu Beginn bestand eine große Unsicherheit bezüglich der Aufgabenverteilung zwischen den Entwicklern und dem Betrieb aufgrund der unklaren Definition. Bedingt durch diese Unsicherheit wurde die Zusammenarbeit zunächst schwieriger und tendierte Richtung No-Ops. Erst durch einen intensiveren Austausch zwischen den Entwicklern und dem Betrieb sowie der Klärung der Verantwortlichkeiten konnte die Zusammenarbeit wieder gestärkt werden. Seitens des Betriebs gab es viel Unterstützung, damit die Entwickler das Wissen zum Anwendungsbetrieb aufbauen konnten. Daraus resultierte die Idee zur Community-of-Practice, die als Plattform für den Wissenstransfer zwischen Betrieb und den unterschiedlichen Entwicklerteams notwendig war. In dieser trafen sich einmal pro Wochen ein DevOps-Zuständiger aus jedem Team und zwei Vertreter aus dem Betrieb, um aktuelle Probleme in den Entwicklerteams und neue Anregungen aus dem Betrieb zu besprechen. Im Anschluss trugen die Teilnehmer die Ergebnisse zurück in ihre Teams. Durch dieses Vorgehen konnten Synergieeffekte zwischen den Entwicklerteams und das Wissen der ehemaligen Betriebsverantwortlichen genutzt werden. In (Abb. 2) ist diese Art der Zusammenarbeit graphisch dargestellt.

Trotz der Anpassungen in der Organisation und der Ausweitung der Rechte für Entwickler blieben Einschränkungen für DevOps. Virtuelle Maschinen mussten weiterhin per Ticket beim Betrieb beantragt werden. Ebenso war es mit Firewall-Freischaltungen und Proxykonfigurationen, die auf schriftlichem Wege beantragt werden mussten. Eine weitere Einschränkung bestand bei der Verwaltung der Anwendungs-Server. Hier beschränkten sich die Rechte auf die Anwendungskonfiguration und die Konfiguration des Servlet-Containers. Den genannten Einschränkungen könnte mit der Verwendung einer Cloud-Plattform begegnet werden, die gleichzeitig ein zukünftiges Ziel für die Weiterentwicklung im Rahmen der DevOps-Transformation darstellen könnte.

 

Fazit aus dieser Transition

Zusammenfassend lässt sich sagen, dass es essenziell ist, die neue DevOps-Kultur in den Teams sowie in der Organisation zu verankern. Hierzu wurde der Transformationsprozess anhand eines Kanban-Boards an einem prominenten Platz wie der Kaffeeküche transparent gemacht. Nichtsdestotrotz ist der Mehrwert, der durch die Einführung der DevOps-Kultur im Unternehmen entstanden ist, nur schwer messbar. Der Umstand, dass vor der Einführung keine Daten erhoben und zu Beginn des Prozesses keine messbaren Ziele definiert wurden, erschweren einen objektiven Vergleich. Dennoch wurde im Laufe der Transition das große Potential zur Automatisierung des Deployment-Prozesses sichtbar. Es gab zwar weiterhin manuelle Aufgaben, doch diese reduzierten sich auf wichtige Spezialpunkte. Die Aufgaben zur Verwaltung der User-Stories und die Abbildung des Deployment-Prozesses innerhalb von JIRA wurden automatisch durch die Deployment-Pipeline übernommen. Außerdem wurden durch die Automatisierung neue Kapazitäten innerhalb des Betriebs geschaffen, welche sich nun auf neue, übergreifende Themen wie die Zero-Downtime-Wartung und die Verbesserung des Monitorings sowie der Analytics-Plattform konzentrieren konnten.

 

Teil 3: Aus der Sicht einer Applikation

Co-Autor Matthias Engelke beschreibt hier ein drittes Projekt, bei dem eine hochmoderne IT-Landschaft in der Cloud mitgestaltet wurde. Die Beschreibung zielt auf die Sichtweise der Applikation und ihrer umliegenden Rahmenbedingungen, die auch das Thema DevSecOps im Blick hat (siehe auch JAVAPRO 03-2018).

 

Containertechnologie

Containerbasierte Entwicklung und ein cloudbasierter Betrieb. (Abb. 3)

In diesem Projekt aus der Automobilindustrie ging es zum einen um den Aufbau einer hochverfügbaren und weltweit verteilten Container-Registry, die die Bereitstellung von Applikationen als Container-Images ermöglichte. Zum anderen wurde der Entwicklungsprozess solcher Applikationen mittels Continuous-Integration und Continuous-Delivery unterstützt und verbessert. Die Container-Technologie und der durch Docker gewachsene Trend dahin lassen sich seit mehreren Jahren auch in der Automobilindustrie beobachten, die diese in unterschiedlichen Themenbereichen sowohl in der Entwicklung als auch in der Produktion einsetzt. Als der Autor das Projekt zum ersten Mal kennenlernte, überraschte es, dass wenige bis keine Anzeichen von DevOps in den Entwicklerteams zu erkennen waren. Diese Teams arbeiteten an verschiedenen Applikationen für eine gemeinsame Plattform, doch verwendeten sie jeweils unterschiedliche Prozesse und Methoden, um ihre Apps zu bauen, testen und auszurollen, obwohl Docker als Technologie eingesetzt wurde. Denn Docker hilft insbesondere bei der Umsetzung des DevOps-Gedanken und wird daher von vielen als der DevOps-Enabler bezeichnet.

 

Cloud-Plattform

Für die Bereitstellung der skalierbaren, hochverfügbaren und weltweit verteilten Container-Registry, die für die Auslieferung aller Applikationen in Form von Docker-Images produktiv eingesetzt werden sollte, kam eigentlich nur eine Cloud-Plattform in Betracht. Das lag unter anderem daran, dass AWS schon beim Kunden erfolgreich eingesetzt wurde, aber auch daran, dass der traditionelle Ansatz eines Datenzentrums bei der benötigten Skalierbarkeit aufgrund der erfahrungsgemäß hohen Rüstzeiten keine Möglichkeit war. Diese Skalierbarkeit kam insbesondere durch den Einsatz des Elastic-Container-Service (ECS) zum Vorschein. Hierbei handelt es sich um Amazons Container-Orchestrierungs-Service, der das Ausführen, Beenden und Verwalten von Docker-Containern innerhalb eines Clusters vereinfacht und durch API-Aufrufe steuerbar macht.

Für die Umsetzung dieses Projektes ging man direkt mit dem DevOps-Gedanken an den Start, um mit Hilfe von Infrastructure-as-Code und viel Automatisierung die bisherigen, allzu bekannten Probleme zu verhindern. Der Leitgedanke dabei war, alle benötigten Cloud-Ressourcen mit Hilfe von Terraform, Continuous-Integration und Continuous-Delivery automatisiert zu entwickeln, zu testen und auszurollen. In (Abb. 3) ist diese Art der Arbeitsweise grafisch dargestellt. Anstelle eine Vielzahl von virtuellen Maschinen für das Deployment dieses Projektes zur Verfügung zu stellen, wurde AWS und Infrastructure-as-Code eingesetzt, um diese selbst zu provisionieren. Dadurch hatte das Entwicklerteam sowohl die Entwicklung, als auch den IT-Betrieb der Plattform in der eigenen Hand. Dies resultierte insbesondere aus  einer deutlichen Beschleunigung der Produktivität und der Auslieferung neuer Releases dieser Plattform. Beispielsweise war das Entwicklerteam durch die Erweiterung des bestehenden Codes direkt in der Lage, Änderungen wie Port-Freischaltungen im Load-Balancer oder das Skalierungsverhalten der Applikationen einzustellen und dadurch automatisiert ein Deployment auf die Entwicklungs-, Test- und letztendlich Produktivumgebung zu bewirken.

 

DevSecOps

Beim Thema DevOps sollte der Security-Aspekt ebenso stark berücksichtigt werden wie die Umsetzung der Container-Registry und die Implementierung von Continuous-Integration und Delivery-Pipelines für die Verbesserung der Entwicklungsprozesse aller Applikationen, d.h. man zielte auf die logisch zu Ende gedachte Idee von DevOps: DevSecOps. Konkret wurden Sicherheitsaspekte der Applikationen in den Entwicklungsprozess integriert, wodurch den Entwicklerteams direktes Feedback gegeben wurde. Im Zusammenhang mit Docker ging es nicht mehr nur um das Verhindern von Sicherheitsschwachstellen innerhalb des Sourcecodes, das mit unterschiedlichen Tools wie beispielsweise dem OWASP-Dependency-Check für Node.js ermöglicht werden kann. Es sollten Sicherheitsschwachstellen innerhalb des Docker-Containers schon während des Entwicklungsprozesses erkannt und beseitigt werden. Insbesondere letzteres wird in den meisten Fällen vernachlässigt. Laut der Studie „A Study of Security Vulnerabilities on Docker Hub“ aus dem Jahre 2017 wurden in über 350.000 Images im Durchschnitt 180 Sicherheitsschwachstellen gefunden[4]. Dies lag vor allem daran, dass die Images die Sicherheitsschwachstellen ihrer Parent-Images erbten und diese auch sehr selten aktualisiert wurden. Das Java 8 Base-Image weist zum Beispiel über 80 High-Level Sicherheitsschwachstellen der National-Vulnerability-Database auf. Um nun diese Sicherheitsschwachstellen frühzeitig zu erkennen und verhindern zu können, sollte zusätzlich zur Container-Registry auch CoreOS-Clair als Image-Security-Scanner zur Verfügung gestellt und in den CI/CD-Prozess integriert werden.

 

Fazit aus dieser Transition

Die Vorteile, die der Einsatz einer Cloud-Plattform in Kombination mit der Container-Technologie mit sich bringt, sind schon lange kein Geheimnis mehr. Allerdings muss hierbei beachtet werden, dass sich die bisher bekannten Prozesse an diesem neuen Ansatz anpassen müssen, um diese wirklich leben zu können. Auch die neuen Herausforderungen dürfen hier nicht außer Acht gelassen werden. Insbesondere dadurch rücken Security-Aspekte deutlich mehr in den Vordergrund und müssen in den Continuous-Delivery-Prozess integriert werden.

 

Schlusspfiff

Aus den drei Erfahrungsberichten erkennt man, dass das Thema DevOps je nach Situation einen anderen Schwerpunkt setzt. Ist man konfrontiert mit einem Transitionsprozess oder liegt eine heterogene Systemlandschaft vor, so sind Organisation, Kommunikation und die Form des Wissensaustausches das Hauptthema, gefolgt von technologischen Hilfswerkzeugen. Gilt andererseits eine derart hohe Anforderung an die Applikationen (z.B. Skalierbarkeit), die nur mittels Cloud-Lösungen wirtschaftlich realisiert werden kann, so rücken plötzlich die technologischen Werkzeuge in den Vordergrund (z.B. Terraform, ECS oder Kubernetes), gepaart mit dem Wissen, wie diese zu nutzen sind. Man baut hier bereits auf einem Konsens auf, wie DevOps zu funktionieren hat. Ein weiterer Schlusspunkt ist, dass oft erst der DevOps-Transitionsprozess offenlegt, welche manuellen, repetitiven Schritte es überhaupt gibt. Dass man anschließend die Verbesserungen und den alten Stand dokumentiert, ist wichtig, um später ein Bewusstsein für die Veränderungen zu erhalten und somit den Mehrwert der Transition im Projekt zu verankern. Außerdem darf man bei diesem Prozess nicht übersehen, dass durch die Verschiebung der Verantwortlichkeiten das Thema Security noch strenger in den Mittelpunkt der Entwicklung rückt und, dass man bei DevOps eigentlich DevSecOps im Blick haben sollte.

 

Matthias Engelke arbeitet seit Anfang 2017 bei der Pentasys. Als großer Befürworter von DevOps arbeitet er an verschiedenen Themen wie Infrastructure as Code, Automatisierung, Continuous Integration und Continuous Delivery. Er interessiert sich insbesondere für CAAS-Systeme wie Kubernetes und OpenShift und fühlt sich in der Cloud zuhause.

Christopher Hensel ist seit 2016 als Software-Entwickler bei der PENTASYS AG in agilen Projekten tätig. Neben der Entwicklung von Webanwendungen mit Java und Spring gilt sein Interesse dem Clean Code und der Automatisiserung im Rahmen von CI/CD.

Dr. Florian Zierer arbeitet seit 2016 bei der PENTASYS AG. Seine Schwerpunkte liegen in den Bereichen Continuous Integration und Automatisierung sowie in der Programmierung mit Java im Bereich Spark/Hadoop. Er interessiert sich besonders für die Qualitätssicherung in agilen Projekten und die Transition von klassischen Systemlandschaften hin zu einer DevOps-Kultur.

 

Quellen:

[1] https://java-pro.de/skills-tools-mindset

[2] Siehe auch Gesetz von Convey (https://de.wikipedia.org/wiki/Gesetz_von_Conway)

[3] https://web.devopstopologies.com

[4] Shu, Rui & Gu, Xiaohui & Enck, William. (2017). A Study of Security Vulnerabilities on Docker Hub

Bilder von Florian Zierer, PENTASYS AG

 

Victoria Krautter


Leave a Reply