Infrastructure as Code

Keine Kommentare

Infrastructure as Code (IaC) ist ein Paradigma in der Softwaretechnik, gemäß dem nicht nur Software, sondern auch die gesamte für die Ausführung benötigte Infrastruktur (Compute-, Storage- und Netzwerkressourcen) in Computersprachen beschrieben wird. Diese Beschreibungen (in diesem Artikel werden sie als Templates, manchmal auch als Blueprints bezeichnet) werden von Maschinen interpretiert, sodass die darin definierten Ressourcen automatisiert bereitgestellt, verwaltet und freigegeben werden können.

In diesem Artikel werden exemplarisch drei IaC-Sprachen (CloudFormation, Troposphere und HashiCorp Configuration Language, kurz HCL) untersucht und miteinander verglichen. Dabei wird das Augenmerk auf die Eigenschaften der Sprachen an sich gelegt und nicht auf die darunter liegende Technologie des Infrastructure Providers.

Die Kernidee ist, dass diese Sprachen als unabhängig von der tatsächlichen Realisierung durch den Infrastructure Provider (z.B. Amazon Web Services (AWS) oder Google Compute Engine (GCE)) betrachtet werden können. Durch diese Abkopplung lässt sich die Infrastruktur auf einer höheren Abstraktionsebene formal beschreiben.

Kontext

Dynamic Infrastructure Provider stellen Dienste für die Bereitstellung von meist virtualisierten Ressourcen (Compute, Storage, Network) zur Verfügung. Dieses Modell wird als Infrastructure as a Service (IaaS) bezeichnet. Diese Services werden über eine Web-API automatisiert aufgerufen und bilden in ihrer Gesamtheit die unterste (operationale) Schicht, auf der weitere Services für die Orchestrierung aufbauen. Ein Beispiel für eine solche Operation ist “Starte eine virtuelle Maschine mit 4GB Arbeitsspeicher, auf der Ubuntu läuft”. Der Infrastructure Provider ist somit vergleichbar mit einem Betriebssystemkern, der Funktionen bereitstellt, über die Ressourcen wie Speicher und Netzwerk-Ports reserviert und freigegeben werden können.

Auf der nächsthöheren Ebene befinden sich Softwarekomponenten, die die Dienste des Infrastructure Provider nutzen, und ihrerseits Dienste für die Orchestrierung der Infrastruktur anbieten. Diese interpretieren Templates, die in höheren (meist deklarativen) Sprachen verfasst sind, und setzen die darin enthaltenen Definitionen in konkrete Service-Aufrufe des Infrastructure Providers um. Drei unterschiedliche Sprachen (CloudFormation, Troposphere und HCL), mit denen diese Tools arbeiten, werden in diesem Blogartikel miteinander verglichen.

Die Templates können nicht nur direkt interpretiert, sondern auch in andere Sprachen übersetzt werden. Diese mehrfache Schichtung ermöglicht eine bessere Trennung von Verantwortlichkeiten und die Entwicklung von höheren Computersprachen für die Infrastruktur-Orchestrierung. Diese Idee ist natürlich nicht neu, wird aber im Kontext von Infrastructure as Code erst durch das Angebot von IaaS Providern praktikabel.

Methode

Um die Sprachen systematisch zu untersuchen, werden als erstes folgende Fragen beantwortet:

  • welche atomaren Bausteine gibt es in der Sprache (Vokabular)?
  • welche Mittel der Komposition gibt es?
  • welche Mittel der Abstraktion gibt es?

Durch die Beantwortung dieser Fragen werden bereits die wesentlichen Eigenschaften der Sprachen und ihre Unterschiede erfasst. Neben diesen grundsätzlichen Fragen werden weitere Eigenschaften betrachtet:

  • Modularisierung
  • Polymorphismus
  • Tool-Unterstützung

Diese Eigenschaften bestimmen, wie die Sprachen in der Praxis eingesetzt werden. Zusätzlich werden folgende “nichtfunktionale” Aspekte untersucht:

  • Übertragbarkeit
  • Wartbarkeit

Diese Eigenschaften spielen eine wichtige Rolle, weil sie Projektrisiken darstellen. Im folgenden Abschnitt werden nun die Sprachen kurz vorgestellt.

