Terraform und OpenStack

Terraform und OpenStack

Viele von Euch sind vermutlich bereits mit der Verwendung von Terraform in Kombination mit Azure oder AWS vertraut. Und obwohl dies die am häufigsten verwendeten Plattformen sind, gibt es – oftmals im Bezug auf Datenschutz (DSGVO) – Unwägbarkeiten und somit weiterhin einen Bedarf an zuverlässigen Alternativen. Da all unsere Systeme auf Open-Source basieren, beschäftigen wir uns an dieser Stelle mit der Verwendung von Terraform in Kombination mit OpenStack. Wir versuchen stets, all unsere Dienste in OpenStack zu integrieren und erstellen anschließend Tutorials, um auch der Community zu helfen. Durch die Verwendung von Terraform mit OpenStack kann man nach Belieben sofort mit dem Deployment von Servern beginnen. Dieses Tutorial führt Euch durch die ersten Schritte.  

Terraform und OpenStack verstehen

Terraform ist ein fantastisches Tool für die Bereitstellung von Infrastrukturen. In den richtigen Händen kann es die Art und Weise wie Ressourcen bereitgestellt werden, verändern. Der Einstieg in Terraform ist relativ einfach und bereits innerhalb weniger Minuten können Server in unserem OpenStack-Projekt deployed werden. Terraform ist deklarativ, was bedeutet, dass Du das Endergebnis definierst und Terraform den Rest für Dich erledigen lässt. OpenStack hingegen ist ein großartiger Open-Source-Cloud-Anbieter mit vielen Funktionen, die für eine Vielzahl von Anwendungen zugänglich sind. Beide Tools sind kostenlos und bedingen keine Anschaffung. Du musst – wie bei NETWAYS Web Services üblich – nur für die tatsächlich entstandenen Serverkosten aufkommen. Und diese sind geringer als Du denkst!  

Terraform installieren

Wir gehen an dieser Stelle davon aus, dass Du Dich bereits eingehend mit OpenStack-Projekten beschäftigt hast und werden uns mehr auf die Einrichtung von Terraform konzentrieren. Falls Terraform bisher nicht installiert wurde, haben wir hier eine kurze Anleitung für Dich: Wenn Du mit macOS arbeitest, hast Du Glück. Man benötigt nur die folgenden zwei Befehle um loszulegen: 

brew tap hashicorp/tap
brew install hashicorp/tap/terraform

Somit wird das Repository und alles, was sonst benötigt wird, installiert. Anschließend stellen wir sicher, dass das Setup funktionsfähig ist. Indem man „terraform“ in die Konsole eingibt, kann man prüfen, ob man eine Antwort erhält. Unter Linux benötigt man jedoch ein paar weitere Befehle, um das System zum Laufen zu bringen. Zunächst muss der GPG-Schlüssel zum System hinzugefügt werden: 

wget -O- https://apt.releases.hashicorp.com/gpg | gpg --dearmor | sudo tee /usr/share/keyrings/hashicorp-archive-keyring.gpg

Nun können wir das offizielle Repository der HashiCorp hinzufügen: 

echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list

Anschließend kann der Server geupdated und Terraform installiert werden. 

sudo apt update
sudo apt install terraform

Auch hier können wir mit dem „terraform“-Befehl überprüfen, ob alles korrekt installiert ist. Ist dies der Fall, kümmern wir uns im nächsten Schritt um die Authentifizierung, damit wir mit OpenStack kommunizieren können.

Terraform konfigurieren

Für alle Terraform-Umgebungen wird eine Datei namens „main.tf“ benötigt. Darin wird der gewünschte Cloud-Anbieter, einschließlich aufzusetzender Server und einzubindender Module, konfiguriert. Ggf. möchtest Du zunächst ein eigenes Verzeichnis für Terraform erstellen, aber das bleibt letztendlich Dir überlassen. 

mkdir terraform
cd terraform
vim main.tf

Untenstehend findest Du meine “main.tf” File. So kann die Konfiguration im Einzelnen aussehen: 

terraform { 
   required_version = ">= 0.14.0" 
   required_providers { 
      openstack = { 
         source = "terraform-provider-openstack/openstack" 
         version = "~> 1.48.0" 
      } 
   } 
}
provider "openstack" {
   auth_url = "https://cloud.netways.de:5000/v3/"
   user_name = "1234-openstack-56789"
   password = "supersecretpassword"
   region = "HetznerNBG4"
   user_domain_name = "Default"
   tenant_name = "1234-openstack-56789"
}

