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.
| 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. |
Ohne Provisioning passiert das hier:
Mit Provisioning:
Merke: Vagrant erstellt VMs. Provisioning macht daraus „fertige Nodes“ für dein verteiltes System.
| 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 |
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
Ein YAML-Dokument, das beschreibt, was auf welchen Hosts passieren soll.
Ein einzelner Schritt, z.B. „nginx installieren“.
„Bausteine“ für typische Dinge: `apt`, `copy`, `template`, `service`, `user`, `lineinfile`…
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.
Es gibt zwei gängige Wege:
In Klassen mit gemischten Betriebssystemen ist ansible_local oft robuster.
projekt/
├─ Vagrantfile
└─ provision/
├─ playbook.yml
├─ group_vars/
│ ├─ all.yml
└─ templates/
└─ nginx.conf.j2
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
Dieses Playbook zeigt typische Patterns:
# 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
# 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.)
| 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.
# in der VM (ansible_local) typischerweise: sudo ansible-playbook /vagrant/provision/playbook.yml # mehr Details: sudo ansible-playbook /vagrant/provision/playbook.yml -vv