Die Frage taucht in fast jedem unserer Beratungsgespräche auf: “Wir haben hier einen Ordner voller Bash-Skripte — sollen wir auf Ansible umsteigen?” Die ehrliche Antwort lautet: Es kommt darauf an. Und zwar nicht auf das Buzzword-Bingo, sondern auf die Anzahl der Server, die Größe des Teams und die Frequenz der Änderungen.
In diesem Artikel zeigen wir den Kipppunkt, an dem der Wechsel von Bash zu Ansible tatsächlich Zeit spart — und wann er nur Overhead produziert. Mit konkretem Migrationsbeispiel aus einem echten SMB-Projekt.
Der Ausgangspunkt: Warum Bash trotzdem lebt
Bash ist nicht tot. Bash ist auf jedem Linux-System vorinstalliert, hat keine Abhängigkeiten, lässt sich per SSH auf jeden Host schieben und ist von jedem Admin lesbar. Für eine Handvoll Server — sagen wir zehn Proxmox-Nodes, drei TrueNAS-Systeme und zwei OPNsense-Firewalls — ist ein sauber strukturiertes Git-Repository mit Shell-Skripten oft die beste Lösung. Kein Kontrollknoten, kein YAML-Overhead, keine Python-Abhängigkeiten auf den Zielen.
Der Klassiker sieht dann so aus:
#!/usr/bin/env bash
# update-node.sh -- Debian/Proxmox-Node updaten
set -euo pipefail
HOST="$1"
ssh "root@${HOST}" 'apt-get update && apt-get -y dist-upgrade && apt-get -y autoremove'
ssh "root@${HOST}" 'systemctl reboot'
Das funktioniert. Bis es das nicht mehr tut. Der Bruch kommt nicht schleichend, sondern an einem Freitagnachmittag, wenn ein Kollege denselben Befehl zweimal ausführt oder ein Skript ohne set -e mittendrin abbricht und den Node in einem Zwischenzustand hinterlässt.
Der Kipppunkt: Idempotenz wird zur Pflicht
Ab etwa 30 bis 50 verwalteten Systemen ändert sich die Physik. Nicht weil Bash technisch nicht mehr könnte, sondern weil zwei Eigenschaften kritisch werden, die Bash nicht mitbringt:
- Idempotenz — ein Skript beliebig oft ausführen zu können, ohne Schaden anzurichten.
- Inventarisierung — die Zuordnung “welcher Host bekommt welche Konfiguration” muss deklarativ, nicht in Skripten versteckt sein.
Ein Bash-Skript, das useradd monitoring aufruft, scheitert beim zweiten Lauf. Ein Ansible-Task ansible.builtin.user: name=monitoring state=present prüft den Zustand und tut beim zweiten Lauf schlicht nichts. Klingt banal, ist aber der Unterschied zwischen “ich führe das Playbook einmal pro Monat gegen alle Hosts aus” und “ich baue eigene Zustandsprüfungen in jedes Skript ein”.
Die Faustregel aus unseren Kundenprojekten:
| Umgebung | Server-Zahl | Änderungen/Monat | Empfehlung |
|---|---|---|---|
| Klein | 5-15 | 1-2 | Bash + Git, ssh in Schleife |
| Mittel | 15-40 | 3-10 | Bash strukturiert, ggf. Ansible-Ad-hoc |
| Wachsend | 40-100 | 10+ | Ansible mit Rollen und Inventory |
| Groß | 100+ | wöchentlich | Ansible + AWX/Semaphore, CI/CD |
Der Übergang von “wachsend” zu “groß” ist fließend. Wichtiger als die reine Serverzahl ist die Zahl der Personen, die auf die Systeme zugreifen. Sobald mehr als zwei Admins parallel arbeiten, ist ein deklarativer Zustand Gold wert.
Migrationsbeispiel: Vom Skript zum Playbook
Nehmen wir einen konkreten Fall aus einem Linux-Consulting-Projekt: Ein Fertigungsbetrieb betrieb 42 Ubuntu-LTS-Server (24.04) auf zwei Proxmox-Clustern, plus zwölf Debian-basierte Application-Server. Die Basiskonfiguration — SSH-Härtung, Monitoring-Agent, Backup-Client, Log-Shipping — lag in acht Bash-Skripten, die per Ansible… äh, per for host in $(cat hosts.txt); do ssh ...; done verteilt wurden.
Das funktionierte drei Jahre lang. Dann kam der Wechsel von rsyslog auf journald-Remote-Forwarding, und plötzlich hatten die Skripte drei Verzweigungen pro Host je nach Alter, Distributionsversion und ob ein früherer Kollege manuell etwas verändert hatte. Der Aufwand pro Rollout stieg von einer Stunde auf einen ganzen Tag.
Der Umbau lief in drei Schritten:
Schritt 1: Inventory extrahieren. Aus der bisherigen hosts.txt wurde eine strukturierte inventory.yml:
all:
children:
proxmox_hosts:
hosts:
pve01.intern:
pve02.intern:
app_servers:
hosts:
app[01:12].intern:
vars:
backup_target: nas01.intern
db_servers:
hosts:
db[01:04].intern:
vars:
backup_target: nas02.intern
Schritt 2: Ein Basis-Rolle statt acht Skripten. Die acht Shell-Skripte wurden zu einer Ansible-Rolle common mit Tasks für SSH-Config, User-Management, Monitoring-Agent und Log-Forwarding zusammengeführt. Jeder Task wurde bewusst idempotent formuliert:
- name: SSH -- root-Login per Passwort deaktivieren
ansible.builtin.lineinfile:
path: /etc/ssh/sshd_config
regexp: '^#?PermitRootLogin'
line: 'PermitRootLogin prohibit-password'
validate: 'sshd -t -f %s'
notify: restart sshd
- name: Monitoring-Agent installieren
ansible.builtin.apt:
name: prometheus-node-exporter
state: present
update_cache: yes
cache_valid_time: 3600
Schritt 3: Dry-Run und Rollout. ansible-playbook site.yml --check --diff gegen alle 54 Hosts zeigte, welche Systeme abweichen — ohne etwas zu ändern. Das war der Aha-Moment für das Team: Zum ersten Mal war der Ist-Zustand aller Hosts auf einer Seite sichtbar.
Der eigentliche Rollout lief anschließend in vier Wellen a zwölf bis fünfzehn Hosts. Zeitbedarf: knapp drei Stunden statt vorher acht.
Was Ansible nicht löst
Ansible ist kein Wundermittel. Drei Punkte, die wir in jedem Beratungsgespräch betonen:
Erstens: Ansible ersetzt kein Monitoring. Ein Playbook, das erfolgreich durchläuft, sagt nichts darüber aus, ob der Dienst danach tatsächlich Anfragen beantwortet. ansible.builtin.uri als Post-Check ist Pflicht, aber ein echtes Monitoring mit Zabbix, Checkmk oder Prometheus bleibt daneben notwendig.
Zweitens: Ansible ist langsam. Für 200 Hosts mit einer komplexen Rolle können Playbook-Laufzeiten von 20 bis 40 Minuten entstehen. strategy: free, serial-Batches und Mitigationen wie Pipelining oder Fact-Caching helfen, aber wer Sub-Minuten-Deployments braucht, schaut Richtung Salt oder Immutable Infrastructure.
Drittens: YAML ist nicht selbsterklärend. Ein 2000-Zeilen-Playbook mit Jinja-Templates, when-Bedingungen und Handlern kann genauso unwartbar sein wie ein Bash-Wildwuchs. Ohne klare Rollen-Struktur, Namenskonventionen und Peer-Review verlagert sich das Problem nur.
Der pragmatische Mittelweg
Für viele mittelständische Umgebungen empfehlen wir eine hybride Strategie: Bash bleibt für einmalige Wartungsjobs, Notfall-Skripte und Boot-Automatisierungen. Ansible übernimmt alles, was wiederholt oder auf mehreren Hosts synchron passieren soll. Der Kontrollknoten kann eine kleine VM auf dem Proxmox-Cluster sein, ein Ansible-Aufruf pro Nacht per Cron reicht für den Anfang. AWX oder Semaphore als Web-UI kommen erst, wenn Nicht-Admins Playbooks anstoßen sollen.
Wichtig ist die Disziplin, jede Änderung über Ansible laufen zu lassen — auch wenn “einmal schnell per SSH” schneller wäre. Sobald zwei Wege existieren, driftet der Zustand.
Fazit
Bash ist kein Anfänger-Werkzeug, und Ansible ist keine Silberkugel. Der Kipppunkt liegt weniger bei einer bestimmten Serverzahl als beim Moment, in dem drift zwischen “so soll es sein” und “so ist es tatsächlich” auftritt. Wer den Zustand seiner Server nicht mehr in zehn Minuten prüfen kann, hat Ansible nötig — egal wie viele Systeme es sind.
DATAZONE unterstützt kleine und mittlere IT-Teams beim strukturierten Aufbau von Ansible-Rollen, Inventory-Design und der Migration bestehender Skript-Landschaften. Von der ersten Rolle bis zur produktiven AWX-Instanz auf Proxmox — sprechen Sie uns an unter /kontakt/, wir schauen uns Ihre Automations-Landschaft gemeinsam an und finden den richtigen Zeitpunkt für den Wechsel.
Mehr zu diesen Themen:
Weitere Artikel
Linux vs. Windows Server 2026: der TCO-Vergleich ohne Marketing-Schleier
Linux vs Windows Server 2026: ehrlicher TCO-Vergleich mit Datacenter-Core, CAL, Betrieb, Personal, Anwendungsdruck und Migration. Warum mixed operations Normalität sind.
Samba als Active Directory: Windows-Domäne ablösen
Windows Server AD durch Samba 4 AD-DC ersetzen: DNS mit BIND9, Replikation, Gruppenrichtlinien-Grenzen und Koexistenz während der Migration.
systemd-networkd vs. NetworkManager: Wann was auf Servern
systemd-networkd oder NetworkManager auf Linux-Servern? Vergleich der Netzwerkstacks mit Bridge-, VLAN- und Migrations-Beispielen für Proxmox, KVM und Container.