Ansible
Kapitel 1 Ansible Playbook
Im Kapitel: Ansible Schritt für Schritt wurde unser Plan beschrieben. Dieses Kapitel 1 beginnt nun von Grund auf. Hier wird nun Schritt für Schritt Ansible erklärt, eingerichtet und ein 1. Playbook erstellt.
Hinweis
Beispiele und Code auf: Gitlab
Bitte beachten:
In dieser Dokumentenserie gehen wir von Zielumgebung Ubuntu 22.04.2 und Ansible 2.10 aus. Vereinzelt gehen wir auf Opensuse Leap 15.4 ein. Bei anderen Distributionen und Versionsstände können nachfolgende Beispiele u.U. nicht funktionieren.
Die Installation:
Um mit Ansible zu beginnen muss zunächst die notwendigen Software installiert werden. Unser Rechner basiert auf Ubuntu 22.04.2. Sie benötigen somit einen Rechner mit Ubuntu 22.04.2.
Bitte auf der Console als Benutzer root anmelden.
Bestätigen mit Y und die Installation beginnt.
apt install ansible
Das Ergebnis:
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following additional packages will be installed:
ieee-data python-babel-localedata python3-argcomplete python3-babel python3-certifi python3-dnspython
python3-jinja2 python3-jmespath python3-kerberos python3-libcloud python3-lockfile python3-markupsafe
python3-netaddr python3-ntlm-auth python3-packaging python3-pycryptodome python3-requests
python3-requests-kerberos python3-requests-ntlm python3-requests-toolbelt python3-selinux python3-simplejson
python3-tz python3-urllib3 python3-winrm python3-xmltodict
Suggested packages:
cowsay sshpass python3-sniffio python3-trio python-jinja2-doc python-lockfile-doc ipython3 python-netaddr-docs
python3-socks python-requests-doc
The following NEW packages will be installed:
ansible ieee-data python-babel-localedata python3-argcomplete python3-babel python3-certifi python3-dnspython
python3-jinja2 python3-jmespath python3-kerberos python3-libcloud python3-lockfile python3-markupsafe
python3-netaddr python3-ntlm-auth python3-packaging python3-pycryptodome python3-requests
python3-requests-kerberos python3-requests-ntlm python3-requests-toolbelt python3-selinux python3-simplejson
python3-tz python3-urllib3 python3-winrm python3-xmltodict
0 upgraded, 27 newly installed, 0 to remove and 2 not upgraded.
Need to get 28.4 MB of archives.
After this operation, 272 MB of additional disk space will be used.
Do you want to continue? [Y/n] Y
Damit ist die Installation von Ansbible abgeschlossen. Kompliziert war das nicht.
Ansible Basics
Was ist ein inventory?
Das Inventory in Ansible ist eine Datei oder eine Gruppe von Dateien, die Informationen über die Hosts enthält, auf denen Ansible-Playbooks ausgeführt werden sollen. Diese Informationen beinhalten die IP-Adressen oder Hostnamen der zu verwaltenden Hosts sowie zusätzliche Attribute wie z.B. Gruppenzugehörigkeit, Variablenwerte oder SSH-Verbindungsoptionen.
YAML verwendet eine einfache Syntax, die durch Einrückungen und Leerzeichen gekennzeichnet ist. Ein YAML-Dokument besteht aus einer Reihe von Schlüssel-Wert-Paaren, welche durch Doppelpunkte getrennt sind. Jeder Schlüssel-Wert-Paar beginnt mit dem Schlüssel, gefolgt von einem Doppelpunkt und dem Wert. Der Wert kann ein String, eine Zahl, ein Array, ein Objekt oder eine andere komplexe Struktur sein.
Oder um es ganz kurz zu sagen: Yaml ist eine „Liste“, welche weitere Listen und Attribute beinhaltet.
Hier ein kleines Beispiel als Host: (btw. das werden wir so nicht verwenden)!
host: mx5
system: Ubuntu
version: 22.04.2
network:
eth0:
ipv4:
- 123.123.123.5/24
- 123.123.124.5/24
ipv6:
- fe80::4827:43ff:fe91:d516/64
filesystem:
root:
size: 64G
type: ext
home:
size: 10G
type: xfs
In diesem Beispiel gibt es 15 Schlüssel-Wert-Paare.
- Der erste Schlüssel ist „host“ und der Wert ist „mx5“.
- Der zweite Schlüssel ist „system“ und der Wert ist „Ubuntu“.
- Der dritte Schlüssel ist „version“ und der Wert ist „22.04.2“
- Der vierte Schlüssel „network“ ist ein Objekt, das drei weitere Schlüssel-Wert-Paare enthält.
- Der achte Schlüssel „filesystem“ ist ebenfalls wieder ein Objekt mit 6 weiteren Schlüssel-Werte Paaren.
Jedes dieser Schlüssel-Wert-Paare ist durch Einrückung vom Elternschlüssel getrennt. Eine Liste an Werten kann man wie bei Schlüssel ipv4, mit „- „eingeleitet anfügen.
YAML kann auch verwendet werden, um Listen und komplexe Strukturen zu definieren. Zum Beispiel könnte eine Liste von Objektern (hier Hosts) wie folgt aussehen:
- host: mx1 system: openSuSe version: 15.4 network: eth0: ipv4: - 10.10.10.1/24 - 10.120.10.1/24 ipv6: - fe80::1827:43ff:fe90:d516/64 filesystem: root: size: 64G type: ext home: size: 10G type: xfs - host: mx5 system: Ubuntu version: 22.04.2 network: eth0: ipv4: - 10.10.10.5/24 - 10.120.10.5/24 ipv6: - fe80::4827:43ff:fe91:d516/64 filesystem: root: size: 64G type: ext home: size: 10G type: xfs
In diesem Beispiel gibt es eine Liste von zwei Objekten, die jeweils die Informationen eines Servers enthalten.
YAML ist sehr flexibel und kann auf unterschiedliche Weise verwendet werden, einschließlich der Definition von Konfigurationen, der Definition von Datenstrukturen und der Definition von Testspezifikationen. YAML-Dateien können auch von anderen Anwendungen gelesen und geschrieben werden, was sie zu einem nützlichen Austauschformat macht.
Das Inventory kann in verschiedenen Formaten vorliegen, darunter INI-Dateien, YAML-Dateien oder dynamische Inventarquellen wie Cloud-Provider-APIs oder CMDBs. Die INI-Formatierung hat dabei eine lange Historie und ist ein einfaches textbasiertes Format, welches in älteren Ansible-Versionen bevorzugt wurde. Das YAML-Format ist hingegen moderner und flexibler, da es ein leicht lesbares und strukturiertes Datenformat ist.
Mithilfe von Gruppenzugehörigkeiten und Variablenzuweisungen können Hosts innerhalb des Inventars in logische Gruppen unterteilt werden, um sie entsprechend zu konfigurieren. Das erleichtert insbesondere die Wartung und Skalierung von großen Infrastrukturen, da die gewünschten Konfigurationen über eine Gruppenzuweisung auf eine Vielzahl von Hosts angewendet werden können.
Das Inventory wird üblicherweise als Eingabe für Playbooks und Ad-hoc-Befehle verwendet, um eine gezielte Konfiguration von Hosts oder Gruppen von Hosts zu ermöglichen. Es ist wichtig, dass das Inventory immer auf dem neuesten Stand gehalten wird, um die korrekte Verwaltung der Hosts zu gewährleisten.
Ansible Basics
Was ist ein Playbook
Ansible Playbooks sind eine zentrale Komponente von Ansible, mit der Automatisierung von IT-Infrastruktur durchgeführt wird. Ein Playbook ist eine Datei, die eine Abfolge von Schritten definiert, die von Ansible auf den verwalteten Hosts ausgeführt werden sollen. Diese Schritte werden als Aufgaben (tasks) bezeichnet und können von einfachen Shell-Befehlen bis hin zu komplexen Deployment- oder Konfigurationsaufgaben reichen.
Ein Playbook besteht aus einer YAML-Datei und enthält eine oder mehrere Plays. Ein Play definiert eine Gruppe von Aufgaben, die auf einer bestimmten Gruppe von Hosts ausgeführt werden sollen. Jede Aufgabe enthält eine spezifische Aktion, die von Ansible auf dem Host ausgeführt werden soll, sowie zusätzliche Optionen wie zum Beispiel die Nutzung von Variablen.
Playbooks ermöglichen es, komplexe Infrastrukturkonfigurationen einfach und reproduzierbar zu automatisieren, da sie eine einzige Quelle der Wahrheit für die gesamte Konfiguration bereitstellen. Mit Hilfe von Playbooks kann man also sehr schnell eine Vielzahl von Konfigurationsänderungen und Updates auf vielen Hosts durchführen. Zusätzlich ermöglichen Playbooks eine automatisierte und dokumentierte Wartung von Systemen, was insbesondere in größeren Infrastrukturen eine enorme Erleichterung darstellt.
Zusätzlich zu den Aufgaben, die in einem Playbook definiert sind, können Playbooks auch Variablen, Schleifen, Bedingungen und andere Funktionen enthalten, die eine komplexe Logik für die Automatisierung bereitstellen. Insgesamt bieten Playbooks eine leistungsstarke Möglichkeit, um komplexe Aufgaben in einer einheitlichen und einfach zu verwaltenden Weise zu automatisieren.
Ansible Basics
Was sind Variablen und worin unterscheiden sich globale, Inventar, Faken, Benutzer und Rollen Variablen?
Variablen in Ansible sind eine Möglichkeit, Werte zu speichern und in verschiedenen Teilen des Playbooks wiederzuverwenden. Es gibt verschiedene Arten von Variablen in Ansible, einschließlich globaler Variablen, Inventarvariablen, Faktoren, Benutzervariablen und Rollenvariablen. Diese Variablen können verwendet werden, um Konfigurationsparameter zu definieren, Host-spezifische Informationen zu speichern oder um Entscheidungen in Playbooks basierend auf bestimmten Bedingungen zu treffen..
Globale Variablen sind vordefinierte Variablen in Ansible, die von jeder Rolle oder jedem Playbook verwendet werden können. Beispiele dafür sind ansible_user
, ansible_ssh_private_key_file
oder ansible_python_interpreter
.
Inventarvariablen sind Variablen, die direkt im Inventar definiert werden und auf den jeweiligen Hosts verwendet werden können. Hierbei wird meist eine INI- oder YAML-Datei verwendet, um das Inventar zu definieren.
Faktoren sind Informationen, die Ansible über das System des verwalteten Hosts sammelt und als Variablen bereitstellt. Beispiele hierfür sind die Architektur, Betriebssystem, Speicherplatz oder Netzwerkschnittstellen.
Benutzervariablen werden in den Playbooks definiert und sind auf die Ebene des jeweiligen Plays oder der jeweiligen Rolle beschränkt. Diese können auf spezifische Hosts oder Hostgruppen angewendet werden und ermöglichen somit eine granulare Steuerung der Konfiguration.
Rollenvariablen sind spezielle Variablen, die in Ansible-Rollen definiert werden und zur Konfiguration von Rollen verwendet werden können. Hierbei wird typischerweise eine defaults/main.yml
-Datei in der Rollenstruktur verwendet, um Variablen zu definieren, die von allen Plays in der Rolle verwendet werden.
Insgesamt bieten Variablen in Ansible eine flexible Möglichkeit, um Informationen zu speichern und wiederzuverwenden, um komplexe Automatisierungsaufgaben durchzuführen. Variablen ermöglichen es, Konfigurationsparameter einfach und zentral zu verwalten und somit eine Wartung der Infrastruktur zu vereinfachen.
Gruppen lassen sich Hosts in Gruppen zusammen Fassen. Ein gutes Beispiel wäre z.B. VM versus physische Server oder konkret. System mit und Systeme ohne vlan Konfiguration. Über Gruppen können verschachtelt werden, so kann z.B. ein Gruppe speziell für eine Anwendung z.B. WordPress als Child (Untermenge) von Webserver sein. Dies ist aber nicht die einzige Möglichkeit solche Unterscheidungen zu treffen. Gerade wenn Anwendungsfälle sehr ähnlich sind, kann eine Unterscheidung / Fallunterscheidung im Tasks selbst sinnvoll sein.
In diesem Dokument wird genau der Fall eintreten, dass die bisherige Struktur und Planung nochmals angepasst wird.
Unser erstes Playbook
Nach der ganzen Theorie geht es nun an die Praxis.
;-) Falls euch jetzt schon der Kopf raucht…. keine Sorge in den folgenden Kapiteln gehen wir das alles nochmals Schritt für Schritt durch. Der Umstieg auf Ansible ist nicht ganz einfach, aber es lohnt sich.
Was benötigen wir also um los zu legen?
Theoretisch nur eine Datei: das Playbook. Wir trennen es aber von Anfang an und erstellen zunächst eine Inventar Liste. Eine Liste unsere Zielsysteme. Zudem ein Playbook mit den Anweisungen. Später trennen wir es auf und führen bereits Rollen ein.
Das 1. Playbook wird einfach. Wir verbinden uns per SSH auf das Zielsystem und geben eine Debug Meldung aus.
Das Inventory
Fürs Erste reicht uns ein Zielsystem. In diesem Beispiel wird ein host: mx5.weiss-system.de festgelegt.
Kurzname mx5 FQDN mx5.domain.tld. In dieser Beitragserie verwenden wir konsquent das yaml Format. Das Inventory könnte auch als im ini Format angelegt werden.
domain.tld oder allgemein der Wert von ansible_host: Muss natürlich an die Zielumgebung angepasst werden. IP Adresse geht natürlich auch. Diese Inventory Datei heisst: hosts
all:
vars:
ansible_user=’root‘
ansible_become=yes
ansible_python_interpreter=’/usr/bin/env python3′
hosts:
mx5:
ansible_host: mx5.domain.tld
Unter
- all:
Wird zunächst alles zusammen gefasst. Es ist die oberste ebene.
- vars
Hier können allgemeingültige Variablen stehen. In unserem Beispiel, unter welchem Benutzer es ausgeführt werden soll. Sprich mit welchem Benutzer sich ansible ans Zielsystem verbindet. Python Interpreter welcher genutzt werden soll.
- hosts:
Danach folgt eine Liste der Hosts. In unserem Beispiel führen wir noch keine Rollen ein. Entsprechend steht bei der Ansible Ausgabe weiter unten „ungrouped“.
hosts: definiert also, welche Art von Objekte als Liste folgen. (Hier könnte auch eine Gruppe stehen, dazu später mehr)
- mx5:
Hier folgt nun der wirkliche Rechner. Der Host mx5. Dieser wiederum hat das Attribut ansbible_host: erhalten, worüber sich ansible zum Zielsystem verbindet.
-> Würden wir auf die Angabe ansible_host: verzichten, müsste „mx5“ auf dem System aufgelöst werden können.
Sprich, ein
ssh root@mx5
sollte euch zum Zielsystem verbinden.
Hier kann nun geprüft werden, ob ansible mit unserem Inventory einverstanden ist.
ansible-inventory --graph -i host
Ergebnis:
@all:
|--@ungrouped:
| |--mx5
Das Playbook
Das erste Playbook enthält nun sowohl den Play Teil, welcher zunächst die Hosts definiert* und enthält zusätzlich die Tasks zur Ausführung der Aufgabe: Gib eine Debug Meldung aus.
*Aus der Menge der Zielsysteme in hosts wird selektiert, welche host angesprochen / verarbeitet werden sollen.
Wie legen die Datei main.yml an. Zunächst wird über:
- host: mx5
Der Host mx5 festgelegt. Statt mx5 könnte eine Rolle oder all für alle Hosts stehen. Rollen haben wir noch nicht definiert: Siehe Ausgabe ansible-inventory oben. „ungrouped“
Die definierten Werte:
become: "true" become_user: root
Sind allgemeingültig, gelten also für alle Hosts, welche in diesem Playbook verarbeitet werden. Danach folgt unser 1. Tasks. -name gibt beim Ausführen des Playbooks an, welcher Tasks gerade bearbeitet wird. Es folgt die Aufgabe:
debug: msg: "Hallo Welt."
--- - hosts: mx5 become: "true" become_user: root tasks: - name: Unser erste Aufgabe debug: msg: 'Hallo Welt'
Die Ausführung:
ansible-playbook -i hosts main.yml
Das Egebnis:
PLAY [mx5] ****************************************************************************************************************************************************************************************************
TASK [Gathering Facts] ****************************************************************************************************************************************************************************************
fatal: [mx5]: UNREACHABLE! => {„changed“: false, „msg“: „Failed to connect to the host via ssh: ssh: Could not resolve hostname mx5.domain.tld: Name or service not known“, „unreachable“: true}PLAY RECAP ****************************************************************************************************************************************************************************************************
mx5 : ok=0 changed=0 unreachable=1 failed=0 skipped=0 rescued=0 ignored=0
failed? Was ging schief.
Der Hostname mx5 und auch nicht der definierte ansible_hosts: mx5.domain.tld kann aufgelöst werden.
in der /etc/hosts trage ich also die IP Adresse und Hostname ein:
192.168.115.1 mx5.dmain.tld
Mit dem erneuten ausführen obigen Befehls folgt nun diese Ausgabe:
ansible-playbook -i hosts main.yml PLAY [mx5] **************************************************************************************************************************************************************************************************** TASK [Gathering Facts] **************************************************************************************************************************************************************************************** ok: [mx5]
TASK [Unser erste Aufgabe] ************************************************************************************************************************************************************************************
ok: [mx5] => {
"msg": "Hallo Welt"
}
PLAY RECAP ****************************************************************************************************************************************************************************************************
mx5 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Was passiert hier?
Als erster wird der Play ausgeführt. Hier wurde der Host mx5 definiert und nur dieser wird verarbeitet.
PLAY [mx5]
Play also fasst die Systeme zusammen wfür welche die nachfolgenden Tasks ausgeführt werden sollen.
TASK [Gathering Facts]
Dieser Taks wird immer ausgeführt. Dieser baut eine Verbindung zum
Zielsystem per ssh auf und ermittelt Informationen zum System. Diese können in den Playbooks / Tasks verwendet werden.
TASK [Unser erste Aufgabe]
Das ist nun unser Task mit der Debug Meldung.
Diese Meldung wird auf dem Zielsystem, hier mx5, erzeugt und im JSON Format zurück gegeben.
PLAY RECAP
Hier gibt Ansible eine Übersicht der ausgeführten Tasks, Erfolge, Änderungen , Erreichbarkeit, Fehlschläge, Übersprungene Tasks, etc. aus.
Das war das 1. Playbook mit einer einfachen Debug Meldung.
Die zugehörigen Dateien sind im Gitlab: Tag: Ansible-Kapitel-01