Dies ist die grundlegende Einstellung, dieDu benötigst, um mit Deinem OpenStack-Provider zu kommunizieren. Zu Beginn definieren wir die Versionen, die wir für Terraform und OpenStack verwenden wollen. Der Abschnitt „Provider“ ist der Authentifizierung gewidmet, die man für die Kommunikation benötigt. Viele dieser Informationen können auch im Projekt unter API Access und clouds.yaml eingesehen werden, u.a.:

auth_url – URL des OpenStack Providers user_name – Der Benutzer des Projekts password – Passwort für dieses Projekt region – Standort des Providers user_domain_name – üblicherweise “Default” tenant_name – Dies ist nicht Teil der clouds.yaml File. In vorliegendem Fall der Projektname
Nun, da die Authentifizierung geklärt ist, können wir den nächsten Befehl ausführen, um alles zu initialisieren. Im Verzeichnis „terraform“ können wir diesen Befehl ausführen: 

terraform init

Dies ist erforderlich, da Terraform – obwohl wir es bereits installiert haben – nicht den Code für alle Provider sammelt. Das übernehmen wir an der Stelle, um alle Informationen zu bekommen, die wir für OpenStack benötigen. Anschließend sind wir in der Lage, mit unserem Projekt zu kommunizieren. Jetzt können wir damit beginnen, eine Infrastruktur aufzubauen und unsere Ressourcen zum Laufen zu bringen! Für dieses Beispiel werden wir einen Server mit einem Standard-Flavour und einem SSH-Schlüssel starten. Hier ist meine Konfiguration für beide Ressourcen: 

resource "openstack_compute_instance_v2" “example-server" {
   name = "terraform-test"
   flavor_name = "s1.small"
   image_name = "Ubuntu Jammy 22.04 LTS"
   security_groups = [
      "HTTP",
      "SSH"
   ]

   network {
      name = "6801-openstack-ca070"
   }

   key_pair = "ssh"
}

Dies ist ein sehr einfaches Setup für den Anfang. Weitere Notwendigkeiten findest Du im folgenden Absatz.  

Weiteres Vorgehen

Zunächst kümmern wir uns um die Ressource oder den Server, den wir erstellen wollen. Achte darauf, dass die eingegebenen Werte mit den Werten im Projekt übereinstimmen, sonst wird die Instanz nicht korrekt erstellt. Die von mir verwendeten Sicherheitsgruppen waren bereits in meinem Projekt vorhanden, da ich sie für ein früheres Projekt konfiguriert hatte. Darunter befindet sich mein SSH-Schlüssel, damit ich mich auch später noch mit dem Server verbinden kann. Dies muss zwangsläufig bei der Erstellung des Servers geschehen. Hier siehst Du die vollständige Konfiguration für die Einrichtung des Cloud-Providers und des Servers, den ich einsetzen möchte: 

terraform {
   required_version = ">= 0.14.0"
   required_providers {
      openstack = {
         source = "terraform-provider-openstack/openstack"
         version = "~> 1.48.0"
      }
   }
}

provider "openstack" {
   auth_url = "https://cloud.netways.de:5000/v3/"
   user_name = "1234-openstack-56789"
   password = "supersecretpassword"
   region = "HetznerNBG4"
   user_domain_name = "Default"
   tenant_name = "1234-openstack-56789"
}

resource "openstack_compute_instance_v2" “example-server" {
   name = "terraform-test"
   flavor_name = "s1.small"
   image_name = "Ubuntu Jammy 22.04 LTS"
   security_groups = [
      "jitsi",
      "SSH"
   ]

   network {
      name = "6801-openstack-ca070"
   }

   key_pair = "ssh"
}

Da unsere Konfiguration eingerichtet ist, können wir jetzt einen Probelauf machen, um zu sehen, welche Änderungen vorgenommen werden. Bevor die Änderungen tatsächlich angewendet werden, ist es immer ratsam, die Konfiguration vorab auszuprobieren. So kann man den Code nochmals überprüfen, bevor er deployed wird. Der Graph, der sich aus dem Befehl ergibt, ist dem von git sehr ähnlich. Er zeigt Dir mit „+“ und „-“ an, welche Änderungen sich ergeben. Auf diese Weise erhält man einen besseren Überblick. 

terraform plan

Wenn Du mit den angezeigten Änderungen zufrieden bist und es keine Fehler gibt, kannst Du den nächsten Befehl ausführen, um die Änderungen tatsächlich anzuwenden. Du hast anschließend der Möglichkeit, die Änderungen zu bestätigen oder abzubrechen. 

