# Ansible-Standard (verbindlich) > Gilt für alle Plays und Rollen in diesem Projekt. Verallgemeinert aus einem erprobten Homelab-Setup. > Vorlagen: [`templates/ansible/`](templates/ansible/). Geheimnisse: `rules/secrets.md`. ## 1. Verzeichnislayout ``` /ansible/ ├── .env.sh # setzt alle Pfade + Secret-Store-Variablen → source (bash/zsh) ├── ansible.cfg # Fact-Cache, become, Log – Pfade aus .env.sh ├── inv/ │ ├── # Inventar (INI oder YAML), z. B. prod, lab │ ├── group_vars/all/ # globale Variablen (ansible_user, ans_files, Secret-Store-Pfade) │ ├── group_vars/.yml │ └── host_vars/.yml ├── playbooks/ # ein Dienst = ein Play; Präambel = Doku ├── roles// # Logik: tasks/ handlers/ defaults/ meta/ (keine templates/!) └── files// # alle Templates (*.j2) und Dateien – Rollen holen sie aus $ANS_FILES ``` `.env.sh` (interaktiv in der Shell gesourct, setzt `ANSIBLE_*`) ist bewusst etwas anderes als die `.env` der Bash-Scripts. ## 2. Aufruf & Umgebung - Vor jedem Aufruf: `source ansible/.env.sh`. Pfade **nie** hart codieren: `$ANSIBLE_BASE_PATH`, `$ANS_PLAYDIR`, `$ANS_FILES` (in YAML: `ans_files`). - Aufrufe immer: `ansible-playbook $ANS_PLAYDIR/.yml [-e hostlist=…] [--check --diff]`. - `.env.sh` setzt fremde `ANSIBLE_*`-Variablen zurück (`unset`), damit kein Kontext eines anderen Repos durchschlägt. | Variable | Zweck | |---|---| | `ANSIBLE_BASE_PATH` | Basis für alles | | `ANSIBLE_CONFIG`, `ANSIBLE_INVENTORY`, `ANSIBLE_ROLES_PATH` | Standard-Ansible-Variablen | | `ANS_PLAYDIR` | Playbooks | | `ANS_FILES` | Templates/Dateien (YAML: `ans_files`) | | `ANS_DEFAULT_HOSTS` | Dokumentation des Standardziels (s. § 3) | | `VAULT_ADDR`, `ANSIBLE_HASHI_VAULT_*`, `ANS_VAULT_KV_MOUNT/PATH` | Secret-Store | | `ANSIBLE_VAULT_PASSWORD_FILE` | nur wenn Datei existiert (Fallback Ansible Vault) | ## 3. Playbooks - **Präambel max. 12 Zeilen** im Header-Format (`rules/headers.md`): `@file`, `@brief`, `@author`, `@owner`, `@version`, `@usage` mit nötigen/optionalen `-e`-Variablen, Tags und Voraussetzungen. - Ziel immer `hosts: "{{ hostlist | default('') }}"` – ohne `-e` genau **ein** bekannter, ungefährlicher Host (Lab/Test). **Nie** `all` oder eine Produktivgruppe als Default. - Ein Dienst = ein Play (`radius.yml`, `dns.yml`). Logik liegt in `roles//`; das Play bindet nur die Rolle ein. - Dateinamen: Kleinbuchstaben, `_` statt `-` (`vault_check.yml`). - Standard-Hilfsplays je Repo: `mini_check.yml` (Erreichbarkeit, Facts), `vault_check.yml` (Secret-Store erreichbar, nur Schlüsselnamen). ## 4. Rollen - Rollenname = Dienst. Tasks thematisch teilen: `main.yml` (Ablauf) → `secrets.yml`, `install.yml`, `config.yml`, `verify.yml`. - `main.yml` beginnt mit einem **Plattform-Check** (`ansible.builtin.assert` auf `ansible_facts`), Tag `always`. - **Templates liegen nicht in der Rolle**, sondern in `files//`; Zugriff über `{{ ans_files }}//…`. - Nur Dateien templaten, die wir „besitzen“. Paket-Defaults nicht komplett überschreiben. - Konfiguration **vor** dem Restart prüfen: Handler-Kette Check → Restart (`listen`/`notify`), `meta: flush_handlers` vor `service: started`. Bei Fehler bleibt der laufende Dienst unberührt. - Jede Rolle hat einen **Smoke-Test** (`verify.yml`, Tag `verify`, `check_mode: false`, `changed_when: false`). - **Idempotent:** zweiter Lauf `changed=0`. `command`/`shell` nur mit `creates`/`changed_when`. - Module mit FQCN (`ansible.builtin.…`, `community.…`). **Task-Namen in der Amtssprache**, als Satz („Paket installieren“). - Variablen der Rolle mit Rollenpräfix (`radius_clients`), Defaults in `defaults/main.yml` mit Kommentar je Variable. ## 5. SSH-Performance - `pipelining=True` (Standard in `templates/ansible/ansible.cfg`): Module laufen per stdin statt Kopie nach `/tmp` – spart je Task mehrere SSH-Roundtrips, typisch der größte Einzelgewinn. Voraussetzung: kein `Defaults requiretty` in `sudoers` (aktuelle Distros: Standard). - Dazu `ControlMaster=auto` / `ControlPersist=60s`: eine SSH-Verbindung je Host wird wiederverwendet. - Bei Fehlern wie „sudo: sorry, you must have a tty“: `requiretty` auf dem Ziel entfernen, nicht `pipelining` abschalten. ## 6. Facts - `gathering=smart` + Fact-Cache (`jsonfile`, 86400 s) aus `ansible.cfg`. Facts nutzen statt Shell-Abfragen (`ansible_facts['distribution_major_version']`), Zugriff immer über `ansible_facts[...]`, nicht über `ansible_*`-Kurzformen. - Facts neu sammeln: `ansible-playbook $ANS_PLAYDIR/mini_check.yml -e check_mode=setup`. ## 7. Geheimnisse - Secret-Store per `community.hashi_vault` (Lookup in `secrets.yml`), Fallback Ansible Vault (`vault_*`-Variablen). - Tasks mit Geheimnissen `no_log: true`, Templates mit Geheimnissen `diff: false`. Nicht entfernen. - Testbetrieb ohne Secret-Store: `-e _secrets_source=vars -e @/pfad/außerhalb/testsecrets.yml`. ## 8. Tags `install`, `config`, `verify`; Plattform-Check und Secrets `always`. ## 9. Kommentare & Stil - Deaktivierte, absichtlich behaltene Blöcke mit `#-#` markieren. - YAML: 2 Leerzeichen, `---` am Anfang, `true`/`false` statt `yes`/`no`, Strings mit Jinja in Anführungszeichen. - Prüfen vor Abgabe: `ansible-lint`, `yamllint`, `ansible-playbook --syntax-check`, `--check --diff`, Lauf gegen lokalen Testcontainer, Idempotenz (`rules/testing.md`). ## 10. Neue Rolle in 5 Schritten 1. Original-Doku des Dienstes holen (`rules/web_search.md`), Ergebnisse in `knowledge/services/.md`. 2. `cp -r ai/common/templates/ansible/roles/example roles/`, `files/example` → `files/`, Play aus `playbooks/example.yml`. 3. Präfix `example_` → `_`, Header ausfüllen. 4. Lokal testen (Container), Idempotenz prüfen. 5. Knowledge/`context.md` aktualisieren. ## Änderungsprotokoll - 07.10.2026 – angelegt, verallgemeinert aus infra-devices/ansible. - 08.10.2026 – § 5 SSH-Performance (pipelining, ControlPersist) als Vorgabe – Wunsch des Bedieners. - 23.10.2026 – Mandantenbezug entfernt (Einzelprojekt).