Ansible für automatisierte Roll-Outs – der Einstieg

This entry is part 1 of 1 in the series Ansible from scratch
  • Ansible für automatisierte Roll-Outs – der Einstieg

In einer beweglichen und agilen Cloud Umgebung wird es immer wichtiger, dass Server Systeme vollautomatisch ausgerollt werden, um den Erwartungen der Nutzer gerecht zu werden. Noch vor wenigen Jahren war es völlig normal, dass man auf einen neuen Server mehrere Wochen warten musste, aber in der heutigen Welt, wo man sich innerhalb von 5 Minuten einen virtuellen Server bei Amazon klicken kann, haben sich die Ansprüche verschoben. Selbst wenige Tage Wartezeit auf einen Server werden schon als inakzeptabel empfunden.

Daher möchte ich in dieser Serie meine Erfahrungen mit Ansible schildern und aufzeigen, welche Wege funktionieren und was man vielleicht vermeiden sollte. Alles hier Dargestellte beruht auf meinen Erfahrungen und stellt nicht „die absolute Wahrheit“ dar, sondern zeigt den Status Quo auf, an dem ich nach einigem Hin und Her angekommen bin. Wer alternative Ideen, Anmerkungen oder Verbesserungsvorschläge hat, ist herzlich eingeladen diese hier in den Kommentaren abzuladen!

Um die Systeme in der gewünschten Geschwindigkeit bereitzustellen muss man diese vollautomatisiert ausrollen können. In dieser Serie gehe ich davon aus, dass das „nackte“ Betriebssystem bereits ausgerollt ist, was durch ein Template in der Cloud Plattform oder auch durch Tools wie Foreman geschehen kann. Dieser Server hat einen SSH Zugang installiert, der das Login mit einem SSH-Key erlaubt, außerdem ist Python verfügbar. Ich konzentriere mich hier auf Linux Systeme, Ansible kann allerdings auch mit Windows Systemen umgehen.

Setup

Ansible greift per ganz normalem SSH auf die zu konfigurierenden Nodes zu. Die sogenannten Playbooks können also vom lokalen Arbeitsplatzrechner oder von einem dedizierten Host gestartet werden. In größeren Umgebungen bietet sich die Variante mit dem zentralen Ansible Host an, für die Entwicklung oder kleinere Umgebungen kann man auch vom lokalen Arbeitsplatz aus arbeiten.

Um sicherzustellen, dass bei verteilter Arbeitsweise alle auf die gleichen Playbooks zurückgreifen, sollte ein zentraler Git Server (Versionskontrollsystem) bereitgestellt werden, auf dem die Playbooks verwaltet werden.

Der Zugriff auf die Hosts per SSH hat zwei große Vorteile:

  • kein Agent auf den Hosts erforderlich – nur Python und ein SSH Zugang
  • durch die Verwendung der SSH Config kann man hier auch Hosts, die nur indirekt (über einen Bastion- oder Jump-Host) erreichbar sind direkt ansprechen.

Der Demo Setup

Diagramm der Netzwerkumgebung

Netzwerk Setup der Demo Umgebung

In dieser Serie wird erst einmal von einer Workstation aus gearbeitet (in meinem Fall ein Mac, Linux geht aber auch, Windows ist leider etwas komplizierter – siehe Ansible Windows Support). Die zu verwaltende Umgebung ist ein Labor Setup, der teilweise über einen Jumphost und teilweise direkt erreichbar ist.

Im direkt erreichbaren Teil der Infrastruktur lautet die DNS Domain der Hosts front.example.com und das nicht direkt erreichbare Netz hat die Domain lab.example.com. Auf dem Jumphost ist die Namensauflösung so konfiguriert, dass per Default in lab.example.com gesucht wird. Wenn auf dem Jumphost als srv01 angefragt wird, so wird dies zu srv01.lab.example.com, sodass die Kommunikation ab diesem Punkt standardmäßig über das Lab Netz geht.