terraform app

Wenn man mit dem Setup fertig ist und dieses nicht länger benötigt, können die Ressourcen anschließend mit untenstehenden Befehl wieder freigegeben werden. Sei jedoch vorsichtig, denn dadurch wird die gesamte Konfiguration entfernt. Falls weitere Personen an der Machine arbeiten, kann es sein, dass diese fortan nicht mehr darauf zugreifen können! 

terraform destroy

Zusammenfassung

Presto! Deine ersten Schritte in der Welt des Provisioning mit OpenStack sind getan. Was wir in diesem Tutorial im kleinen Rahmen beschrieben haben, verändert an sich nicht die Welt. Aber es eröffnet Dir viele weitere Möglichkeiten für Deine künftigen Projekte. Mit dem deklarativen Ansatz von Terraform und der Flexibilität von OpenStack wird die Bereitstellung und Verwaltung von Infrastrukturressourcen effizient und zugänglich. Aber das ist noch nicht alles: in den kommenden Terraform Tutorials beschäftigen wir uns mit spezifischen Konfigurationen in Verwendung mit OpenStack. Starte Dein eigenes Projekt mithilfe unserer OpenStack Cloudlösung und probier es selbst aus! Und falls Du Hilfestellung benötigst, sind unsere MyEngineers jederzeit für Dich da.

Dynamic Inventory – Eine Ansible und OpenStack Lovestory

Dynamic Inventory – Eine Ansible und OpenStack Lovestory

Für diejenigen unter euch, die mit Ansible möglicherweise nicht allzu vertraut sind: Es ist ein großartiges Tool, um in die Welt der Automatisierung einzusteigen und erleichtert euer Leben im Konfigurationsmanagement erheblich.  

Die Kennenlernphase

In diesem Tutorial werden wir ein grundlegendes Playbook durchgehen, welches man mit OpenStack verwenden kann, und uns mit der Verwendung dynamischer Inventare befassen. Dynamische Inventare haben einen großen Vorteil: man muss die Datei nicht jedes Mal manuell aktualisieren, wenn man einen neuen Server in einem Projekt einrichtet. Falls Ansible mit OpenStack verwendet wird, kann ein dynamisches Inventar-Plugin verwendet werden, um eine Liste der Server zu erstellen, die in der OpenStack-Umgebung ausgeführt werden. Das Plugin stellt eine Verbindung zur OpenStack-API her und sammelt Informationen über Instanzen, die bestimmte Kriterien erfüllen, beispielsweise solche mit einem bestimmten Tag oder die Ausführung eines bestimmten Images. Durch die Verwendung eines dynamischen Inventars kann man den Prozess der Erkennung und Verwaltung von Hosts in der Netzwerkumgebung optimieren, ohne eine statische Inventardatei manuell aktualisieren zu müssen. Dies ist besonders in größeren oder dynamischeren Umgebungen nützlich, in denen sich die Anzahl der Hosts ständig ändert. Die einzigen Voraussetzungen für dieses Tutorial sind Grundkenntnisse von Ansible und OpenStack. Und selbst als absoluter Anfänger sollten man dennoch in der Lage sein, den Kern dessen zu verstehen, was wir erreichen wollen. Zu Demonstrationszwecken werden wir die Server meines Projekts verwenden, in der Realität könnte es sich jedoch um beliebig viele Server handeln. In diesem Beispiel überprüfen wir lediglich die Betriebszeit aller unserer Server. Also lasst uns direkt anfangen! Die beiden wichtigsten Voraussetzungen sind (natürlich) Ansible sowie das OpenStack SDK, um die API zu steuern. Jedoch ist Vorsicht geboten: Abhängig von Ihrem System muss möglicherweise „pip3“ verwendet werden, da sich „pip“ auf „pip2“ bezieht, welches nicht mehr unterstützt wird. Zunächst installieren wir Ansible mit Pip von Python. Überprüfen wir, ob pip installiert ist: 

python3 -m pip -V

Wenn Sie die Meldung „No module named pip“ erhalten, können Sie es mit diesen Befehlen installieren: 

curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
python3 get-pip.py --user

Und anschließend können Sie auch Ansible installieren: 

curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
python3 get-pip.py --user

Mit diesem Befehl können wir überprüfen, ob es korrekt installiert wurde: 

ansible —-version

Die erste gemeinsame Wohnung