CloudFormation

CloudFormation ist ein Service von AWS und eine Sprache zur Beschreibung von Templates. Sie hat eine JSON bzw. YAML-basierende Syntax. Ein grafischer Editor und der Interpreter sind über die AWS-Konsole erreichbar. Die über AWS-Konsole instanziierten Templates werden als Stacks bezeichnet.

Troposphere

Troposphere ist eine Python-Bibliothek, mit der CloudFormation-Templates aus einem Objektmodell generiert werden können. Sie beinhaltet Klassen für diverse Ressourcentypen, die von AWS angeboten werden. Die Beschreibung der Infrastruktur erfolgt durch die Instanziierung von entsprechenden Klassen und Herstellung von Verbindungen zwischen ihnen. Ein so ersteller Objektgraph wird dann in Text (CloudFormation/JSON) gerendert. Damit ist Troposphere eine nach CloudFormation übersetzte Sprache.

HCL (Terraform)

Terraform ist ein Tool, das Templates verarbeitet, die in HashiCorp Configuration Language (HCL) verfasst sind. Beim Interpretieren der Terraform-Templates kommuniziert es über Web-Service-Aufrufe direkt mit den Infrastructure Providern, um die Bereitstellung, Änderung und Freigabe von Ressourcen durchzuführen. Darüber hinaus erstellt Terraform sogenannte State Files, in denen der aktuelle Zustand der Ressourcen gespeichert wird. Damit lassen sich inkrementelle Änderungen an der Infrastruktur vornehmen: Terraform ermittelt dazu zuerst ein Delta, das in die Service-Aufrufe umgesetzt wird, um die Infrastruktur zu einem neuen Zustand zu “konvergieren”.

Analyse

Bausteine

In allen drei Sprachen bilden Ressourcen die Basis für die Spezifikation der Infrastruktur. Grundsätzlich lassen sich die Ressourcen bei allen Sprachen in drei Kategorien einteilen: Compute, Storage und Network. Die konkrete Syntax für die Definition von Ressourcen ist aber unterschiedlich.

In CloudFormation werden Ressourcen als JSON- bzw. YAML-Elemente definiert. So wird zum Beispiel eine Maschine in CloudFormation definiert:

MyEC2Instance: 
  Type: "AWS::EC2::Instance"
  Properties: 
    ImageId: "ami-79fd7eee"
    KeyName: "testkey"
    BlockDeviceMappings: 
      - DeviceName: "/dev/sdm"
        Ebs: 
          VolumeType: "io1"
          Iops: "200"
          DeleteOnTermination: "false"
          VolumeSize: "20"
      - DeviceName: "/dev/sdk"
        NoDevice: {}

In Troposphere werden Ressourcenklassen instanziiert, die zu einem Template hinzugefügt werden:

template = Tempate()
 
instance = ec2.Instance(
    "Ec2Instance",
    ImageId = FindInMap("RegionMap", Ref("AWS::Region"), "AMI"),
    InstanceType = "t1.micro",
    KeyName = Ref(keyname_param),
    SecurityGroups = ["default"],
    UserData = Base64("80")
)
 
template.add_resource(instance)
 
print(template.to_json())

In HCL werden Ressourcen mit dem speziellen “resource” Element definiert. Zum Beispiel:

resource "aws_instance" "web" {
    ami = "${data.aws_ami.ubuntu.id}"
    instance_type = "t2.micro"
    tags {
        Name = "HelloWorld"
    }
}

Komposition

Die einzelnen Ressourcen können Abhängigkeiten zueinander haben und gruppiert werden. Dadurch lassen sich komplexere Systeme aus einfachen Bestandteilen aufbauen.

In CloudFormation müssen alle Ressourcen in einer einzelnen Datei definiert werden, da das Template im Wesentlichen aus einer Liste von JSON-Objekten besteht.

In Troposphere nimmt die Template-Klasse Ressourcenklassen auf. Das Template-Objekt ist somit ein Behälter für mehrere Ressourcen. Wenn alle Ressourcen und ihre Abhängigkeiten zueinander definiert und zu einem Template hinzugefügt worden sind, kann das Template gerendert werden.

