Konfigurationsvorlagen auswerten und validieren

AnsibleBeginner
Jetzt üben

Einführung

Vorlagenautomatisierung erhält eine einzige Quelle und erzeugt daraus Konfiguration anhand der Eingaben jedes Hosts. Sie erzeugen Dateien aus Variablen und Facts, transformieren einen Header mit einem integrierten Jinja-Filter, wählen einen bedingten Zweig und laden validierte nginx-Konfiguration über einen Handler. Tatsächliche HTTP-Anfragen und ein abgelehnter ungültiger Kandidat zeigen den Unterschied zwischen Quelltext, verwalteten Dateien und aktivem Dienstverhalten.

Hostvariablen und Facts in verwalteten Inhalt umsetzen

In diesem Schritt erstellen Sie eine Seitenvorlage und erzeugen aus derselben Quelle unterschiedliche tatsächliche Dateien auf beiden Zielen.

Auf den vorbereiteten Knoten ist nginx als Voraussetzung installiert. Ihre Arbeit besteht im Erzeugen und Anwenden von Konfiguration statt einer erneuten Paketinstallation. Vorlagen werden auf dem Controller im Variablenkontext jedes Ziels ausgewertet und anschließend an verwaltete Ziele übertragen.

Wechseln Sie ins Controller-Projekt und erstellen Sie ein Vorlagenverzeichnis. mkdir -p erstellt das Verzeichnis bei Bedarf, ohne bei bereits vorhandenem Verzeichnis fehlzuschlagen:

cd /home/labex/project
mkdir -p templates

Definieren Sie typisierte Hosteingaben. Umgebung und Dienstport unterscheiden sich, und die Werte von maintenance_mode ohne Anführungszeichen sind boolesche YAML-Werte:

cat > host_vars/web1.yml <<'YAML'
environment_label: development
service_port: 8081
maintenance_mode: true
YAML
cat > host_vars/web2.yml <<'YAML'
environment_label: production
service_port: 8082
maintenance_mode: false
YAML

Jinja-Ausdrücke in doppelten geschweiften Klammern fügen Werte in Text ein. Die Endung .j2 ist eine hilfreiche Konvention für Vorlagenquellen, keine Anforderung an den verwalteten Zieldateinamen. Erstellen Sie eine Quelle, die den aktuellen Inventarnamen, die Umgebungsvariable und den ermittelten Distributions-Fact verwendet:

cat > templates/page.txt.j2 <<'JINJA'
host={{ inventory_hostname }}
environment={{ environment_label }}
distribution={{ ansible_facts.distribution }}
JINJA

Verwenden Sie das template-Modul zum Auswerten der Vorlage. Copy würde normalerweise Quellbytes ohne Interpretation dieser Jinja-Ausdrücke übertragen. Erfassen Sie Facts vor der Verwendung des Distributionswerts und deklarieren Sie ausdrückliche verwaltete Eigentümer und Berechtigungen:

cat > templates.yml <<'YAML'
- name: Render host-specific website content
  hosts: all
  gather_facts: true
  become: true
  tasks:
    - name: Prepare the rendered site directory
      ansible.builtin.file:
        path: /var/www/template-site
        state: directory
        owner: root
        group: root
        mode: "0755"

    - name: Render each host's website content
      ansible.builtin.template:
        src: templates/page.txt.j2
        dest: /var/www/template-site/index.html
        owner: root
        group: root
        mode: "0644"
YAML

Erzeugen Sie beide verwalteten Seiten:

ansible-playbook templates.yml --syntax-check
ansible-playbook templates.yml

Lesen Sie die tatsächlichen Zieldateien:

ansible all -m ansible.builtin.command -a 'cat /var/www/template-site/index.html'

Jede Seite sollte ihren eigenen Host, die passende Umgebung development/production und distribution=Ubuntu identifizieren. Der Controller behält eine wiederverwendbare Quelle, während die beiden verwalteten Ausgaben unterschiedlich sind.

Einen integrierten Filter und einen bedingten Konfigurationszweig ergänzen

In diesem Schritt erzeugen Sie eine gültige nginx-Konfiguration, die das HTTP-Verhalten anhand der Eingaben jedes Hosts ändert.

Ein Jinja-Filter transformiert einen Wert mit dem Pipe-Symbol. upper ist ein integrierter Filter, der Text in Großbuchstaben umwandelt; er ist kein benutzerdefiniertes Plugin. Jinja-Steueranweisungen verwenden Begrenzungen aus Prozentzeichen und geschweiften Klammern. Der folgende if-/else-/endif-Zweig wählt anhand der booleschen Eingabe einen Wartungsheader aus.

Erstellen Sie eine vollständige nginx-Konfigurationsvorlage. Port, Umgebungsheader und Wartungsheader stammen alle aus hostspezifischen Daten. Die Einstellungen root und index liefern die bereits erzeugte Seite aus:

cat > templates/nginx.conf.j2 <<'JINJA'
events {}
http {
    server_tokens off;
    server {
        listen {{ service_port }};
        root /var/www/template-site;
        index index.html;
        add_header X-Environment "{{ environment_label | upper }}" always;
{% if maintenance_mode %}
        add_header X-Maintenance "enabled" always;
{% else %}
        add_header X-Maintenance "disabled" always;
{% endif %}
    }
}
JINJA