Nachdem wir Ansible nun installiert haben, kann mit dem OpenStack SDK fortgefahren werden. Nachdem wir sichergestellt haben, dass Pip definitiv installiert ist, können wir Folgendes verwenden: 

pip install openstack

Nachdem wir nun beide Programme sowie das Plugin installiert haben, können wir mit dem Schreiben eines einfachen Playbooks beginnen. Dieses Playbook ist, wie bereits erwähnt, sehr simpel gehalten und wir werden lediglich die Betriebszeit der Server überprüfen. Natürlich kann dies auch sehr viel komplexer gestaltet sein, aber das Prinzip ist immer dasselbe. Wir benötigen die folgenden Dateien in unserem Ordner, in dem wir den Ansible-Code ausführen: clouds.yaml In dieser Datei befinden sich alle unsere Anmeldeinformationen für OpenStack. Ansible benötigt diese, um Zugriff auf unser Projekt zu erhalten. Die Anmeldeinformationen erhält man, indem man die Datei vom OpenStack herunterlädt. So sieht meine aus: 

clouds:
  openstack:
    auth:
      auth_url: https://cloud.netways.de:5000/v3/
      username: “openstack-user"
      password: “super-secret-password“
      project_id: 12495myproject-id65684
      project_name: "1234-openstack-15def5"
      user_domain_name: "Default"
    region_name: "HetznerNBG4"
    interface: “public"
    identity_api_version: 3

ansible.cfg Hier habe ich einen Server eingefügt, der als Jumphost fungiert, sowie einen Benutzer, der benötigt wird um eine Verbindung zu unseren Servern herzustellen. 

[defaults]
ansible_ssh_common_args='-o ProxyCommand="ssh -W %h:%p user1@jumpserver"'
remote_user=ubuntu

openstack.yml In dieser Datei geben wir an, welches Plugin wir verwenden und welche Variablen wir einschließen möchten. „private: false“ stellt beispielsweise sicher, dass wir öffentliche IP-Adressen verwenden. Dadurch wird auch unsere cloud.yaml-Datei verknüpft, sodass wir sie nicht in unseren Befehl einschließen müssen. Dies ist die Datei, die ich verwendet habe: 

---
plugin: 'openstack.cloud.openstack'
expand_hostvars: yes
fail_on_errors: yes
all_projects: false
private: false
clouds_yaml_path: ["./clouds.yml"]

playbook.yaml Dies ist das einfache Playbook, mit dem ich die Betriebszeit aller meiner Server ermittelt habe: 

---
- name: Print uptime of servers in OpenStack project
  hosts: all
  gather_facts: no
  tasks:
    - name: Print server uptime
      command: uptime
      register: uptime
    - debug: msg="{{ uptime.stdout }}"

Da nun alle Vorbereitungen getroffen sind, ist es an der Zeit, unser Playbook auszuführen und die Ausgabe zu überprüfen: 

ansible-playbook -i openstack.yml playbook.yml

Honeymoon

Nachdem das Playbook vollständig ausgeführt wurde, können wir überprüfen, ob es ordnungsgemäß funktioniert hat. Wir sollten die Ergebnisse wie oben auf dem Terminal ausgedruckt sehen. Sollte das Playbook viel komplexer sein und fehlschlagen, kann man einfach anhand der Fehlermeldungen sehen, wo das Problem aufgetreten ist. Das ist das Tolle an Ansible: Man kann das Playbook beliebig oft ausführen und erhält das gleiche Ergebnis. Dies wird auch als Idempotenz bezeichnet. Obwohl dies ein sehr grundlegendes Tutorial zu den Möglichkeiten eines dynamischen Inventars ist, kann man es ebenso ganz einfach auf viel komplexere Playbooks anwenden. Wenn das zugrundeliegende Projekt 100 Server umfasst, wäre dies ideal, da somit nicht jeder Server manuell konfiguriert werden muss. Jedoch kann dies auch bei kleineren Projekten hilfreich sein. Man muss beispielsweise die Details neuer Server nicht erneut eingeben, falls alte Server zerstört und analog neue eingerichtet werden müssen. Wenn Du mehr über IaaS erfahren oder weitere Tutorials zu verschiedenen anderen Dev-Ops-Themen lesen möchtest, sieh Dir doch unsere Blogs und die anderen Beiträge auf unserer Website an. Der Einstieg ins eigene Setup könnte nicht einfacher sein. Einer unserer MyEngineers hilft gerne dabei, Deine Projektideen zum Leben zu erwecken.