Verbinde die Veranstaltungsseiten

AnsibleBeginner
Jetzt üben

Einführung

Die Startseite von Riverlight Weekend ist bereit, aber Besucher können weder das Programm noch die Seite zum Veranstaltungsort öffnen. Beide Quelldienste funktionieren bereits. Verbinde den Eingang mit Ansible mit den gewählten Inventarmitgliedern, lade nur geänderte Konfiguration neu und schütze funktionierende Routen vor einem ungeeigneten Ersatz.

Du brauchst grundlegende Terminalnavigation und Übung im Lesen eines kleinen Ansible-Inventars, von Variablen und eines Playbooks. Dieses Lab erklärt HTTP-Dienstrollen, Gruppenmitglieder, Variablen anderer Hosts, JSON, reine Leseabfragen und Handler vor ihrer Verwendung. Software und Veranstaltungsdienste sind vorbereitet. Die Zeit ist eine Schätzung des Autors einschließlich Lesen und gewöhnlicher Korrekturen.

Verbinde die Programm- und Besuchsseiten

In diesem Schritt verbindest du eine Veranstaltungswebsite mit ihren vorbereiteten Programm- und Ortsquellen. Dabei verwendest du Inventarmitglieder statt fester Adressen in einer Vorlage.

Riverlight Weekend hat eine funktionierende Startseite und einen Besucherleitfaden. Die Links zu Programm und Veranstaltungsort zeigen derzeit eine Meldung zur nicht verfügbaren Seite. Der Eingang ist ein vorbereiteter kleiner HTTP-Reverse-Proxy: Er leitet eine Anfrage an einen anderen Dienst weiter und liefert dessen tatsächliche Antwort zurück. Er kopiert keine Programmdaten in die Startseite. Der Eingang läuft auf dem Controller; die beiden Quellknoten sind Container, die den Kernel dieser Lern-VM teilen. Es sind keine drei unabhängigen VMs. Software und Dienste sind bereit; du verwaltest nur die Verbindungen des Eingangs.

Öffne den Tab Event Site. Auf der Startseite sollte A little closer to the river. stehen. Klicke auf Explore the program: This page is taking a break. ist die erwartete HTTP-502-Antwort, weil die Route noch nicht verbunden ist. Verwende Back to the weekend auf dieser Seite und dann Visitor guide in der Navigation. Diese Seite funktioniert bereits und muss verfügbar bleiben.

Wechsle zu Controller. Der Tab startet in /home/labex/project. pwd zeigt das aktuelle Verzeichnis:

pwd

Falls du das Arbeitsverzeichnis verlierst, kehre mit cd /home/labex/project zurück. Ein falsch geschriebener Dateiname verursacht „No such file or directory“. Prüfe die Schreibweise, liste bei Bedarf mit ls templates das Verzeichnis auf und versuche es erneut. Die VM muss nicht zurückgesetzt werden.

cat zeigt eine Datei an. Lies die freigegebene Dienstauswahl, das Inventar und die Daten je Host:

cat approved-services.txt
cat inventory.ini
cat host_vars/web1.yml
cat host_vars/web2.yml

Die Gruppen [program] und [venue] wählen jeweils eine Quelle. web1 liefert das aktuelle Programm, web2 den Veranstaltungsort. Die Hostdateien enthalten die tatsächliche service_address und die Dienstports. Adressen können zwischen VMs variieren. Manche Knoten bieten auch einen Archivdienst an; Erreichbarkeit macht ihn nicht zum freigegebenen aktuellen Programm.

Die Gruppe [gateway] enthält entry. ansible_connection=local bedeutet, dass Ansible den Eingang direkt auf dem Controller verwaltet, ohne zusätzliche SSH-Verbindung. /usr/bin/python3 ist der vorbereitete lokale Python-Interpreter. Ein HTTP-Port kennzeichnet einen lauschenden Dienst an einer Adresse. Ein Knoten kann mehrere Dienste auf unterschiedlichen Ports ausführen.

Lies jede ausgewählte Quelle direkt, bevor du den Eingang änderst. Die vorbereiteten curl-Konfigurationen enthalten die tatsächlichen URLs. --config liest curl-Optionen aus einer Datei; fail lässt HTTP-Fehler fehlschlagen, silent blendet die Fortschrittsanzeige aus und show-error erhält hilfreiche Fehlermeldungen. Diese Dateien enthalten weder Passwort noch Token.

