20.012016

Serverautomatisierung für Entwickler mit Ansible

Wer bereits Erfahrung mit Chef, Puppet oder Salt gesammelt hat merkt schnell, dass um die entsprechenden Produkte zu vewenden lange Toolchains, Service-Infrastruktur und viel Erfahrung nötig sind, um Serververwaltung tatsächlich zu vereinfachen.

Ich möchte heute einen kleinen Crashkurs für Ansible geben: ein auf Python und SSH aufsetzendes Tool, dass genauso machtvoll wie die oben genannten Werkzeuge geschwungen werden kann, dabei aber sowohl einsteigerfreundlich, flexibel als auch performant ist.

Grundvoraussetzung für Ansible ist, dass ihr in der Lage seit, eine SSH-Verbindung zu euren Zielservern aufzubauen. Preferriert wird Autentifizierung mittels Public-Keys, die über den ssh-agent einmalig geladen werden. So werden keine Passwörter gespeichert und übertragen.

Stellt sicher, dass ihr euch auf die Zielrechner mittels SSH verbinden könnt (für die folgenden Beispiele nehmen wir an, ein SSH-Server läuft unter der IP 192.168.2.11 und der User "user" existiert):

ssh user@192.168.2.11

Funktioniert alles wie erhofft, so installieren wir Ansible

Jetzt legen wir uns ein Host-Inventar an. Hierbei handelt es sich um eine entweder manuell, oder automatisch gepflegte Sammlung aller Server, die mit Ansible verwaltet werden soll.

Für unsere Zwecke genügt eine Textdatei, in der Zeilenweise alle Server aufgelistet werden

[~/hosts]
192.168.2.11

Nun sind wir auch schon bereit einen ersten kleinen Test zu starten:

ansible all -i ~/hosts -m ping -u user

Dieser Befehl macht nichts anderes, als sich auf alle in der Datei ~/hosts gelisteten Server als User [username] zu verbinden, und dort ein kleines Python-Skript zu starten, welches mit "Pong" antwortet.

Erhaltet ihr die Meldung

192.168.2.11 | UNREACHABLE! => ...

so prüft erneut, ob die SSH-Verbindung auch funktioniert.

Ein weiterer häufiger Fehler kann das Fehlen einer Python2 Umgebung auf den Host-Rechnern sein. Diese benötigt Ansible, da aus den übergebenen Befehlen (und auch später "Playbooks") Python-Skripte generiert werden, welche auf dem Zielsystem ausgeführt werden.

Als Notlösung kann Ansible auch direkt Befehle über SSH aufrufen, um etwa ein minimales Bootsprapping durchzuführen:

ansible all --become -m raw -a "apt-get install --yes --force-yes python2 python-simplejson"

Anweisungen führt Ansible über Module aus. Das Ping-Modul haben wir gerade schon gesehen. Ebenso das raw-Modul. Ein weiteres, sehr häufig verwendetes Modul ist das "command"-Modul, welches erlaubt, Kommandozeilenbefehle auszuführen. Im Gegensatz zum raw-Modul passiert hierbei der Aufruf als Teil eines Python-Skriptes, was die präferierte Methode ist:

ansible all -i ~/hosts -m command --a whoami -u user
192.168.2.11 | SUCCESS | rc=0 >>
user

Genauso wie bei anderen Verwaltungstools hat auch Ansible eine große Sammlung interner Module sowie eine aktive Community, die für fast jeden Anwendungsfall bereits ein Modul bereitstellt.

Ob nun das Erstellen von Usern oder Verzeichnissen, das Installieren und Konfigurieren von Anwendungen oder auch einfach nur Starten und Stoppen von Diensten - für alles gibt es das passende Modul.

Der "immediate"-Modus ist zwar gut, um schnell Logik auf vielen Servern auszuführen, allerdings ist er ungeeignet, um komplexe Arbeitsabläufe durchzuführen.

Um einen Arbeitsablauf zu beschreiben werden in Ansible "Playbooks" geschrieben, die Modul-Befehle zusammenfassen. Playbooks sind Arbeitsanweisungen, die in yaml geschrieben werden. Ein einfaches Playbook könnte etwa so aussehen:

[~/playbook.yaml]
---
# initialize server environment
- name: ensure basic tools are installed
 package: name={{ item }} state=present
 become: yes
 with_items:
 - htop
 - iotop
 - vim-minimal
 - git
 - curl
 - nss-mdns
 - avahi

- name: enable avahi
 service: name=avahi-daemon enabled=yes state=started
 become: yes

Wir stellen sicher, dass eine Reihe an Tools installiert ist und starten dann den avahi-daemon, falls dieser noch nicht läuft.

Module (wie hier das Package und service-Modul) sind in Ansible wenn möglich so geschrieben, dass Sie idempotent sind. Sie können unabhängig vom aktuellen Serverzustand genutzt werden, um den Server in einen definierten Zielzustand zu bringen.

Um das "playbook" auszuführen benötigen wir einen neuen Befehl

ansible-playbook -i ~/hosts ~/playbook.yaml -u user

Ansible abstrahiert dass erlangen von erweiterten Rechten auf dem Zielserver über das Argument "become". Become nutzt "sudo", "su" und weitere Möglichkeiten der Priviledge-Escalation, falls für einen Befehl die entsprechende Option gesetzt wurde. Hierbei kann become auch sowohl in den Playbooks, über den playbook-Aufruf oder über Variablen gesteuert werden.

Für Umfangreiche Serververwaltungsprojekte empfiehlt es sich ein eigenes Projektverzeichnis anzulegen, in dem dann für verschiedene Server-Rollen Aufgaben, Templates und Variablen definiert werden können. Hier empfehle ich aber einfach mal einen Blick in die Doku zu werfen.

Ich hoffe ihr habt jetzt schon einen Haufen Ideen, für die Ansible verwendet werden kann. Ich nutze Ansible beispielsweise um einen RaspberryPi-Cluster zu verwalten.