In HCL können die Ressourcen ebenfalls beliebig oft in einer oder mehreren Dateien mit der Endung “.tf” definiert werden. Alle solche Dateien werden dann bei der Interpretation berücksichtigt. Zusätzlich gibt es die Möglichkeit, Module zu definieren, was im nächsten Abschnitt erläutert wird.

Abstraktion

Eines der wichtigsten Unterscheidungsmerkmale liegt in den Möglichkeiten der Abstraktion der jeweiligen Sprachen. Diese bestimmen zum großen Teil viele weitere Eigenschaften wie Wiederverwendbarkeit, Portierbarkeit, Wartbarkeit usw.

Die Möglichkeiten der Abstraktion in CloudFormation sind sehr begrenzt. Es können Parameter in den Templates definiert werden, die beim Instanziieren des Stacks mit Werten belegt werden. Darüber hinaus gibt es keine weitere Möglichkeiten. Ein CloudFormation-Template ist in diesem Sinne monolithisch.

In Troposphere sieht es anders aus. Dadurch, dass Troposphere eine interne DSL ist, erbt sie die Abstraktions-Mechanismen von ihrer Host-Sprache Python. Python-Skripte können bspw. auf mehrere Dateien aufgeteilt werden, zu Packages zusammengefasst werden, zur Laufzeit generiert werden, usw.

HCL hat ein eigenes Modularisierungskonzept. Module haben eine nach außen sichtbare Signatur und eine gekapselte Implementierung. Die Trennung der Signatur von der Implementierung ermöglicht zum Einen eine effektive Wiederverwendung, zum Anderen bringt es eine Reduktion von Komplexität mit sich, da die Erstellung von Terraform-Modulen eine Beschreibung der Infrastruktur auf einer höheren Abstraktionsebene ermöglicht. Komplexe Systeme lassen sich dadurch nach dem “Teile und Herrsche”-Prinzip aus einfachen Subsystemen (Modulen), die ihrerseits aus weiteren Modulen bestehen können, zusammensetzen.

Bewertung

Modularisierung

CloudFormation hat kein Modularisierungskonzept. Alle Ressourcen müssen in einer Template-Datei definiert werden, die im Wesentlichen eine flache Liste von JSON-Objekten beinhaltet.

Troposphere ist eine Python-Bibliothek, somit stehen alle Mittel von Python zur Verfügung, um Module zu bilden. Allerdings bedeutet es auch, dass der Entwickler verantwortlich ist für die Entscheidung, wie er die Modularisierung gestaltet (Pakete, Klassen, Funktionen usw.). Es bringt zwar Flexibilität, verlangt aber vom Entwickler Disziplin, weil er für die konsistente Umsetzung selber sorgen muss.

Die Möglichkeit, HCL-Templates auf mehrere Dateien aufzuteilen, und das Modularisierungskonzept von Terraform, das bereits im Kapitel über Abstraktion beschrieben wurde, eignen sich hervorragend zur modularen Strukturierung von Templates. Durch die explizite Definition von Modul-Inputs (Parameter) und Outputs lässt sich die Modul-Implementierung effektiv kapseln. Außerdem können Modul-Implementierungen ausgelagert und bei der Instanziierung zur Laufzeit aus externen Quellen (bspw. über HTTP) importiert werden. Auf diese Weise lassen sich ganze Modul-Bibliotheken erstellen.

In diesem Kontext wird unter Polymorphismus die Idee verstanden, dass die Implementierung eines Moduls oder einer Ressource (evtl. zur Laufzeit) ausgetauscht werden kann, ohne das einbindende Modul anpassen zu müssen.

Polymorphismus

Man kann dabei unterscheiden zwischen:

  • Austausch des Infrastructure Providers (Ressourcen-Implementierung)
  • Austausch der Modul-Implementierung

In diesem Abschnitt wird auf die Austauschbarkeit der Modul-Implementierung eingegangen. Die Austauschbarkeit des Infrastructure Providers wird weiter unten unter Übertragbarkeit (Portierbarkeit) betrachtet.

CloudFormation ermöglicht keinen Polymorphismus. Es können nur AWS-spezifische Ressourcen definiert werden und es gibt keine Module.