Hängen Sie Konfigurations- und Dienstaufgaben sowie den benannten Reload-Handler an das bestehende Playbook an. Der validate-Befehl der template-Aufgabe testet einen temporären erzeugten Kandidaten (%s), bevor er die verwaltete Konfiguration ersetzt. Eine geänderte gültige Konfiguration benachrichtigt den Handler; die gewöhnliche service-Aufgabe hält nginx am Laufen.

cat >> templates.yml <<'YAML'

    - name: Render and validate the nginx candidate before replacement
      ansible.builtin.template:
        src: templates/nginx.conf.j2
        dest: /etc/nginx/nginx.conf
        owner: root
        group: root
        mode: "0644"
        validate: /usr/sbin/nginx -t -c %s
      notify: Reload nginx

    - name: Keep the rendered site service running
      ansible.builtin.service:
        name: nginx
        state: started

  handlers:
    - name: Reload nginx
      ansible.builtin.service:
        name: nginx
        state: reloaded
YAML

Wenden Sie das vollständige Playbook an:

ansible-playbook templates.yml

Die Konfigurationsaufgabe sollte beide Hosts ändern und den Reload-Handler auslösen. Untersuchen Sie web1 auf Port 8081 und web2 auf Port 8082. curl -i nimmt Antwortheader zusammen mit dem Inhalt auf:

ansible web1 -m ansible.builtin.command -a 'curl --fail --silent --show-error -i http://127.0.0.1:8081/'
ansible web2 -m ansible.builtin.command -a 'curl --fail --silent --show-error -i http://127.0.0.1:8082/'

Web1 sollte X-Environment: DEVELOPMENT und X-Maintenance: enabled zurückgeben; web2 X-Environment: PRODUCTION und X-Maintenance: disabled. Beide Antwortinhalte behalten die korrekte hostspezifische Seite. Header-Datumsangaben variieren; vergleichen Sie die datengesteuerten Werte und den erfolgreichen Status.

Eingaben ändern und einen ungültigen Kandidaten ablehnen

In diesem Schritt aktualisieren Sie dauerhafte Eingaben ohne Bearbeitung der Vorlagen, beobachten das tatsächliche aktive Ergebnis und weisen nach, dass Validierung funktionierende Konfiguration schützt.

Ändern Sie die gespeicherte Umgebung von web1 auf staging und dessen Wartungsmodus auf false; behalten Sie seinen bestehenden Port bei:

cat > host_vars/web1.yml <<'YAML'
environment_label: staging
service_port: 8081
maintenance_mode: false
YAML

Wenden Sie dieselben Quellvorlagen an:

ansible-playbook templates.yml

Seite und Konfiguration von web1 sollten sich ändern und seinen Reload-Handler benachrichtigen; web2 sollte unverändert bleiben. Untersuchen Sie web1 erneut:

ansible web1 -m ansible.builtin.command -a 'curl --fail --silent --show-error -i http://127.0.0.1:8081/'

Sein Inhalt sollte environment=staging zeigen, mit X-Environment: STAGING und X-Maintenance: disabled. Die Vorlagen blieben bei geänderter Eingabe wiederverwendbar.

Testen Sie nun die Kandidatenablehnung. cp sichert die gültige Controller-Quelle zur Wiederherstellung. Ersetzen Sie ausschließlich die nginx-Vorlage durch absichtlich ungültigen Text:

cp templates/nginx.conf.j2 templates/nginx.conf.j2.good
printf 'invalid nginx configuration;\n' > templates/nginx.conf.j2

Die nächste Playbook-Ausführung soll bei der Kandidatenvalidierung fehlschlagen. Das Shell-Zeichen || führt die Nachricht nur nach einem Rückgabewert ungleich null aus und lässt diese Übung mit absichtlichem Fehler weiterlaufen:

ansible-playbook templates.yml || printf 'Expected candidate validation rejection\n'

Lesen Sie den Aufgabenfehler: nginx sollte den temporären Kandidaten ablehnen. Die verwaltete funktionierende Konfiguration muss erhalten bleiben, sodass beide aktiven Dienste weiterhin korrekt antworten sollten:

ansible web1 -m ansible.builtin.command -a 'curl --fail --silent --show-error -i http://127.0.0.1:8081/'
ansible web2 -m ansible.builtin.command -a 'curl --fail --silent --show-error -i http://127.0.0.1:8082/'

mv stellt die gespeicherte gültige Quelle unter ihrem ursprünglichen Dateinamen wieder her. Führen Sie das vollständige Playbook noch einmal aus:

mv templates/nginx.conf.j2.good templates/nginx.conf.j2
ansible-playbook templates.yml

Beide Hosts sollten changed=0, failed=0 und unreachable=0 melden, ohne eingeplanten Reload-Handler. Validierung schützte die aktive Konfiguration, ohne eine Kopie eines ungültigen Kandidaten zum gewünschten Endzustand zu machen.

Zusammenfassung

Sie haben Hostvariablen und Facts mit dem template-Modul umgesetzt, den integrierten Filter upper und einen booleschen Jinja-Zweig verwendet und validierte Konfiguration über einen Handler angewendet. Geänderte Eingaben erzeugten unterschiedliche aktive Ausgabe ohne Umschreiben der Quellen. Ein ungültiger Kandidat wurde vor dem Ersetzen abgelehnt, und wiederhergestellte gültige Vorlagen konvergierten ohne zusätzliche Änderungen.