cat requests/web1.conf
curl --config requests/web1.conf
cat requests/web2.conf
curl --config requests/web2.conf

Die JSON-Antworten identifizieren program und venue, die Veranstaltung riverlight und die jeweiligen Ausgaben. JSON ist strukturierter Text mit benannten Feldern. Eine erfolgreiche Quellanfrage beweist ihre direkte Funktion, noch nicht die Funktion der Websiterouten.

Erstelle nun die Routenvorlage. Ansibles groups ordnet Gruppennamen ihre Mitglieder zu; [0] wählt das erste Mitglied der Gruppe mit genau einem Mitglied. hostvars liefert dessen Variablen. Das folgende Playbook nennt diese Mitglieder program_host und venue_host. In Jinja-Ausdrücken verbindet ~ Werte als Text, auch numerische Ports. | to_json erzeugt einen korrekt in Anführungszeichen gesetzten JSON-String, statt Anführungszeichen unsicher selbst zusammenzusetzen.

Der Shellbefehl verwendet >, um nur diese Datei zu ersetzen. <<'EOF' übergibt die folgenden Zeilen wortgetreu an cat; die einfachen Anführungszeichen verhindern, dass die Shell Jinja-Klammern interpretiert. Füge bis zum abschließenden EOF auf einer eigenen Zeile ein. Wartet die Shell wegen eines fehlenden Trennzeichens an einer Fortsetzungsaufforderung, drücke Ctrl+C und füge den vollständigen Befehl erneut ein.

cat > templates/routes.json.j2 <<'EOF'
{
  "program": {{ ('http://' ~ hostvars[program_host].service_address ~ ':' ~ hostvars[program_host].program_port) | to_json }},
  "venue": {{ ('http://' ~ hostvars[venue_host].service_address ~ ':' ~ hostvars[venue_host].venue_port) | to_json }}
}
EOF

Schreibe das Playbook für den Eingang. gather_facts: false vermeidet ungenutzte Maschineninformationen. vars definiert Ausdrücke, die mit dem aktuellen Inventar ausgewertet werden. template erzeugt die Datei, setzt den Modus 0644 (Eigentümer darf schreiben, alle dürfen lesen) und benachrichtigt nur bei einer Änderung der Routendatei einen Handler. Ein Handler ist eine Aufgabe, die nach einer Benachrichtigung ausgeführt wird, gewöhnlich am Ende des Plays.

Der Eingang hält Routen im Speicher; nur die Datei zu ersetzen reicht deshalb nicht. Der vorbereitete Helfer sendet ausschließlich dem bestehenden Prozess dieses Eingangs ein echtes SIGHUP zum Neuladen und wartet auf dessen Bestätigung. Der command des Handlers nutzt argv, eine Liste getrennter Argumente. playbook_dir ist das Verzeichnis des Playbooks und bindet den verwalteten Eingangspfad an dieses Projekt. Du brauchst weder sudo noch einen Dienstneustart.

cat > connect.yml <<'EOF'
- name: Connect the event services
  hosts: gateway
  gather_facts: false
  vars:
    program_host: "{{ groups['program'][0] }}"
    venue_host: "{{ groups['venue'][0] }}"
  tasks:
    - name: Write the inventory-derived routes
      ansible.builtin.template:
        src: templates/routes.json.j2
        dest: "{{ playbook_dir }}/entry/routes.json"
        mode: '0644'
      notify: Reload entry
  handlers:
    - name: Reload entry
      ansible.builtin.command:
        argv:
          - python3
          - /opt/labex/service-links/reload.py
          - "{{ playbook_dir }}/entry"
EOF

Prüfe zuerst die YAML-Struktur und sieh dann die erwartete Dateiänderung an. --syntax-check wendet keine Aufgaben an. --check sagt unterstützte Änderungen voraus; --diff zeigt den alten und den vorgeschlagenen Inhalt. Diese Vorschau sendet dem Gateway kein Signal und beweist nicht die Funktion der fertigen Website.

ansible-playbook connect.yml --syntax-check
ansible-playbook connect.yml --check --diff

Der Diff sollte die unverbundenen Routen 127.0.0.1:9 durch die aktuellen Quelladressen und Ports ersetzen. Wende das Playbook normal an:

ansible-playbook connect.yml