Der Jumphost ist bereits fertig konfiguriert und erfordert keine weitere Einrichtung (mein Adminaccount pd ist angelegt und mein SSH Key ist installiert. Die weiteren Hosts haben zwar eine Netzwerkconfig (IP Adressen etc.) und einen Default Login Account (deploy), der auch sudo Berechtigungen (ohne Passwort!) hat, aber noch keine weitere Config. Der Default Login Account ist auch mit einem SSH Key ausgestattet, der in die authorized_keys von SSH eingetragen ist und das Passwort ist deaktiviert (d.h.: Login mit einem Passwort ist nicht möglich).

 

Los geht’s

Workstation (Mac) vorbereiten

Wir benötigen Homebrew um etwas Software zu installieren und die Pakete zu managen. Einfach der Anleitung im Link folgen.

Anschließend nutzen wir Homebrew, um python (und hier insbesondere PIP) zu installieren:

Jetzt installieren wir noch Ansible aus den offizielle Python PIP Repositories (dies ist im Allgemeinen die aktuellste stabile Version):

Inventar und SSH Verbindungen einrichten

In diesem Teil der Serie richten wir uns erst einmal häuslich ein, erstellen ein Grundgerüst für unser Playbook und stellen die benötigte SSH Konnektivität her. Im weiteren Verlauf dieser Serie bauen wir darauf auf und erstellen nach und nach ein komplexeres Playbook, welches uns die Grundeinrichtung von Linux Hosts abnimmt bzw. diese ganz erheblich beschleunigt.

Verzeichnisstruktur

Um unser Playbook auch für spätere Erweiterungen sauber zu halten, verwende ich die hier gezeigte Verzeichnisstruktur, die wir im späteren Verlauf nach Bedarf erweitern werden:

Die einzelnen Einträge in diesem Verzeichnis sind:

  • README.md – eine klassische README Datei, die den Zweck und die Verwendung des Playbooks erklärt (im Markdown Format)
  • group_vars – ein Verzeichnis, in das Variablen und Parameter für spezifische Gruppen von Hosts abgelegt werden
  • host_vars – analog zu group_vars aber nur für einzelne Hosts
  • inventory – ein Verzeichnis für Inventarlisten. Auf Basis dieser Listen wendet Ansible die Playbooks auf die darin genannten Hosts an
  • site.yml – das Haupt-Playbook File. Der name ist beliebig und es ist durchaus gebräuchlich mehrere dieser Files für unterschiedliche Aufgaben zu haben
  • templates – ein Verzeichnis für Template Dateien, welche auf die Hosts ausgerollt werden sollen. Diese Templates verwenden Jinja2 als Templating Sprache
  • vars – ein Verzeichnis für sonstige Variablen und Parameter, die nicht pro Host oder pro Gruppe verwendet werden.

Diese Struktur habe ich in ein leeres Verzeichnis angelegt, sodass ich für neue Projekte einfach die leere Hierarchie kopieren kann, um einen Startpunkt zu haben.

Das Inventory

Als erstes erstellen wir mal ein kleines Inventory file, welches alle beteiligten Hosts enthält, auf denen etwas gemacht werden soll. Im ersten Anlauf halten wir das schön einfach: keine Gruppen, keine Spezialparameter, nur die Hosts. Inventory Files orientieren sich am INI-File Format. Hier ist also mein erstes Inventory File:

Dieses File wird einfach mit einem Texteditor erstellt und unter einem beliebigen (sprechenden!) Namen im inventory Verzeichnis abgelegt. In meinem Fall heißt das File lab-environment.

Alles ab einem # in einer Zeile wird als Kommentar ignoriert. Auf jeder Zeile steht ein Hostname, was uns jetzt ein Problem bereitet: die nicht direkt erreichbaren Hosts. Um mit diesen Hosts zu kommunizieren müssen wir uns zuerst auf dem Jumphost einloggen und dann von da aus weiter verbinden:

OpenSSH bietet für diesen Zweck die hilfreiche ProxyJump Option an. Wir legen uns also einen entsprechende Eintrag in der Datei  .ssh/config in unserem Home Verzeichnis an:

Für den Jumphost aktivieren wir per default das Agent Forwarding, was uns das Herumhantieren mit SSH Keys erspart und unsere lokalen Keys von der Workstation über den Jumphost auch an die Rechner dahinter weiterreicht.

Der Eintrag StrictHostKeyChecking no für die Hosts hinter dem Jumphost ist der Tatsache geschuldet, dass wir in einem Ansible Run keine Möglichkeit haben, eventuelle Rückfragen von SSH bezüglich des HostKeys zu beantworten. Alternativ kann man auch einmal die entsprechende Verbindung mit dem Host manuell per ssh herstellen, so dass der Hostkey bereits lokal vorliegt und ein Login ohne Rückfragen möglich ist.

Tests

Jetzt sollte es möglich sein, direkt per ssh deploy@compute01 zum Beispiel auf den compute01 Host zu verbinden. Die Verbindung wird automatisch durch den Jumphost aufgebaut und unsere SSH Keys werden direkt weitergereicht.

Wir können jetzt unseren ersten Ansible Test starten, für den wir noch kein eigentliches Playbook benötigen:

Diese eine Zeile stellt die Verbindung zu jedem einzelnen Host her und führt dort das Ansible setup Modul aus, welches die sogenannten „Facts“ auf den Hosts einsammelt. Dieser Aufruf sollte keine Fehlermeldungen produzieren und eine Menge Output zu jedem Host ausgeben, auf den man dann später in den Playbooks zurückgreifen kann.

Im nächsten Teil dieser Serie werden wir dann ein tatsächliches Playbook aufbauen und dieses im weiteren Verlauf mit mehr Funktionen und Features ausstatten.

Patrick Dreker

Patrick arbeitet seit 2006 bei der teamix GmbH und bearbeitet dort die Themenfelder OpenStack, Cloud, Linux, Automatisierung und DevOps. Sein erster Linux Kernel war 1.2.13 und was Netscape und NCSA Mosaic waren, weiß er auch noch.

 
Kommentare

Noch keine Kommentare vorhanden.

Hinterlassen Sie einen Kommentar