Da Troposphere eine interne DSL der Sprache Python ist, stehen alle Python-Mittel der objektorientierten und funktionalen Programmierung zur Verfügung. So können bspw. abstrakte Datentypen definiert werden, gegen die programmiert wird.

In Terraform kann grundsätzlich die Implementierung von Modulen ausgetauscht werden. Solange die Modulsignatur gleich bleibt, wird es keine Probleme geben. Allerdings ist es nicht möglich, in HCL Schnittstellen explizit zu definieren, die von einem Typ-Checker verwendet werden können, um eine Modul-Implementierung bzw. Instanziierung zu validieren. Es gibt auch eine Einschränkung, die es nicht erlaubt, die Modul-Implementierung zur Laufzeit auszuwählen. Dadurch wird die Parametrisierung von Terraform-Templates effektiv einschränkt.

Tools

Alle beschriebenen Sprachen haben eine textbasierte Syntax. Somit lassen sich die Templates mit jedem Texteditor bearbeiten und mit den gängigen Versionsverwaltungstools effizient verwalten. Um die Produktivität zu erhöhen, werden aber spezialisierte Tools benötigt.

CloudFormation bietet einen grafischen Editor in AWS an, der über Webbrowser erreichbar ist. Dieser stellt die Templates als Diagramme dar, die per Drag-and-Drop editiert werden können.

Beim Einsatz von Troposphere kann auf sämtliche Python-Entwicklungstools zugegriffen werden.

Für HCL gibt es Erweiterungen für diverse Editoren und IDEs, die bspw. Syntax-Highlighting anbieten. Das Kommandozeilenwerkzeug “terraform” bietet auch die Möglichkeit, Templates in “check mode” zu interpretieren, also nur das berechnete Delta auszugeben, ohne die Veränderungen an der Infrastruktur tatsächlich vorzunehmen.

Übertragbarkeit

CloudFormation und Troposphere funktionieren ausschließlich mit AWS. Diese Einschränkung ist “by design”.

Terraform ist beschränkt portabel. Es können verschiedene Provider konfiguriert werden mit dem “provider”-Konstrukt. Allerdings müssen die Ressourcen-Definitionen bei der Umstellung auf einen anderen Provider umgeschrieben werden (das liegt schon an der Syntax: alle Ressourcentypen haben als Präfix den Kürzel des Providers, z.B. “aws”). Somit stellt Terraform keine Abstraktionsschicht über diverse IaaS-Provider dar. Die Unterschiede der einzelner IaaS-Provider könnten zwar durch das vorhandene Modularisierungskonzept weg abstrahiert werden, was allerdings einen zusätzlichen Mehraufwand für die Entwicklung nach sich ziehen würde (es müssten mehrere Modul-Implementierungen für unterschiedliche Provider geschrieben werden).

Wartbarkeit

Die Wartbarkeit hängt von vielen Faktoren ab. Zum Einen spielt die konkrete Syntax für die Lesbarkeit der Templates eine große Rolle. Entscheidend sind aber die Möglichkeiten der Abstraktion.

CloudFormation-Syntax ist JSON bzw. YAML-basierend. Alle Ressourcen müssen einzeln in einer flachen Liste aufgelistet werden. Somit lassen sich größere CloudFormation-Templates nur sehr aufwändig pflegen. Manuelle Änderungen sind fehleranfällig. Außerdem gibt es keine Möglichkeit, die Templates auf mehrere Dateien aufzuteilen. Erschwerend kommt hinzu, dass bspw. Shell-Skripte in die Datei inline aufgenommen werden müssen, was die Template-Größe stark ansteigen lässt. Allerdings bietet Amazon einen graphischen Editor für CloudFormation im Web, der zumindest für kleine bis mittelgroße Systeme die Handhabung erleichtert. Große und komplexe Systeme lassen sich aber auch im grafischen Editor aufgrund mangelnder Abstraktionsmechanismen nicht überschaubar darstellen.

Troposphere ist in Python geschrieben und hat somit eine sehr einfache Syntax. Die vorhandenen Klassen bilden aber nur eine dünne Schicht über die darunter liegenden CloudFormation-Ressourcen. Die Entwicklung von höherwertigen Konstrukten (bspw. Module) muss also explizit erfolgen. Die Wartbarkeit von Troposphere-Templates hängt somit wesentlich von der Qualifikation (und Motivation) des Entwicklers ab.