Du solltest die Vorlagenänderung und RUNNING HANDLER [Reload entry] sehen. Kehre zu Event Site zurück, öffne Program und lies die drei aktuellen Programmpunkte: Paper and ink, Acoustic afternoon und Shared supper. Klicke auf Download the schedule, um schedule.csv herunterzuladen. Zeiten, Programmpunkte und Orte müssen der Tabelle entsprechen. Öffne über Visit die Seite zu Riverside Yard und danach Visitor guide. Startseite und Leitfaden müssen weiter funktionieren.

Das verbundene Programm sollte diese drei Programmpunkte zeigen, mit Download the schedule direkt unter der Tabelle:

Aktuelles Riverlight-Programm und Download des Zeitplans

Wechsle zurück zu Controller. Du kannst den echten Download auch in der VM speichern und lesen. Bei curl lässt -f HTTP-Fehler fehlschlagen, -sS verbirgt den Fortschritt, zeigt aber Fehler, und -o benennt die Ausgabedatei:

curl -fsS http://127.0.0.1:8081/program/schedule.csv -o schedule.csv
cat schedule.csv

Erwarteter Inhalt:

time,session,place
10:30,Paper and ink,Making table
13:00,Acoustic afternoon,River stage
16:00,Shared supper,Long table

127.0.0.1 bezeichnet diesen Controller, auf dem der Eingang an Port 8081 lauscht. Die öffentliche Browseradresse leitet zum selben Dienst weiter.

Führe dasselbe Playbook erneut aus:

ansible-playbook connect.yml

Die Zusammenfassung sollte changed=0 und failed=0 melden. Der Handler darf nicht laufen. Das ist Konvergenz: Die aktuelle Deklaration stimmt bereits mit der Datei überein. Echte Seiten und Download belegen das nutzbare Ergebnis; die Zusammenfassung allein genügt nicht.

Schütze funktionierende Routen vor dem Ersetzen

In diesem Schritt ergänzt du echte HTTP-Identitätsprüfungen vor dem Schreiben und lehnst einen erreichbaren Archivdienst ab, während die Website funktioniert.

Bleibe in Controller, im Verzeichnis /home/labex/project. HTTP 200 bedeutet, dass der Server erfolgreich geantwortet hat. Diensttyp, Veranstaltung und Ausgabe sind damit noch nicht bestätigt. Das aktuelle Programm und der Veranstaltungsort identifizieren sich über /identity. Die vorbereitete Datei group_vars/all.yml enthält die freigegebene Veranstaltung und die Ausgaben:

cat group_vars/all.yml

Ergänze eine Vorabprüfung, also eine Prüfung vor der Änderung. assert stoppt den Play, wenn eine Bedingung falsch ist. Die erste Assertion verlangt genau ein Mitglied je Dienstgruppe. Jede uri-Aufgabe sendet vom Controller eine echte HTTP-GET-Anfrage. return_content: true erhält den Antwortinhalt; eine JSON-Antwort ist zusätzlich über .json verfügbar. register speichert das Aufgabenergebnis unter einem Variablennamen für spätere Aufgaben. Die letzten Assertions vergleichen tatsächliche Identitäten mit freigegebenen Werten.

Die HTTP-Aufgaben verwenden bewusst check_mode: false: Diese reinen Leseanfragen müssen auch während einer Vorschau laufen. Andernfalls kann eine normale uri-Aufgabe im Prüfmodus übersprungen werden. Diese Einstellung gehört nur zu den Leseabfragen; sie erlaubt weder das Anwenden einer Vorlage noch ein Neuladen in der Vorschau. Das Zeitlimit von drei Sekunden verhindert, dass eine fehlende Quelle die Übung lange aufhält.

Ersetze das Playbook durch diese vollständige geschützte Fassung. Behalte die Vorlage und lasse alle Identitätsprüfungen vor der Vorlagenaufgabe stehen:

