Hallo zusammen,
Vom 24.3. - 27.3.2026 haben wir an einer Schulung zum Thema Ansibel mit
dem Dozenten Adrran Sorge teilgenommen.
Hier sind meine subjektiven Mitschriften und Erfahrungen aus dem Kurs.
Keine Garantie für Richtigkeit oder Vollständigkeit:
Was ist Ansible
Ansible ist eine Sammlung von Python Kommandos, die zwar lokal laufen,
aber auf Zielrechnern, sofern dort Python installiert ist, Befehle
ausführen können. Dadurch sind wir in der Lage komplette Rechnersysteme
inklusiver Konfiguration von Servern zentral zu steuern. Die Scripte
werden via einem Git-Repository in sogenannten Playbooks in einer
Yaml-Struktur verwaltet. Dem Playbook Kommando werden dann diese
Playbooks übergeben und im Hintergrund arbeiten dann mächtige
Bibliotheken, die als Open Source zur Verfügung stehen, die gewünschten
Aufgaben, entsprechend der Playbooks ab. Die Dokumentation dieser
Bibliotheken (im Ansible Sprech Module genannt) befindet sich hier:
Ansible Community | Ansible documentation
Im Folgenden gehen wir durch die Themen durch, so wie wir sie zeitlich
durchgearbeitet haben:
Schulungstag 1
Git
Zuerst mal ein paar Vokabeln:
Repository: gemanagte Ordnerstruktur
Origin: Standardname für das Default Upstream Repo
HEAD: Aktueller Punkt im Graphen, auf dem das Repo zeigt (das
Stimmt, ich habe es mit Perplexity gecheckt, es muss also nicht der
letzte (oberste) Datenstand sein).
Git speichert nicht in den Versionen den kompletten Datenstand, sondern
(ähnlich wie bei der Blockchain), es werden nur die Änderung
gespeichert.
Daher sollten keine Binärdateien hochgeladen werden. Und auch möglichst
wenig Bilder, vor allem, wenn die ständig wechseln.
Es gibt LFS (Large File System) bei Git dafür.
Hier eine bewährte Git Staging Strategie:
Auf dem Main Branch liegt der Produktionscode. Auf dem Integration
Branch liegt der zu testende Code. Von ihm werden zur Entwicklung
einzelne Feature Branches abgezweigt.
Es gibt neben .gitignore auch die .gitkeep Datei. Die legt man in leere
Ordner rein, wenn man möchte, dass diese mit nach Github hochgeladen
wird.
In der .gitignore kann man auch bestimmte Dateien negieren. z.B.:
!/drv/.gitkeep
YAML
YAML ist ähnlich wie JSON eine Konfigurations-Sprache. Im Unterschied zu
JSON lebt sie von Einrückungen anstelle von Klammer-Strukturen. Dies hat
Vor- und Nachteile. Details zu YAML siehe hier: https://yaml.org
Ansible
Ansible ist in Python geschrieben. Auf dem ausführenden Server werden
Python Scripte geschrieben.
Auf Windows Systemen ist Powershell genug.
Hie ein paar Vokabeln:
Modul - Block der dafür zuständig ist, auf dem Zielsystem Aktionen
auszuführenCollection - Sammlung von Modulen
Task -- Instanz eines Moduls
Host -- Host, dem Variablen zugewiesen werden können
Inventar - Sammlung von Hosts
Playbook - Liste von Tasks, die auf einer Host(Gruppe) ausgeführt
werden sollen
Details:
Ansible Community | Ansible documentation
Beispiele einer YAML Datei:
Entnommen aus:
https://docs.ansible.com/projects/ansible/latest/collections/community/general/ipa_pwpolicy_module.html#examples
- name: Modify the global password policy
community.general.ipa_pwpolicy:
maxpwdlife: '90'
minpwdlife: '1'
historylength: '8'
minclasses: '3'
minlength: '16'
maxfailcount: '6'
failinterval: '60'
lockouttime: '600'
ipa_host: ipa.example.com
ipa_user: admin
ipa_pass: topsecret
Selbstgeschriebenes Beispiel:
---
http_port: 80
schulungs_ids:
- schulungs_id: v991423
lieblingsfarbe: blau
schuhe:
groesse: 42
farbe: schwarz
nachbarn:
- Dr. Snuggles (Küken)
- Silke SIlberfisch
- schulungs_id: "andreas"
lieblingsfarbe: "blau"
schuhe:
groesse: 40
farbe: "schwarz"
nachbarn:
- "Irgend Einer"
- "Noch Jemand"
Schulungstag 2
Wir wurden in vier Gruppen aufgeteilt mit folgenden Aufgaben:
●p1-1: Installation von Apache und Kopieren einer Datei, die dann im
Browser angezeigt werden soll
●p1-2: Installation nginx und Kopieren einer Datei, die dann im Browser
angezeigt werden soll
●Je zwei Gruppen pro Server: Apache auf 80 und nginx auf 8080
Unsere Aufgabe war es, das innerhalb der index.html das Wort „Welcome"
zu ersetzen durch „Ansible-101: Projekt 1"
Nachdem wir die Git-Schwierigkeiten gelöst hatten um den Code mit
unserem Ansible Server (Red Had Linux Server) synchronisieren zu können
(ssh Key rüber kopieren mit „ssh-copy-id ansiplab2.plab.kern.drv.drv")
haben wir die Aufgabe wie folgt erledigt:
[v991423@ansiplab1.plab.kern.drv.drv (el9) [0] |
~/git/ansible-101-26 ]
$ ansible-playbook -i inventory.yml httpd.yml --extra-vars
"ansible_remote_tmp=/var/tmp/.ansible-${USER}/tmp"
[WARNING]: Found variable using reserved name: become_flags
PLAY [Webserver auf Remote Host installieren]
********************************************************************************************************************
TASK [Gathering Facts]
*******************************************************************************************************************************************
ok: [ansiplab2.plab.kern.drv.drv]
TASK [Paketliste aktualisieren]
**********************************************************************************************************************************
ok: [ansiplab2.plab.kern.drv.drv]
TASK [Webserver starten und aktivieren]
**************************************************************************************************************************
ok: [ansiplab2.plab.kern.drv.drv]
TASK [kopiere index]
*********************************************************************************************************************************************
changed: [ansiplab2.plab.kern.drv.drv]
PLAY RECAP
*******************************************************************************************************************************************************
ansiplab2.plab.kern.drv.drv : ok=4 changed=1 unreachable=0 failed=0
skipped=0 rescued=0 ignored=0
[v991423@ansiplab1.plab.kern.drv.drv (el9) [0] |
~/git/ansible-101-26 ]
$ curl ansiplab2.plab.kern.drv.drv:80
<body>
<h1>Ansible-101: Projekt 1</h1>
Httpd.yml:
---
- name: Webserver auf Remote Host installieren
hosts: webserver
become: yes
vars:
package_name: httpd
become_flags: -i
tasks:
- name: Paketliste aktualisieren
ansible.builtin.dnf:
name: "{{ package_name }}"
state: present
- name: Webserver starten und aktivieren
ansible.builtin.service:
name: "{{ package_name }}"
state: started
enabled: yes
- name: kopiere index
ansible.builtin.copy:
src: ~/git/ansible-101-26/index.html
dest: /var/www/html/
owner: apache
group: apache
Inventory.yml
all:
children:
webserver:
hosts:
ansiplab2.plab.kern.drv.drv: # Zielserver
weitere Ansible Vokabeln
- Conditionals - Bedingungen, die zur Laufzeit ausgewertet werden
- Rolle - Objekt/Container/Klasse welche mehrere Tasks zusammenfasst
und wiederverwendbar macht - Jinja2 Templates - Templates mit Variablen und if Bedingungen
- Tags - Ermögliht es Teile von Playbooks auszuführen
- Collections - Sammlung von Rollen, Modulen, Plugins
Die When-Liste bei den Conditionen ist eine UND-Verknüpfung
Ansible-galaxy - Lädt Rollen und Collections runter
Ansible-galaxy role init test <- lädt die Ordnerstruktur init in den
Ordner Test runter
https://jinja.palletsprojects.com/en/stable/templates
Mit lookup können Passwörter in die Templates eingefügt werden
Schulungstag 3
Aufgabe: Wir sollen yml Dateien erstellen, die auf einem Zielserver die
Zertifikate für eine Webseite anlegen
Funktionierendes Ergebnis:
Im Ordner roles/generate_ssl/tasks liegt die Datei main.yml mit
folgendem Inhalt:
---
- name: Erstelle private Verzeichnis
ansible.builtin.file:
path: "{{ ssl_path }}private/"
state: directory
mode: '0755'
- name: Generate an OpenSSL private key with the default values (4096
bits, RSA)
community.crypto.openssl_privatekey:
path: "{{ private_key_path }}"
- name: Generate an OpenSSL Certificate Signing Request
community.crypto.openssl_csr:
path: "{{ ssl_path
}}[www.ansible.com.csr](http://www.ansible.com.csr)"
privatekey_path: "{{ private_key_path }}"
common_name: [www.ansible.com](http://www.ansible.com)
- name: Generate a Self Signed OpenSSL certificate
community.crypto.x509_certificate:
path: "{{ ssl_path }}ansible.com.crt"
privatekey_path: "{{ private_key_path }}"
csr_path: "{{ ssl_path
}}[www.ansible.com.csr](http://www.ansible.com.csr)"
provider: selfsigned
selfsigned_not_after: "+30m"
force: true
- name: Get certificate information
community.crypto.x509_certificate_info:
path: "{{ ssl_path }}ansible.com.crt"
register: result
- ansible.builtin.debug:
msg: "Läuft ab: {{ result.not_after }}"
Im Hauptordner liegt die Datei generate_ssl.yml mit folgendem Inhalt:
---
- name: Webserver auf Remote Host installieren
hosts: webserver
become: yes
vars:
package_name: httpd
become_flags: -i
private_key_path: "/etc/ssl/private/{{ inventory_hostname }}.pem"
ssl_path: /etc/ssl/
roles:
- generate_ssl
Diese ruft die main.yml im Verzeichnis roles/generate_ssl/tasks auf und
führt sie als Task aus.
Ergebnis:
Wir rufen die Dateien wie folgt auf:
[v991423@ansiplab1.plab.kern.drv.drv (el9) [0] |
~/git/ansible-101-26 ]
$ ansible-playbook -i inventory.yml generate_ssl.yml --extra-vars
"ansible_remote_tmp=/var/tmp/.ansible-${USER}/tmp"
[WARNING]: Found variable using reserved name: become_flags
PLAY [Webserver auf Remote Host installieren]
**************************************************************************************************************************
TASK [Gathering Facts]
*************************************************************************************************************************************************
ok: [ansiplab2.plab.kern.drv.drv]
TASK [generate_ssl : Erstelle private Verzeichnis]
*********************************************************************************************************************
ok: [ansiplab2.plab.kern.drv.drv]
TASK [generate_ssl : Generate an OpenSSL private key with the default
values (4096 bits, RSA)]
*************************************************************************
ok: [ansiplab2.plab.kern.drv.drv]
TASK [generate_ssl : Generate an OpenSSL Certificate Signing Request]
**************************************************************************************************
ok: [ansiplab2.plab.kern.drv.drv]
TASK [generate_ssl : Generate a Self Signed OpenSSL certificate]
*******************************************************************************************************
changed: [ansiplab2.plab.kern.drv.drv]
TASK [generate_ssl : Get certificate information]
**********************************************************************************************************************
ok: [ansiplab2.plab.kern.drv.drv]
TASK [generate_ssl : ansible.builtin.debug]
****************************************************************************************************************************
ok: [ansiplab2.plab.kern.drv.drv] => {
"msg": "Läuft ab: 20260326085052Z"
}
PLAY RECAP
*************************************************************************************************************************************************************
**********ansiplab2.plab.kern.drv.drv : ok=7 changed=1
unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[v991423@ansiplab1.plab.kern.drv.drv (el9) [0] |
~/git/ansible-101-26 ]
Auf dem Zielserver sehen wir:
[v991423@ansiplab2.plab.kern.drv.drv (el9) [0] | /etc/ssl ]
$ sudo openssl x509 -in ansible.com.crt -noout -enddate
notAfter=Mar 22 14:26:49 2036 GMT
Weitere Infos:
Community.Crypto --- Ansible Community
Documentation
https://docs.ansible.com/projects/ansible/latest/collections/community/crypto/
Good Practices for Ansible -
GPA
Handlers
Ist so eine art Unterprogramm. Mit Notify wird das nur dann ausgeführt,
wenn eine Veränderung stattgefunden hat.
Handlers werden immer am Ende eines Plays ausgeführt (auch wenn das
Notify früher steht). Mit Meta Modulen /Flush Handler kann man die
Handler auch zu einem anderen Zeitpunkt starten.
Handlers: running operations on change --- Ansible Community
Documentation
https://docs.ansible.com/projects/ansible/latest/playbook_guide/playbooks_handlers.html
Linter
Dnf install yamllint.noarch python3-ansible-lint.noarch
Damit kann man die Dateien auf Syntaxprobleme überprüfen
System Rollen
Red Hat Enterprise Linux (RHEL) System Roles - Red Hat Customer
Portal
dnf install cockpit
Podman
Podman-compose.yml liegt in den Templates
Über systemd wird dann der Container gestartet
Man kann podman auch über das Container Module in Ansible starten
Mit dem k8s Module arbeiten.
Tag 4
Ansible Automation Platform
Zentrales Management von Playbooks als Dashboard
Ich sehe Ähnlichkeiten zu Jenkins
Man kann die Playbooks dort ausführen oder schedulen.
Debugging
Fazit
Die Schulung war lehrreich und sehr anstrengend für mich als Ansible
Anfänger. Wir haben viele Praxisbeispiele gemacht, was herausfordernd,
aber eben auch griffig und damit bildend war. Natürlich konnten wir nur
an der Oberfläche kratzen, aber wir haben nun einen Startpunkt, auf dem
wir aufsetzen können.
Nachtrag: Ein Nachteil der YAML Struktur ist, dass die Einrückungen beim Konvertieren der Dokumentation verloren gegangen sind. Bei JSON wäre das nicht so schlimm, aber hier ging dann leider auch einiges an Informationen verloren.
Achim Mertens