Terraform hat eine sehr schlanke DSL und lässt sich somit sehr leicht lesen und bearbeiten. Durch das Modularisierungskonzept lassen sich Systeme sehr gut in kleinere Subsysteme aufteilen, die unabhängig voneinander gepflegt werden können. Durch die Auslagerung und Teilen von Modul-Implementierungen können auf lange Sicht sogar Skaleneffekte erreichen lassen, weil häufig verwendete Module wiederverwendet werden können.

Zusammenfassung

SpracheCloudFormationTroposphereHCL (Terraform)
SyntaxJSON/YAMLPythonHCL
AusführungInterpretiertÜbersetztInterpretiert
ModularisierungNeinMöglichJa
PolymorphismusNeinMöglichBegrenzt möglich
ÜbertragbarkeitNein (nur AWS)Nein (nur AWS)Begrenzt möglich
WartbarkeitSchwierigEntwicklerabhängigGut

Fazit

In diesem Artikel wurden drei Sprachen verglichen, mit denen Infrastructure as Code umgesetzt werden kann. Die vorgestellten Sprachen sind sehr verschieden. Für welche Sprache man sich letztendlich entscheidet, sollte anhand von konkreten Anforderungen und Gegebenheiten abgewägt werden.

CloudFormation ist aufgrund mangelnder Möglichkeiten für Abstraktion nur für kleinere und einfache Systeme geeignet. Dafür wird es nativ von AWS unterstützt und hat keine Abhängigkeiten auf weitere Tools. Mit dem grafischen Editor kann man sofort loslegen.

Troposphere ist eine interne Python DSL und bietet somit große Freiräume für den Entwickler an. Sie erbt die konkrete Syntax von der Host-Sprache Python. Das bedeutet aber auch, dass der Entwickler selbst viele Konzepte implementieren und viele Entscheidungen treffen muss.

Terraform von HashiCorp hat eine schlanke DSL. Die größte Stärke von Terraform ist ein eingebautes Modularisierungskonzept. Somit ist HCL eine Sprache, die auch auch für größere und komplexere Systeme sehr gut skaliert.

Keine der besprochenen Sprachen ist perfekt. Eine Konsolidierung der allgemeinen Konzepte und Best Practices bleibt noch abzuwarten. Bis zu einer vollständigen Kommodifizierung der IaaS ist noch ein langer Weg. So bleibt bspw. die Portabilität von Templates eine noch nicht gelöste Herausforderung.

Vielversprechend in diesem Kontext kann Cloudify sein, das einen offenen Standard für die Infrastruktur-Orchestrierung TOSCA (Topology and Orchestration Specification for Cloud Applications) implementiert. Durch die Spezifikation der Infrastruktur in einer standardisierten Sprache können Templates von der konkreten Implementierung des Service Providers entkoppelt werden.

JClouds, Libcloud, Fog und Pkgcloud bieten einen alternativen Ansatz, bei dem eine Zusätzliche Abstraktionsschicht über die verschiedenen Service Provider APIs erstellt wird, gegen die Infrastruktur-Orchestrierung definiert wird.

Einen weiteren alternativen Ansatz stellt das PaaS-Modell dar. In diesem Fall übernimmt der Provider die Verantwortung für die Bereitstellung der technischen Infrastruktur. Allerdings können zusätzliche Lock-In-Effekte entstehen, wenn man gegen proprietäre Schnittstellen des Anbieters programmiert, was wiederum die Übertragbarkeit stark einschränkt.

Links

https://aws.amazon.com/cloudformation

https://github.com/cloudtools/troposphere

https://www.terraform.io

Andrey Skorikov

Andrey Skorikov ist IT Consultant am Standort Karlsruhe der codecentric AG. Sein Schwerpunkt liegt in der Softwarequalität, Testautomatisierung und Continuous Integration/Delivery.

Share on FacebookGoogle+Share on LinkedInTweet about this on TwitterShare on RedditDigg thisShare on StumbleUpon

Weitere Inhalte zu Allgemein

Kommentieren

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.