cat > connect.yml <<'EOF'
- name: Connect the event services
  hosts: gateway
  gather_facts: false
  vars:
    program_host: "{{ groups['program'][0] }}"
    venue_host: "{{ groups['venue'][0] }}"
  tasks:
    - name: Require one member for each service
      ansible.builtin.assert:
        that:
          - groups['program'] | length == 1
          - groups['venue'] | length == 1
    - name: Read the selected program identity
      ansible.builtin.uri:
        url: "http://{{ hostvars[program_host].service_address }}:{{ hostvars[program_host].program_port }}/identity"
        return_content: true
        timeout: 3
      check_mode: false
      register: program_probe
    - name: Read the selected venue identity
      ansible.builtin.uri:
        url: "http://{{ hostvars[venue_host].service_address }}:{{ hostvars[venue_host].venue_port }}/identity"
        return_content: true
        timeout: 3
      check_mode: false
      register: venue_probe
    - name: Check the actual service identities
      ansible.builtin.assert:
        that:
          - program_probe.json.service == 'program'
          - program_probe.json.site == event_site
          - program_probe.json.edition == program_edition
          - venue_probe.json.service == 'venue'
          - venue_probe.json.site == event_site
          - venue_probe.json.edition == venue_edition
    - name: Write the inventory-derived routes
      ansible.builtin.template:
        src: templates/routes.json.j2
        dest: "{{ playbook_dir }}/entry/routes.json"
        mode: '0644'
      notify: Reload entry
  handlers:
    - name: Reload entry
      ansible.builtin.command:
        argv:
          - python3
          - /opt/labex/service-links/reload.py
          - "{{ playbook_dir }}/entry"
EOF
ansible-playbook connect.yml --syntax-check

Speichere nun einen Fingerabdruck der funktionierenden Routendatei. sha256sum berechnet einen Inhaltshash; > legt die Ausgabe separat für den späteren Vergleich ab:

sha256sum entry/routes.json > routes-before.sha256

Das vorbereitete alternative Inventar wählt ein Archiv als Programm. Lies es und teste es absichtlich mit -i, das nur für diesen Befehl eine Inventardatei auswählt. Das normale Inventar bleibt unverändert:

cat inventory-wrong-service.ini
ansible-playbook -i inventory-wrong-service.ini connect.yml

Dieser Befehl soll mit einem Status ungleich null und failed=1 scheitern. Das Archiv ist erreichbar und liefert JSON, aber seine Ausgabe ist nicht freigegeben. Die Assertion muss vor Write the inventory-derived routes fehlschlagen. Die Zusammenfassung sollte changed=0 zeigen, ohne Handler. Das unterscheidet sich von einer abgelehnten Verbindung, bei der uri überhaupt keine Antwort erhält. Beide Fälle müssen das Schreiben verhindern.

Prüfe den gespeicherten Fingerabdruck. Mit -c vergleicht sha256sum die aktuelle Datei mit dem aufgezeichneten Hash:

sha256sum -c routes-before.sha256

Erwarte entry/routes.json: OK. Öffne in Event Site die Seite Program und lade den aktuellen Zeitplan erneut herunter. Eine abgelehnte Änderung muss das aktuelle Programm benutzbar lassen und nicht nur eine Datei erhalten.

Kehre zu Controller zurück und nutze das normale Inventar:

ansible-playbook connect.yml --check --diff
ansible-playbook connect.yml

Beide gewählten Identitäten müssen bestehen. Die bereits richtigen Routen benötigen keine Änderung, daher zeigt die Zusammenfassung changed=0 und kein Handler läuft. Bei einem YAML-Einrückungsfehler vergleiche den vollständigen Block, nutze Leerzeichen statt Tabulatoren und schreibe connect.yml neu. Ein Syntaxfehler beweist keine erfolgreiche Ablehnung durch die Vorabprüfung.

Dein Bereich umfasst connect.yml, templates/routes.json.j2 und die über das Playbook verwalteten Eingangsrouten. Erhalte die gelieferten Inventare, Hostdaten, freigegebenen Ausgaben, curl-Anfragen, Quellinhalte, Organisationsnotizen, Startseite und Leitfaden. Nutze /opt/labex/service-links/reload.py mit dem Eingangsverzeichnis dieses Projekts zum Neuladen. Trage aktuelle Knotennamen oder Adressen nicht fest in Vorlage oder Abfragen ein. Kopiere keine Quellseiten in den Eingang, verbirg keine Fehler, starte keine Quellknoten neu und ändere das vorbereitete Gateway nicht. Die konfigurierten Mitglieder und Ports müssen bei Inventaränderungen maßgeblich bleiben.

Zusammenfassung

Du hast echte Programm- und Veranstaltungsortdienste durch aus dem Inventar abgeleitete Routen verbunden, die Website und ihren inhaltlich korrekten CSV-Download geprüft und mit einem Handler nur geänderte Konfiguration neu geladen. Anschließend hast du eine erreichbare, aber nicht freigegebene Quelle vor dem Schreiben der Routen abgelehnt und die aktuelle Website erhalten. Das nächste unabhängige Lab wechselt Mitglieder und bewahrt die alte Quelle samt Daten.