Ein Ansatz für unveränderliche Infrastruktur
Sami Alajrami
Sami is a DevOps consultant in our Oslo office. He comes from Palestine and has a PhD in Computing Science from Newcastle University. Sami’s previous work focused on cloud-based software development, model-based engineering, and safety-critical systems. He’s also an INTJ.
Unveränderliche Infrastruktur als Code reduziert Inkonsistenzen und macht Deployments schneller und einfacher. Mit Packer und Terraform können wir unveränderliche Infrastruktur bereitstellen. Nutzen wir sie, um Jenkins-Windows-Build-Slaves bereitzustellen.
In einem früheren Beitrag haben wir erläutert, wie ihr Jenkins mithilfe von Helm auf einem Kubernetes-Cluster deployen und Windows-Build-Slaves damit verbinden könnt. Aufgrund der noch unausgereiften Windows-Unterstützung in k8s haben wir die Windows-Build-Slaves in einer separaten VPC platziert. Diese Slaves jedoch manuell bereitzustellen und zu starten, ist im Zeitalter von Continuous Delivery und DevOps alles andere als ideal. In diesem Beitrag zeigen wir, wie ihr die Bereitstellung von Windows-Build-Slaves auf AWS mit Packer und Terraform automatisieren könnt.
While we use AWS -in this post- as an IaaS provider, both Packer and Terraform support multiple other cloud providers.
Unveränderliche Infrastruktur
Windows-Build-Slaves lassen sich mit Konfigurationsmanagement-Tools wie Chef oder Puppet bereitstellen. Diese Tools schaffen eine veränderliche Infrastruktur, bei der eure Server im Laufe der Zeit voneinander abweichen können. Dies wird als Configuration Drift bezeichnet. Packer und Terraform ermöglichen euch – neben anderen Tools – die Erstellung von unveränderlicher Infrastruktur. Mit Packer könnt ihr ein vorkonfiguriertes Image mit sämtlicher benötigter Software erstellen. Anschließend stellt ihr mit Terraform alle eure Cloud-Ressourcen aus diesen Images bereit. Wenn ein Update ansteht, wendet ihr es auf eure Images an und stellt neue Cloud-Ressourcen bereit. Die alten Ressourcen werden entfernt.
You might want to keep your old resources a little longer while you make sure the new -updated- resources are behaving as intended.
Warum ihr kein Konfigurationsmanagement verwenden solltet, erfahrt ihr hier.
Please note that there are cases where configuration management tools are still needed. For example, to install your OS of choice on bare-metal infrastructure.
Der Weg mit Packer und Terraform
Mit Packer können wir ein Windows-VM-Image erstellen, das alle Abhängigkeiten für den Betrieb des Build-Slaves enthält. Terraform wiederum ermöglicht es uns, Instanzen auf AWS über ein mit Packer erstelltes Amazon Machine Image (AMI) zu starten und zu verwalten.
Packer wird verwendet, um Machine Images aus Code-Templates zu generieren. Die Templates definieren, wie das Image mithilfe von Builders erstellt wird, die spezifisch für die Zielumgebung sind, etwa AWS oder VirtualBox. Außerdem enthalten sie Provisioner, die Software bereitstellen und die erforderliche Konfiguration im Image vornehmen. Wir verwenden ein Packer-Template, das eine EC2-Instanz mit der neuesten Version von Windows Server 2016 auf AWS startet und Docker sowie Java installiert. Zudem lädt es die Jenkins-Datei slave.jar vom Jenkins-Master herunter und erstellt ein Skript, das den Slave startet und mit dem Master verbindet. Nach Abschluss der Bereitstellung registriert Packer das neue AMI in eurem AWS-Konto und bereinigt die verwendeten Ressourcen.
By installing Docker into the AMI, Jenkins jobs can be executed in containers. This means creating a custom build environment for specific jobs is as simple as creating a Dockerfile and building a Docker image from it.
Terraform ist ein Infrastructure-as-Code-Tool zum Erstellen, Weiterentwickeln und Versionieren von Infrastruktur bei Cloud-Anbietern. Terraform verwendet versionierte Code-Templates, die das Teilen und Wiederverwenden von Infrastruktur ermöglichen. Mit einigen Terraform-Templates erstellen wir eine VPC in AWS, starten mehrere Windows-Instanzen und führen darauf die Build-Slaves aus.
Windows-Besonderheiten bei der Verwendung von Packer und Terraform
Wenn wir mit Packer Windows- statt Linux-Images erstellen, besteht der entscheidende Unterschied darin, dass für die Kommunikation mit der Windows-Instanz während ihrer Konfiguration WinRM (Windows Remote Management) verwendet wird.
Anders als SSH unter Linux muss WinRM auf der Windows-Instanz konfiguriert werden, bevor Packer eine Verbindung herstellen und Software bereitstellen kann. Dies geschieht über User Data. Wenn Packer auf AWS eine neue Instanz startet, die zum Erstellen des AMI verwendet wird, kann es ein User-Data-Skript an AWS übergeben. AWS führt dieses Skript dann beim Starten auf der Instanz aus. Das Skript ec2-userdata.ps1 enthält die WinRM-Konfiguration zum Öffnen der erforderlichen Ports und zum Hinzufügen von Listenern. Weitere Details zu dieser Konfiguration findet ihr hier.
If you face problems with WinRM, and want to check that it is running, have a look at this page for some useful commands.
Windows-Administratorpasswort und User-Data-Skripte
Packer erstellt das AMI, indem es eine Instanz startet, darauf alle erforderlichen Bereitstellungsschritte ausführt und sie anschließend als Image speichert. Wenn eine Windows-Instanz auf AWS zum ersten Mal gestartet wird, wird sie mit EC2Launch initialisiert – oder mit EC2Config bei Windows-Versionen vor Windows Server 2016. Zur Initialisierung gehören das Erstellen eines zufälligen Administratorpassworts und die Ausführung aller angegebenen User Data. Die Initialisierung wird als Dienst registriert, der beim Booten ausgeführt wird. Nach ihrem Abschluss wird der Dienst wieder deregistriert. Das bedeutet, dass weitere Starts der Instanz weder neue Administratorpasswörter erzeugen noch User-Data-Skripte ausführen.
Wenn ihr eine Instanz aus dem von Packer generierten AMI erstellt, übernimmt sie das Administratorpasswort der Instanz, mit der das AMI erstellt wurde. Außerdem wird keine neue User Data ausgeführt, da die Initialisierung, wie gerade beschrieben, deregistriert wurde. Was aber, wenn ihr User-Data-Skripte auf den Instanzen ausführen möchtet, die ihr aus dem von Packer generierten AMI startet?
Ihr müsst die für die Erstellung des AMI verwendete Instanz während der Packer-Bereitstellung so konfigurieren, dass der nächste Start als neuer Launch behandelt wird. Das bedeutet, dass ein neues zufälliges Passwort vergeben und jedes neue User-Data-Skript ausgeführt wird. Unter Windows Server 2016 erfolgt dies mit EC2Launch; ältere Windows-Versionen werden mit EC2Config konfiguriert.
The EC2Launch scripts triggering the instance initialization can be found (on the Windows instance) in C:\ProgramData\Amazon\EC2
Ihr könnt das von Packer generierte AMI so konfigurieren, dass beim nächsten Start die Initialisierungsskripte ausgeführt werden. Führt dazu auf der Windows-Instanz während der Packer-Bereitstellung den folgenden Befehl aus:
./C:ProgramDataAmazonEC2-WindowsLaunchScriptsInitializeInstance.ps1 -ScheduleWartung
Jetzt verfügen wir über eine unveränderliche Infrastruktur, die mit Terraform verwaltet wird. Möchtet ihr die auf den Windows-Instanzen verwendete Java-Version aktualisieren? Aktualisiert einfach euer Packer-Template, erstellt ein neues AMI und führt anschließend den Terraform-Befehl „apply“ aus. Fertig! Eure aktualisierten Build-Slaves sind in wenigen Minuten einsatzbereit.
Möchtet ihr für bestimmte Build-Jobs eine angepasste Umgebung nutzen? Erstellt innerhalb eures Packer-Templates ein Docker-Image mit einem Dockerfile und generiert ein AMI, bevor ihr eure Infrastruktur mit Terraform aktualisiert. Eure Build-Slaves können dann Container ausführen und damit jede gewünschte angepasste Umgebung bereitstellen. Einfach!
Den vollständigen Code findet ihr auf Github.
- Cloud
- CI/CD
Subscribe to our newsletter
Related blogs