~~NOTOC~~ ====== LU10c - Provisioning mit Ansible (idempotent konfigurieren) ====== **Ziel:** Du kannst **Provisioning** verstehen und anwenden: Du konfigurierst VMs automatisiert mit **Ansible** (idempotent), und du kannst Ansible-Provisioning sinnvoll von **Shell-Skripten** und **Dockerfiles** abgrenzen. ===== Übersicht ===== ^ Thema ^ Kernaussage ^ | **Provisioning** | „Maschine nach dem Boot automatisch einrichten“ (Pakete, Konfig, Services, Users, Files). | | **Shell Provisioner** | Schnell, aber oft „fragil“ (nicht idempotent, schwer wartbar). | | **Ansible** | Konfiguration als Code: deklarativ, **idempotent**, gut strukturierbar (Rollen/Tasks). | | **Idempotenz** | „Mehrfach ausführen → gleicher Zustand, ohne Chaos“. | | **Handler** | „Nur bei Änderung Service neu starten/reload“. | | **Playbook** | Sammlung von Tasks, die auf Hosts angewendet werden. | ===== Warum Provisioning? ===== Ohne Provisioning passiert das hier: * Jede:r installiert manuell Pakete * Jede:r vergisst etwas * Jede:r hat andere Versionen/Einstellungen * Debugging wird unfair („bei mir geht’s“) Mit Provisioning: * Einmal definieren → immer reproduzierbar * Gleiche Ausgangslage für alle * Ideal für Multi-Node Labs **Merke:** Vagrant erstellt VMs. Provisioning macht daraus „fertige Nodes“ für dein verteiltes System. ===== Shell vs. Ansible (kurzer Vergleich) ===== ^ Kriterium ^ Shell-Skript ^ Ansible ^ | Lesbarkeit | ok, aber schnell unübersichtlich | sehr gut (Tasks/Module) | | Wiederholbarkeit | oft problematisch | **idempotent** | | Fehlerhandling | selber bauen | eingebaut (Return-Codes, Changed-Status) | | Strukturierung | eher „Script-Spaghetti“ | Rollen, Variablen, Templates | | Lerntransfer | Script-Skills | DevOps/IaC-Transfer sehr hoch | ===== Kernkonzepte in Ansible ===== ==== Inventory (Hosts-Liste) ==== Welche Maschinen gibt es und wie heissen sie? Beispiel (klassisch): [db] 192.168.56.11 [api] 192.168.56.12 [proxy] 192.168.56.13 ==== Playbook ==== Ein YAML-Dokument, das beschreibt, was auf welchen Hosts passieren soll. ==== Task ==== Ein einzelner Schritt, z.B. „nginx installieren“. ==== Module ==== „Bausteine“ für typische Dinge: `apt`, `copy`, `template`, `service`, `user`, `lineinfile`… ==== Handler ==== Wird nur ausgelöst, wenn sich etwas ändert (z.B. Config geändert → nginx reload). **Idempotenz** ist das Killer-Feature: Ein Playbook kann man „einfach nochmal laufen lassen“, ohne alles kaputt zu machen. ===== Ansible in Vagrant einbinden ===== Es gibt zwei gängige Wege: ==== Variante A: ansible (Host-basiert) ==== * Ansible läuft auf deinem **Host** * Vagrant übergibt die VM-Infos an Ansible * Vorteil: schnell, simpel (wenn Host Ansible hat) * Nachteil: Host muss Ansible installiert haben (Windows teils mühsam) ==== Variante B: ansible_local (Guest-basiert) ==== * Ansible wird in der **VM** installiert und dort ausgeführt * Vorteil: host-unabhängiger, oft „klassen-tauglicher“ * Nachteil: Playbook-Lauf ist minimal langsamer In Klassen mit gemischten Betriebssystemen ist **ansible_local** oft robuster. ===== Beispiel-Projektstruktur ===== projekt/ ├─ Vagrantfile └─ provision/ ├─ playbook.yml ├─ group_vars/ │ ├─ all.yml └─ templates/ └─ nginx.conf.j2 ===== Beispiel: Vagrantfile mit ansible_local ===== Vagrant.configure("2") do |config| config.vm.box = "ubuntu/jammy64" nodes = { "db" => "192.168.56.11", "api" => "192.168.56.12", "proxy" => "192.168.56.13" } nodes.each do |name, ip| config.vm.define name do |node| node.vm.hostname = name node.vm.network "private_network", ip: ip end end # Ansible läuft in der VM (ansible_local) config.vm.provision "ansible_local" do |ansible| ansible.playbook = "provision/playbook.yml" ansible.install = true end end ===== Beispiel: Playbook (Basis + Rollen light) ===== Dieses Playbook zeigt typische Patterns: * Pakete installieren * /etc/hosts pflegen (damit Namen auflösbar sind) * nginx als Proxy konfigurieren * Services starten/aktivieren # provision/playbook.yml - name: Multi-Node Setup fuer verteilte Systeme hosts: all become: true vars: cluster_hosts: - { name: "db", ip: "192.168.56.11" } - { name: "api", ip: "192.168.56.12" } - { name: "proxy", ip: "192.168.56.13" } tasks: - name: Pakete installieren (Basis) ansible.builtin.apt: name: - curl - ca-certificates - net-tools - python3 - python3-pip update_cache: true state: present - name: /etc/hosts fuer Cluster-Namen pflegen ansible.builtin.lineinfile: path: /etc/hosts line: "{{ item.ip }} {{ item.name }}" state: present loop: "{{ cluster_hosts }}" - name: Proxy Node konfigurieren hosts: proxy become: true tasks: - name: nginx installieren ansible.builtin.apt: name: nginx update_cache: true state: present - name: nginx config deployen ansible.builtin.template: src: templates/nginx.conf.j2 dest: /etc/nginx/sites-available/default notify: reload nginx - name: nginx aktivieren und starten ansible.builtin.service: name: nginx state: started enabled: true handlers: - name: reload nginx ansible.builtin.service: name: nginx state: reloaded ===== Beispiel: Nginx Template (Reverse Proxy) ===== # provision/templates/nginx.conf.j2 server { listen 80; location / { proxy_pass http://api:8000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } } **Was hier wichtig ist:** Der Proxy spricht **api:8000** (Name, nicht IP). Das funktioniert, weil wir via Ansible `/etc/hosts` gesetzt haben. (Später kann man das durch „echte“ Service Discovery ersetzen.) ===== Brücke zu Dockerfile / Docker-Compose ===== ^ Konzept ^ Docker-Welt ^ VM/Ansible-Welt ^ | Artefakt | Image | VM/Box + Provisioning | | „Build“ | Dockerfile → Image | (optional) Packer → Image / oder Vagrant + Provisioning | | Konfiguration | ENV, COPY, RUN | apt, template, service, systemd | | Reproduzierbarkeit | sehr hoch | hoch (wenn idempotent) | | Runtime | Container | VM | Wenn du Ansible sauber machst, lernen die Lernenden „Konfiguration als Code“ – das ist in der Praxis extrem gefragt, egal ob VM, Cloud oder Kubernetes. ===== Debugging & Qualität ===== ==== Playbook testen ==== # in der VM (ansible_local) typischerweise: sudo ansible-playbook /vagrant/provision/playbook.yml # mehr Details: sudo ansible-playbook /vagrant/provision/playbook.yml -vv ==== Häufige Fehler ==== * falscher Pfad zu Templates * Service heisst anders (z.B. nginx vs apache2) * Ports stimmen nicht (Proxy zeigt auf falschen Port) * Rechte fehlen → `become: true` vergessen ==== Profi-Pattern (optional) ==== * **check mode** (trocken laufen lassen): `--check` * **syntax check**: `--syntax-check` * Variablen pro Umgebung (`group_vars`, `host_vars`) * Rollen (`roles/`) für saubere Wiederverwendung ---- {{tag>M321-LU10}} [[https://creativecommons.org/licenses/by-nc-sa/4.0/|{{https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png}}]] Kevin Maurizi