Einführung in Ansible
Im Laufe meiner Jahre im Bereich der Automatisierung, habe ich bereits so einige Software gesehen und genutzt. Seit einiger Zeit ist in diesem Metier Ansible immer präsenter geworden. Dies also einmal selber zu testen, lag natürlich auf der Hand. Eingangs bin ich davon ausgegangen, dass das eine längere Geschichte wird, zumal ich das Thema mit dem vorangegangenen Thema "ESX auf Raspberry Pi" kombinieren wollte. Tatsächlich aber sind die Erfolge, welche man mit Ansible erzielt, enorm schnell und einfach.
Mir ist jetzt klar, warum Ansible so beliebt ist und scheinbar auch immer gefragter wird. Keine komplizierte Installation von Infrastrukturen mit massiven Overhead, simple Arbeitsweise mit bereits vorhandenen Mitteln, leicht verständliche Umsetzung bei der Automatisierung. Eigentlich das, was wir immer in diesem Bereich wollten. Ich bin in der Vergangenheit Leuten begegnet, welche sich ihre Automatisierung komplett selber mittels Shellscripten gebaut haben. Ansible schlägt meines Erachtens bezüglich des Minimalismus ein wenig in die Kerbe, macht aber am Ende vieles mehr und vor allem richtig.
Das fängt bei der Installation auf einem Debian System (bei mir natürlich wieder ein Pi4) an:
apt install ansible
Fertig. Die Basiskonfiguration (/etc/ansible/ansible.cfg) erlaubt es bereits durchzustarten. Natürlich müssen noch die per Ansible zu verwalteteten Systeme in der /etc/ansible/hosts eingetragen, und der SSH Key des Ansible-Servers (Controller) verteilt werden. Ansible arbeitet nämlich einfach und simpel per SSH. Die Hosts Datei sieht bei mir folgendermaßen aus:
[esx]
192.168.1.20
[vms]
192.168.1.240
192.168.1.140
Zwei Hostgruppen, einmal mit den ESX Hosts (bei mir natürlich nur einer) und die VMs, welche auf dem Host laufen. Damit der Zugriff per Ansible bzw. per SSH funktioniert, muss auf dem Controller ein Schlüssel erzeugt und auf die Hosts kopiert werden:
cd /root/.ssh
ssh-keygen -b 4096
ssh-copy-id -i id_rsa.pub root@192.168.1.20
In diesem Beispiel habe den Schlüssel zunächst nur auf den ESX Host kopiert. Das ist im Prinzip auch alles. Damit lassen sich auf dem ersten Host Ansible Kommandos und natürlich auch Playbooks starten.
Ping auf alle Host Systeme:
Shell-Befehl auf eine Host Gruppe:
Playbooks
Wenn man jahrelang normale Scripte/Programme in sämtlichen Sprachen entwickelt hat, sind Playbooks ein zweischneidiges Schwert. Auf der einen Seite sind diese sehr simpel aufgebaut und folgen einer gewissen Logik, auf der anderen Seite muss man sich als alteingesessener Scripter zunächst umgewöhnen. Das allerdings geht recht schnell, sobald man einmal das Prinzip von Playbooks begriffen hat. Playbooks beinhalten einzelne Plays, welche im Normalfall auf einzelnen Hosts ausgeführt werden, die wiederum Tasks und Einzelschritte besitzen. Wichtig: Es lassen sich nicht beliebig viele Befehle untereinander definieren. Ansible erwartet hier eine saubere Trennung.
Beispiel um auf einem Host einen Ordner anzulegen:
- name: Create a folder on remote system
hosts: 192.168.1.140
remote_user: root
vars:
folder: meep
tasks:
- name: Execute command
command: mkdir /tmp/{{ folder }}
Ausgeführt wird dies mittels
ansible-playbook mkdir.yml
Die interne Variable "folder" kann übrigens auch per Argument mitgegeben werden:
ansible-playbook mkdir.yml -e "folder=meep2"
Die Mitgabe von Variablen beim Aufruf des Playbooks, überschreibt übrigens intern gesetzte Variablen. In diesem Beipspiel würde der Ordner "meep2" erstellt werden, obwohl im Playbook die Variable als "meep" deklariert wurde.
Variablen von Play zu Play durchreichen
Zugegeben, da gibt es ein paar Stolpersteine, welche ich auch brav mitgenommen habe. Soweit ich es bis jetzt nachvollziehen konnte, müssen Variablen, welche an einen anderen Play übregeben werden sollen, vorab fest definiert sein. Ein einfaches "register" einer Ausgabe reicht nicht. Die Lösung ist hier set_fact. Variablen eines anderen Plays können mittels
"{{ hostvars['hostdesplays']['namedervariable'] }}"
angesprochen werden. Beispiel:
- name: Dummy Play
hosts: localhost
tasks:
- name: Set a variable
set_fact:
vmip: 192.168.1.140
- name: Some magic on another host
hosts: "{{ hostvars['localhost']['vmip'] }}"
tasks:
- name: Run a command
command: uname -a
register: result
- debug:
msg: "{{ result.stdout }}"
Die Variable (die IP eines Hosts) wird hier sogar verwendet, um zu definieren, wo das zweite Play ausgeführt werden soll.
Ausgabe:
Ausblick
Das war es eigentlich auch schon an Basics. Im nächsten Artikel wird dann mein Script zur Erstellung von VMs auf dem ESX Host, mit Ansible verheiratet...