Pulumi verspricht Multicloud-Orchestrierung in nahezu jeder beliebigen Programmiersprache. Damit treffen seine Entwickler einen Nerv: Vielerorts wünschen Unternehmen sich, Ressourcen etwa bei den Hyperscalern direkt aus Anwendungscode heraus zu starten, ohne jedoch dafür die jeweiligen deklarativen Definitionssprachen der jeweiligen Anbieter zu erlernen. Wir stellen das Werkzeug vor, grenzen es zu Terraform ab und beschreiben, wie es funktioniert.
Der Gang in die Cloud ist, obgleich vielerorts ausdrücklich erwünscht, wenn nicht sogar herbeigesehnt, kein leichter. Das hat primär gar nicht etwas mit den einzelnen Hyperscalern zu tun, sondern eher mit der Anzahl und Menge der grundsätzlich verfügbaren Zielplattformen. Klar: Die Hyperscaler, also AWS, Azure und Google haben die meisten Firmen auf der Rechnung, wenn sie sich ernsthaft mit der Cloud befassen.
Alternativ stehen aber auch andere Wege in die Wolke zur Verfügung, etwa in Form einer privaten IaaS-Plattform, die beispielsweise auf OpenStack fußt. Das Problem: Die Entscheidung für eine dieser Plattformen bedeutet in den meisten Fällen implizit auch, sich für ein bestimmtes Infrastructure-as-Code-Tool zu entscheiden und mithin für spezielle Wege der Automation und auch der Orchestrierung.
Zur Erinnerung: Ein zentraler Vorteil von Diensten in der Cloud ist, dass sie Infrastruktur in virtueller Form zur Verfügung stellen in ebenjenem Rahmen, den der Kunde gerade benötigt und bezahlen möchte. Das Thema Virtualisierung spielt dabei eine große Rolle: Gerade weil die Ressourcen in der Cloud meist virtuell sind, ist es leicht, ihr automatisiertes und orchestriertes Deployment zentral zu betreiben und zu garantieren.
Der Gang in die Cloud ist, obgleich vielerorts ausdrücklich erwünscht, wenn nicht sogar herbeigesehnt, kein leichter. Das hat primär gar nicht etwas mit den einzelnen Hyperscalern zu tun, sondern eher mit der Anzahl und Menge der grundsätzlich verfügbaren Zielplattformen. Klar: Die Hyperscaler, also AWS, Azure und Google haben die meisten Firmen auf der Rechnung, wenn sie sich ernsthaft mit der Cloud befassen.
Alternativ stehen aber auch andere Wege in die Wolke zur Verfügung, etwa in Form einer privaten IaaS-Plattform, die beispielsweise auf OpenStack fußt. Das Problem: Die Entscheidung für eine dieser Plattformen bedeutet in den meisten Fällen implizit auch, sich für ein bestimmtes Infrastructure-as-Code-Tool zu entscheiden und mithin für spezielle Wege der Automation und auch der Orchestrierung.
Zur Erinnerung: Ein zentraler Vorteil von Diensten in der Cloud ist, dass sie Infrastruktur in virtueller Form zur Verfügung stellen in ebenjenem Rahmen, den der Kunde gerade benötigt und bezahlen möchte. Das Thema Virtualisierung spielt dabei eine große Rolle: Gerade weil die Ressourcen in der Cloud meist virtuell sind, ist es leicht, ihr automatisiertes und orchestriertes Deployment zentral zu betreiben und zu garantieren.
Längst erfreuen sich Dienste wie AWS CloudFormation oder Hilfswerkzeuge wie Terraform größter Beliebtheit. Denn sie bieten die Möglichkeit, ganze virtuelle Umgebungen in Template-Form zu beschreiben, dieses Template dann einfach an den dafür zuständigen Dienst der Zielplattform zu übergeben und dieser kümmert sich wie von Zauberhand um den Rest. Ohne weiteres Zutun des Admins oder Entwicklers entsteht die virtuelle Welt genau so, wie sie zuvor im Template fixiert beschrieben war. Klingt vertraut, denken Sie sich an dieser Stelle vielleicht, wenn Sie schon mal mit Terraform oder einem vergleichbaren Werkzeug gearbeitet haben.
Hyperscaler mit eigener Syntax
Gegen Terraform spricht zunächst nichts. Im Grunde ist die Idee dahinter nämlich eine ähnliche wie bei Pulumi, zumindest was die Grundlagen betrifft. Terraform versucht, dasselbe Problem zu lösen: Dass Administratoren, die Dienste auf mehreren Zielplattformen jonglieren, nämlich auch deren jeweils eigene Syntax in Sachen Orchestrierung erlernen müssen. Wer etwa schon einmal mit CloudFormation von AWS gearbeitet hat, kennt das: Die genutzte Syntax zur Deklaration der benötigten Ressourcen ist angebotsspezifisch; sie kommt praktisch nirgendwo sonst auf der Welt zum Einsatz.
Dasselbe gilt für die jeweiligen Gegenstücke bei Azure oder Google Cloud. Frei nach dem Motto "Das Schöne an Standards ist, dass es so viele davon gibt" kochen gerade die Hyperscaler in Sachen Orchestrierung ihr ganz eigenes Süppchen. Und freilich nicht aus Versehen: Natürlich wissen Amazon & Co., dass sie es den Kunden der eigenen Plattform extrem schwer machen, so zu Angeboten der Konkurrenz zu wechseln. Gerade das ist der Grund dafür, dass Migrationen zwischen den großen Plattformen im Alltag so selten stattfinden.
Wer seine gesamte Toolchain und auch seine Orchestrierung einmal an AWS, Azure oder GCP angepasst hat, muss viel Aufwand betreiben, um dieselbe Konfiguration bei einem anderen Hyperscaler in identischer Weise zum Laufen zu bringen. Und dabei sind Situationen, in denen die Zielplattform kein Hyperscaler ist, sondern etwa eine private OpenStack-Umgebung, noch gar nicht eingerechnet.
Der in OpenStack für Orchestrierung zuständige Dienst nutzt zwar eine Syntax, die lose an CloudFormation angelehnt ist, kompatibel ist sie damit aber nicht. Kommt dann noch ein Kubernetes ins Spiel, das ja im Grunde ein einziger großer Orchestrierer ist und wieder eine eigene Syntax hat, ist das Chaos perfekt.
Abgrenzung zu Terraform
Terraform setzt an dieser Stelle an und bietet eine eigene deklarative Syntax an, die es im Hintergrund an die Anforderungen der jeweiligen Zielplattform übersetzt. Der Administrator schreibt hier also auch ein Template für Infrastructure-as-Code, nutzt dabei aber die generische Terraform-Notation (Bild 1). Aus "Ich brauche eine EC2-Instanz" wird entsprechend "Ich brauche eine virtuelle Maschine" und je nach gewählter Zielplattform kümmert Terraform sich darum, die nötigen Ressourcen dort zu starten. Das ist durchaus ein Schritt in die richtige Richtung, krankt aber an mehreren Stellen.
Bild 1: Terraform eignet sich gut für Cloudorchestrierung, erzwingt aber das Erlerneneiner eigenen Syntax, nämlich jener von Terraform.
Einerseits bietet Terraform nämlich kein umfassendes State Management der von ihm selbst angelegten Ressourcen. Ein einmal in Betrieb genommener Dienst lässt sich aus Terraform heraus also nur mühselig umkonfigurieren oder hinsichtlich seines Status überwachen. Dabei spielt eine Rolle, dass Terraform selbst nahezu kein Monitoring, Alerting oder Trending implementiert und die ausgerollten Ressourcen auch nicht detailliert überwacht oder regelmäßig untersucht. Der größere Pferdefuß ist aber die Tatsache, dass Terraform auch wieder eine eigene Syntax für seine deklarativen Definitionen von Ressourcen nutzt, die künftige Nutzer erst einmal erlernen müssen.
Auf Basis einer Sprache, die weder YAML noch JSON ist, legt der Anwender in Terraform nämlich fest, welche Dienste er benötigt. Und mit der Abstraktion ist es oft auch nicht ganz so weit her, wie der Hersteller verspricht. Wer nämlich Dienste in der Zielplattform benötigt, die so überhaupt nur dort zur Verfügung stehen – und das betrifft von den sehr grundsätzlichen Diensten abgesehen beinahe alle, fertigt auch in Terraform-Dateien letztlich CloudFormation-Instruktionen im Deckmäntelchen an. Mit deren Portabilität auf andere Plattformen ist es lange nicht so weit her, wie Nutzer annehmen oder glauben möchten.
Pulumi erlaubt beliebigen Code
Genau hier kommt Pulumi ins Spiel. Der vorrangig online gehostete Dienst verspricht Anwendern nicht weniger als das Definieren von Infrastructure-as-Code-Instruktionen direkt aus laufendem Programmcode heraus. Hier beschäftigt sich der User, der IaC-Dienste nutzen möchte, also nicht mit der spezifischen Syntax von Terraform, sondern nutzt seine gewohnte Programmiersprache, um Ereignisse direkt in der Zielplattform auszulösen.
Dabei macht es keinen Unterschied, ob er seine Anweisungen für das Starten von Ressourcen in der Cloud in C, Python oder JavaScript definiert – solange Pulumi für die verwendete Sprache Bindings hat, lassen sie sich auch direkt aus dem Code eines Programms heraus nutzen.
Der zuvor beschriebene Start einer virtuellen Instanz in AWS etwa ist aus einem Stück Python-Code in Pulumi leicht zu bewerkstelligen. Dazu bindet der Entwickler in seinem Programm unmittelbar die entsprechende Pulumi-Python-Klasse ein und legt seine Ressourcen in der Cloud dann durch Pulumi hindurch über Funktionsaufrufe an. Diese unterscheiden sich dabei nicht von Standard-Funktionsaufrufen in Python. Iac-Code und der eigentliche Payload-Code einer Anwendung werden eins.
Obendrein bietet Pulumi umfassendes State-Handling inklusive der Anbindung an CI/CD-Pipelines. Wer also seinen Programmcode in Git verwaltet und eine Änderung in das Quelltextverzeichnis einspielt, kann über Pipelines dafür sorgen, dass Pulumi die entsprechenden Dienste in der Cloud automatisch aktualisiert. Ebenso bietet das Werkzeug seit einiger Zeit eine "Insights"-Funktion. Die ermöglicht das Sezieren der eigenen genutzten Clouddienste direkt auf Orchestrierungsebene und hilft so zu vermeiden, dass eine versehentlich nicht gelöschte Testinstanz die Rechnung des jeweiligen Monats in astronomische Höhen katapultiert.
Erste Schritte
Wie bereits erwähnt ist Pulumi vor allem ein gehosteter Onlinedienst. Der Anbieter offeriert zwar die Option, eine Installation auch lokal zu betreiben. Das Feature steht aber nur im Rahmen des größten Supportvertrags zur Verfügung, der "Business Critical"-Edition. Wohlweislich gibt der Hersteller für diese online erst gar keine Preise an, schon die "Enterprise"-Edition schlägt jedoch mit monatlich etwas über einem Dollar pro verwalteter Ressource zu Buche. Weil ein Stack für eine gesamte virtuelle Plattform gern mal 100 Ressourcen und mehr enthält, kommt hier also ein bisschen was zusammen.
Im Gegenzug erhalten gerade Enterprise-Kunden bei Pulumi Business Critical aber auch Funktionen wie SAML/SSO, Audit-Logs, Policy- und Compliance-Garantien und diverse andere Goodies als Dreingabe. Für erste Gehversuche mit der Plattform werden die meisten Unternehmen aber eher nicht bereit sein, gleich einen entsprechenden Rahmenvertrag mit dem Hersteller zu schließen, sodass nur die Nutzung des Anbieter-gehosteten Pulumi Cloud als Option übrig bleibt.
Bei dieser klappt der Einstieg aber relativ schnell. Zunächst registrieren Sie sich unter [1]. Der Prozess ist so gestaffelt, dass Sie sich im Rahmen des Setups idealerweise gleich auch eine lokale Instanz vom Pulumi-CLI anlegen, die per Token Zugriff auf den eigenen Account erhält. Der Aufruf von pulumi auf der Kommandozeile sorgt im Anschluss dafür, dass sich das Werkzeug weitgehend von dort aus steuern lässt.
Ganz ohne eigene Konfiguration oder Metadaten kommt auch Pulumi nicht aus: Zumindest eine Beschreibung des Projekts in Pulumi, zu dem ein bestimmtes Stück Code gehört, muss der Autor der jeweiligen IaC-Lösung beisteuern.
Begrifflichkeiten verstehen
Es schadet an dieser Stelle nicht, sich mit den Begrifflichkeiten in Pulumi zu befassen. Denn die fliegen einem durchgehend um die Ohren: "Programm", "Projekt" und "Stack" sind die drei wichtigsten der kontinuierlich genutzten Begriffe. Jeder davon hat eine konkrete Bedeutung. Noch am ehesten erschließt sich die des Programms: Hierunter subsumiert Pulumi allen Code, der letztlich zur Ausführung innerhalb eines Aufrufs von "pulumi" führt und dafür sorgt, dass in der gewählten Zielplattform Dienste entstehen. Entwickelt also der Administrator wie beschrieben eine IaC-Anweisung im Kontext eines Python-Skripts, gehört diese ebenso zum Programm wie der eigentliche Programmcode selbst.
Ein Programm ist bei seiner Ausführung stets einem Projekt zugeordnet: Das Projekt beschreibt einerseits die logische Einteilung innerhalb von Pulumi und andererseits die Zuweisung eines abgetrennten Bereichs im Pulumi-Interface zu einem definierten Programm. Der Stack schließlich meint eine konkrete, ausgerollte Instanz eines Programms im Kontext eines Projekts, die läuft und beispielsweise mittels "Pulumi Insights" zu überwachen ist.
Wichtig ist vor allem das Verständnis, dass Pulumi nicht die eigentlichen Funktionen der Zielplattformen abstrahiert, sondern vor allem die Möglichkeit bietet, auf diese direkt aus Core heraus zuzugreifen, statt durch eine deklarative Syntax hindurch. Aus Sicht eines Entwicklers ist es also ein wichtiger Unterschied, ob er einen Webserver in einer AWS-Instanz oder in einer virtuellen Instanz in OpenStack aufrufen möchte – und auch die zu Pulumi gehörenden Funktionen, die dafür nötig sind, unterscheiden sich deutlich voneinander.
So gibt es beispielsweise für das Erstellen von Ressourcen in den verschiedenen Hyperscaler-Clouds ebenso eigene Funktionen wie beispielsweise für Kubernetes oder OpenStack.
Pulumi in der Praxis
Wie das in der Praxis aussehen kann, verdeutlicht ein Beispiel mit AWS-Bezug direkt von den Entwicklern sehr anschaulich. Das nginx-Beispiel in Go [2] vollführt mehrere Arbeitsschritte (Bild 2). Zunächst enthält es in Form der Datei "main.go" einen zugegebenermaßen sehr simplen Webserver, der eine statische Website ausliefert. Die Dateien "go.mod" und "go.sum" sind Go-spezifisch, sie gehören also zu einem Pulumi-Programm ebenso wie zu jedem anderen in Go verfassten Programm auch. "Pulumi.yaml" enthält die bereits erwähnten Metadaten des Programms, die später etwa im Web-GUI auftauchen.
Bild 2: Pulumi selbst stellt etliche Beispiele für die Nutzung der eigenen Plattform zur Verfügung, etwa diesen in Go verfassten Webserver, der nativ in AWS läuft.
Um genauer zu verstehen, wie dieses Beispiel funktioniert, hilft eine tiefere Analyse von "main.go". Zunächst bindet dieses die Go-Bindings für Pulumis AWS-Integration ein. Dann erstellt es über die Funktion "ec2.NewSecurityGroup" zunächst eine Security Group in AWS, die eingehenden Datenverkehr auf Port 80 erlaubt. Die eigentliche Arbeit erledigt dann die Funktion "ec2.NewInstance": Die sorgt für das Anlegen einer EC2-Instanz mit öffentlicher IP-Adresse. Pulumi macht sich hier zunutze, dass viele Dinge in AWS mittlerweile im Hintergrund automatisch geschehen.
Wer etwa eine EC2-Instanz anlegt und diese mit einer öffentlichen IP-Adresse versorgt, wie es der Aufruf von "ec2.NewInstance" in "main.go" tut, sorgt implizit auch dafür, dass eine Virtual Private Cloud entsteht, also ein privates Netz innerhalb des AWS-Accounts des ausführenden Nutzers. Weil der Aufruf zudem die zuvor angelegte Security Group referenziert, sorgt er automatisch dafür, dass Zugriff auf Port 80 der Instanz im Anschluss von außen möglich ist – die Default Security Group in AWS unterbindet nämlich eingehenden Traffic grundsätzlich.
Mehr ist für ein fertiges Pulumi-Programm nicht nötig: Liegen die beschriebenen Dateien aus dem Beispiel in einem Ordner, der sich natürlich mittels "git" verwalten lässt, hinterlegen Sie nach der Installation von "pulumi" als CLI-Client auf Ihrem System bloß noch die AWS-Zugangsdaten. Das kann über die CLI-Umgebungsvariablen AWS_ACCESS_ KEY_ID, AWS_SECRET_ACCESS_KEY sowie AWS_REGION geschehen und lässt sich auch mittels "aws configure" einrichten. Dieses ist zuvor händisch zu installieren. Danach führt der Aufruf von pulumi up im Ordner des Beispiels dafür, dass die gewünschten Ressourcen automatisch angelegt werden.
Durchaus bemerkenswert: Noch ohne sich mit den genauen Details einer Zielplattform zu beschäftigen, sorgen die Pulumi-Beispiele dafür, dass Nutzer flott an die gewünschten Ressourcen auf der jeweiligen Zielplattform gelangen. Noch besser: Das Werkzeug stellt nicht nur die jeweiligen Bindings für die diversen Skript- und Programmiersprachen zur Verfügung, sondern bietet für diese auch eine exzellente und sehr umfangreiche Dokumentation an. Wer beispielsweise ein erfahrener Python-Entwickler ist, wird auf Grundlage der Dokumentation [3] schnell in der Lage sein, Pulumi-Befehle in seine Programme zu integrieren.
Assistenten helfen
Noch leichter wird der Pulumi-Einstieg durch die diversen Assistenten, die Pulumi selbst im Webinterface anbietet (Bild 3). Wer nicht mit einem leeren Quelltext-Verzeichnis anfangen will, wählt stattdessen im Onlineassistenten zunächst die Zielplattform aus und dann die Programmiersprache, die dafür zum Einsatz kommen soll. Pulumi erstellt dann ein fertiges Verzeichnis mit den Grunddateien aus dem Beispiel. Weil sich Pulumi über eine eigene App sinnvoll an GitHub anbinden lässt, kann die Integration mit diesem ebenfalls direkt aus dem GUI heraus erfolgen.
Bild 3: Über die Integrationsmaske des Pulumi-GUIs ist es möglich, neue Projekte anzulegen, die bei Anbindung von GitHub direkt in einem Git-Verzeichnis liegen und per CLI oder GUI auszurollen sind.
Dazu genügt es, den eigenen GitHub-Account einmalig mit Pulumi zu verbinden. Im Anschluss laden Sie eine lokale Kopie des gesamten Git-Verzeichnisses herunter, integrieren Ihren eigenen Code in dieses, checken die Änderungen wieder ein, laden sie auf GitHub hoch und rufen sie unmittelbar mittels Pulumi-CLI lokal auf. Wer das CLI nicht nutzen möchte, hat obendrein die Option, alle Befehle aus dem Web-GUI heraus aufzurufen.
Kubernetes-Support an Bord
Besonders in jüngerer Vergangenheit haben die Pulumi-Entwickler die Kubernetes-Integration ihres Produktes ganz massiv ausgebaut. Logisch: Kubernetes ist gerade das It-Piece der modernen IT-Infrastruktur-Community und kommt landauf und landab vielfach zum Einsatz. Eine Herausforderung ist dabei, dass die Kubernetes-API zwar diverse Standard-Ressourcentypen kennt, jedoch externe Anwendungen über "Custom Resource Definitions" (CRDs) jederzeit eigene API-Definitionen hinterlegen können.
Pulumi geht das Problem auf mehreren Ebenen an: Für alle zur Standard-API gehörenden Komponenten bietet es ebenso eigene Funktionen für diverse Skript- und Programmiersprachen an wie eine generische Funktion zum Erstellen von Ressourcen, deren Ursprung in CRDs liegt. Daraus ergibt sich eine weitgehend vollständige Möglichkeit zur Nutzung von Ressourcen in Kubernetes-Clustern direkt aus Pulumi heraus.
Policies sorgen für Kontrolle
Nicht unerwähnt bleiben soll an dieser Stelle, dass Pulumi nicht nur die Möglichkeit bietet, die diversen Cloudfunktionen zu nutzen, sondern dass es über eine eigene Policy-Umgebung gleich auch wieder die Option einräumt, die Nutzung einzuschränken – die Geschichten, die im Netz über auf AWS vergessene Ressourcen kursieren, die im Folgemonat zu horrenden Rechnungen führten, sind keine Hirngespinste.
Aus Unternehmenssicht kann das katastrophale Folgen haben: Wenn so ein Lapsus innerhalb kurzer Zeit vielen Angestellten eines Unternehmens passiert, die durch Pulumi hindurch Zugriff auf AWS oder einen anderen Clouddienst haben, kann das schlimmstenfalls zur finanziellen Schieflage einer ganzen Organisation führen. AWS hat eben für diesen Fall selbst Guardrails implementiert. Und Pulumi fügt in Form seiner Policy Engines eine weitere Schutzebene hinzu.
Konkret funktioniert das so: Mittels der CrossGuard-Funktion lassen sich auf der Pulumi-Ebene verschiedene Policies definieren, die im Anschluss auf ausgerollte Stacks anwendbar sind. Verstößt ein Stack gegen eine festgelegte Regel, schlägt Pulumi automatisch Alarm und gibt dem zuständigen Admin die Möglichkeit, den Stack entweder komplett stillzulegen oder in seinen Parametern anzupassen, um die Policy-Verletzung zu beseitigen.
Parameter, die als Regeln für die Policy dienen können, unterstützt das Tool dabei vielfältig: So lassen sich etwa Regeln auf Grundlage von Deployment-Größen, genutzten Setups, Datenverkehr oder anderen Eigenschaften definieren.
Verzahnung mit Clouddiensten
Neben der bereits erwähnten GitHub-Integration verfügt Pulumi zusätzlich über eine "ESC"-Funktion (Bild 4), die das Werkzeug an verschiedene Clouddienste der Hyperscaler ankoppelt. Wobei hier nicht nur die Hyperscaler zum Handkuss kommen, sondern etwa auch Dienste wie Ansible Vault nutzbar sind. Die Idee ist, verschiedene externe Dienste wie eben Vault oder Amazon S3 als Datenspeicher unmittelbar in ein Pulumi-Deployment zu integrieren, sodass sie in aus Pulumi heraus gestarteten Stacks unmittelbar nutzbar werden.
Bild 4: Pulumi ESC bietet Secret-Management und die Möglichkeit, aus angeschlossenenPlattformen Daten unmittelbar in Pulumi zu verwenden.
So kann Pulumi beispielsweise Zugangsdaten aus diversen Hyperscaler-Diensten ebenso beziehen wie aus 1Password oder der nativen Pulumi-Stacks-Schnittstelle des Anbieters selbst. Obendrein lässt sich das Werkzeug über die ESC-Funktion auch als externer Dienst in andere Deployments einbinden, etwa in ein externes, außerhalb von Pulumi betriebenes Kubernetes. So sorgt die Plattform bei einigen Funktionen für eine echte Zwei-Wege-Integration, was im Alltag ausgesprochen praktisch ist.
Fazit
Pulumi erweitert Infrastructure-as-Code um eine zusätzliche Dimension und erlaubt es Entwicklern, eine bereits bekannte Programmier- oder Skriptsprache samt ihrer bekannten Syntax zu verwenden, um Ressourcen in der Cloud zu betreiben. Dadurch wird Orchestrierung möglich, für deren Nutzung ansonsten das Studium deklarativer Syntaxsprachen wie jener von Terraform nötig wäre.
Ein Haken an der Sache ist allerdings, dass Pulumi vorrangig als Onlinedienst konzipiert ist, der selbst in der Cloud gehostet ist. Der Betrieb im eigenen Rechenzentrum ist zwar möglich, bedingt aber den Kauf der "Business Critical"-Lizenz, deren Preise der Anbieter öffentlich nicht angibt. Dennoch gilt: Wer auf der Suche nach Cloud-Orchestrierung ist und möglichst schnell Ergebnisse sehen will, sollte Pulumi einer genaueren Evaluation unterziehen.