Zusammenstellen und Ausführen eines Playbooks mit benutzerdefinierten Rollen, Git und Systemrollen
In diesem Schritt bringen Sie alle vorbereiteten Komponenten zusammen: Ihre benutzerdefinierte Rolle, die Abhängigkeit von Git und die RHEL System Role. Sie erstellen ein Haupt-Playbook, das diese Rollen orchestriert, um den Entwicklungsserver vollständig zu konfigurieren.
Betrachten Sie diesen Schritt als das Zusammenfügen einer komplexen Maschine aus verschiedenen Teilen – jede Rolle dient einem bestimmten Zweck, und sie arbeiten zusammen, um eine vollständige Webserver-Umgebung zu schaffen. Lassen Sie uns dies in überschaubare Abschnitte aufteilen:
Stellen Sie zunächst sicher, dass Sie sich im Hauptprojektverzeichnis befinden.
cd ~/project
Bevor wir uns mit der Konfiguration befassen, lassen Sie uns verstehen, was wir erstellen:
- Ansible-Konfiguration: Legt fest, wie sich Ansible verhält und wo es Dateien findet
- Inventory: Definiert, welche Server verwaltet werden sollen (in unserem Fall localhost)
- Variablen: Speichern Daten, die unsere Rollen verwenden werden (Entwicklerinformationen, SELinux-Einstellungen)
- Benutzerdefinierter Rolleninhalt: Die eigentlichen Tasks, die Entwicklungsumgebungen konfigurieren
- Haupt-Playbook: Der Orchestrator, der alles in der richtigen Reihenfolge ausführt
1. Erstellen der Ansible-Konfiguration und des Inventars
Die Datei ansible.cfg
ist wie eine Konfigurationsdatei, die Ansible mitteilt, wie es sich verhalten soll. Ohne sie müssten Sie Pfade und Optionen in jedem Befehl angeben. Mit ihr weiß Ansible automatisch, wo es Ihre Rollen, Collections und Ihr Inventar findet.
Erstellen Sie die Datei ansible.cfg
mit nano
. Diese Datei teilt Ansible mit, wo es Ihre Rollen, Collections und Ihr Inventar finden kann.
nano ansible.cfg
Fügen Sie den folgenden Inhalt hinzu. Lassen Sie uns jede Zeile verstehen:
[defaults]
inventory = inventory ## Weist Ansible an, eine Datei namens 'inventory' zu verwenden
roles_path = roles ## Suche nach Rollen im Verzeichnis 'roles'
collections_paths = collections ## Suche nach Collections im Verzeichnis 'collections'
host_key_checking = False ## Überspringe SSH-Schlüsselüberprüfung (nützlich für Laborumgebungen)
[privilege_escalation]
become = True ## Verwende automatisch sudo für Tasks, die es benötigen
Was jede Einstellung bewirkt:
inventory = inventory
: Anstatt jedes Mal -i inventory
einzugeben, verwendet Ansible automatisch diese Datei
roles_path = roles
: Ansible sucht nach Rollen im Verzeichnis roles
collections_paths = collections
: Ansible findet hier Ihre installierten Collections
host_key_checking = False
: Verhindert SSH-Schlüsselüberprüfungsfehler in Laborumgebungen
become = True
: Führt Tasks bei Bedarf automatisch mit erhöhten Rechten aus
Speichern und beenden Sie nano
(Drücken Sie Ctrl+X
, dann Y
, dann Enter
).
Die Inventardatei teilt Ansible mit, welche Maschinen verwaltet werden sollen. In unserem Fall konfigurieren wir die lokale Maschine.
nano inventory
Fügen Sie die folgende Zeile hinzu:
localhost ansible_connection=local
Was das bedeutet:
localhost
: Der Name unseres Zielhosts
ansible_connection=local
: Anstatt SSH wird eine lokale Verbindung verwendet (da wir dieselbe Maschine verwalten, auf der wir Ansible ausführen)
Speichern und beenden Sie nano
.
2. Definieren von Rollenvariablen
Variablen in Ansible sind wie Einstellungen, die Ihre Rollen verwenden können. Anstatt Werte wie Benutzernamen oder Portnummern direkt in Ihre Tasks zu schreiben, definieren Sie diese in Variablendateien. Dies macht Ihre Automatisierung flexibel und wiederverwendbar.
Das Verzeichnis group_vars/all
ist ein spezieller Speicherort, an dem Ansible automatisch Variablen für alle Hosts lädt. Jede YAML-Datei in diesem Verzeichnis wird für Ihre Playbooks und Rollen verfügbar.
Erstellen Sie die Verzeichnisstruktur für Variablen, die für alle Hosts gelten:
mkdir -p group_vars/all
Erstellen Sie nun eine Datei, um die Entwicklerinformationen zu definieren. Diese Daten werden von Ihrer benutzerdefinierten Rolle verwendet, um Benutzerkonten und Webkonfigurationen zu erstellen.
nano group_vars/all/developers.yml
Fügen Sie den folgenden Inhalt hinzu:
---
web_developers:
- username: jdoe ## Erster Entwickler
port: 9081 ## Benutzerdefinierter Port für die Website dieses Entwicklers
- username: jdoe2 ## Zweiter Entwickler
port: 9082 ## Benutzerdefinierter Port für die Website dieses Entwicklers
Was diese Datenstruktur bedeutet:
web_developers
: Eine Liste, die Entwicklerinformationen enthält
- Jeder Entwickler hat einen
username
und einen port
- Ihre benutzerdefinierte Rolle durchläuft diese Liste, um Konfigurationen für jeden Entwickler zu erstellen
Speichern und beenden.
Erstellen Sie als Nächstes eine Variablendatei für die SELinux-Konfiguration. SELinux (Security-Enhanced Linux) ist ein Sicherheitsmodul, das steuert, was Anwendungen tun können.
nano group_vars/all/selinux.yml
Fügen Sie den folgenden Inhalt hinzu:
---
selinux_state: enforcing ## Setzt SELinux in den enforcing-Modus (höchste Sicherheit)
selinux_ports: ## Liste der Ports, die Apache verwenden darf
- ports: "9081" ## Port 9081 zulassen
proto: "tcp" ## Protokoll: TCP
setype: "http_port_t" ## SELinux-Typ: HTTP-Port
state: "present" ## Diese Regel hinzufügen
- ports: "9082" ## Port 9082 zulassen
proto: "tcp" ## Protokoll: TCP
setype: "http_port_t" ## SELinux-Typ: HTTP-Port
state: "present" ## Diese Regel hinzufügen
Verständnis der SELinux-Einstellungen:
selinux_state: enforcing
: SELinux blockiert aktiv unbefugte Aktionen
selinux_ports
: Eine Liste von Portkonfigurationen
http_port_t
: Der SELinux-Typ, der es Apache erlaubt, sich an Ports zu binden
- Standardmäßig kann Apache nur die Ports 80 und 443 verwenden; wir müssen 9081 und 9082 explizit zulassen
Speichern und beenden.
3. Befüllen der benutzerdefinierten Rolle
Ihre Rolle apache.developer_configs
hat derzeit die Verzeichnisstruktur, aber keinen tatsächlichen Inhalt. Wir müssen hinzufügen:
- Templates: Dateien, die Variablen enthalten können (mit Jinja2-Syntax)
- Tasks: Die eigentliche Arbeit, die Ansible ausführen wird
- Handlers: Spezielle Tasks, die nur bei Benachrichtigung ausgeführt werden (z. B. Dienste neu starten)
- Metadaten: Informationen über Rollenabhängigkeiten
Templates ermöglichen es Ihnen, Konfigurationsdateien zu erstellen, die sich basierend auf Ihren Variablen anpassen. Die Erweiterung .j2
zeigt an, dass es sich um eine Jinja2-Vorlage handelt.
nano roles/apache.developer_configs/templates/developer.conf.j2
Fügen Sie den folgenden Inhalt hinzu:
{% for dev in web_developers %}
Listen {{ dev.port }}
<VirtualHost *:{{ dev.port }}>
ServerAdmin webmaster@localhost
DocumentRoot /var/www/{{ dev.username }}
<Directory /var/www/{{ dev.username }}>
Options Indexes FollowSymLinks
AllowOverride None
Require all granted
</Directory>
</VirtualHost>
{% endfor %}
Verständnis der Template-Syntax:
{% for dev in web_developers %}
: Startet eine Schleife durch die Entwicklerliste
{{ dev.port }}
: Fügt die Portnummer für diesen Entwickler ein
{{ dev.username }}
: Fügt den Benutzernamen für diesen Entwickler ein
{% endfor %}
: Beendet die Schleife
- Das Ergebnis sind separate VirtualHost-Konfigurationen für jeden Entwickler
Was dies erstellt: Für unsere beiden Entwickler generiert diese Vorlage eine Apache-Konfiguration, die:
- Apache auf den Ports 9081 und 9082 lauschen lässt
- Virtual Hosts erstellt, die Inhalte von
/var/www/jdoe
und /var/www/jdoe2
bedienen
- Angemessene Berechtigungen für jedes Verzeichnis festlegt
Speichern und beenden.
Tasks sind die eigentliche Arbeit, die Ansible ausführt. Jeder Task verwendet ein Ansible-Modul, um etwas Bestimmtes zu erreichen.
nano roles/apache.developer_configs/tasks/main.yml
Fügen Sie den folgenden Inhalt hinzu und lassen Sie uns jeden Task verstehen:
---
## Task 1: Erstellen von Benutzerkonten für jeden Entwickler
- name: Create developer user accounts
ansible.builtin.user: ## Verwendet das 'user'-Modul
name: "{{ item.username }}" ## Erstellt Benutzer mit diesem Namen
state: present ## Stellt sicher, dass der Benutzer existiert
loop: "{{ web_developers }}" ## Führt dies für jeden Entwickler in der Liste aus
## Task 2: Erstellen von Webverzeichnissen für jeden Entwickler
- name: Create developer web root directories
ansible.builtin.file: ## Verwendet das 'file'-Modul
path: "/var/www/{{ item.username }}" ## Erstellt dieses Verzeichnis
state: directory ## Stellt sicher, dass es ein Verzeichnis ist
owner: "{{ item.username }}" ## Setzt den Besitzer
group: "{{ item.username }}" ## Setzt die Gruppe
mode: "0755" ## Setzt Berechtigungen (rwxr-xr-x)
loop: "{{ web_developers }}"
## Task 3: Erstellen einer Beispielwebseite für jeden Entwickler
- name: Create a sample index.html for each developer
ansible.builtin.copy: ## Verwendet das 'copy'-Modul
content: "Welcome to {{ item.username }}'s dev space\n" ## Dateiinhalt
dest: "/var/www/{{ item.username }}/index.html" ## Wo die Datei abgelegt werden soll
owner: "{{ item.username }}" ## Dateibesitzer
group: "{{ item.username }}" ## Dateigruppe
mode: "0644" ## Dateiberechtigungen (rw-r--r--)
loop: "{{ web_developers }}"
## Task 4: Bereitstellen der Apache-Konfigurationsdatei
- name: Deploy developer apache configs
ansible.builtin.template: ## Verwendet das 'template'-Modul
src: developer.conf.j2 ## Quelldatei der Vorlage
dest: /etc/httpd/conf.d/developer.conf ## Ziel auf dem Server
mode: "0644" ## Dateiberechtigungen
notify: restart apache ## Löst den restart-Handler aus, wenn dies geändert wird
Verständnis wichtiger Konzepte:
loop
: Wiederholt den Task für jedes Element in der Liste
{{ item.username }}
: Bezieht sich auf den Benutzernamen des aktuellen Elements in der Schleife
notify: restart apache
: Wenn dieser Task Änderungen vornimmt, löst er einen Handler namens "restart apache" aus
- Dateiberechtigungen:
0755
bedeutet, dass der Besitzer lesen/schreiben/ausführen kann, andere lesen/ausführen können; 0644
bedeutet, dass der Besitzer lesen/schreiben kann, andere nur lesen können
Speichern und beenden.
Handler sind spezielle Tasks, die nur ausgeführt werden, wenn sie von anderen Tasks benachrichtigt werden. Sie werden typischerweise für Aktionen wie das Neustarten von Diensten verwendet.
nano roles/apache.developer_configs/handlers/main.yml
Fügen Sie den folgenden Inhalt hinzu:
---
- name: restart apache ## Dieser Name muss mit der 'notify:'-Anweisung übereinstimmen
ansible.builtin.service: ## Verwendet das 'service'-Modul
name: httpd ## Der Dienstname (Apache heißt auf RHEL 'httpd')
state: restarted ## Startet den Dienst neu
Warum Handler verwenden?
- Effizienz: Der Dienst wird nur neu gestartet, wenn sich die Konfiguration tatsächlich geändert hat
- Reihenfolge: Alle Tasks werden zuerst ausgeführt, dann alle Handler am Ende
- Idempotenz: Mehrere Tasks können denselben Handler benachrichtigen, aber er wird nur einmal ausgeführt
Speichern und beenden.
Schließlich müssen wir Ansible mitteilen, dass unsere benutzerdefinierte Rolle von der zuvor installierten Rolle infra.apache
abhängt.
nano roles/apache.developer_configs/meta/main.yml
Ersetzen Sie den Inhalt der Datei durch:
---
dependencies:
- role: infra.apache ## Diese Rolle muss vor unserer benutzerdefinierten Rolle ausgeführt werden
Was dies bewirkt:
- Wenn Ansible
apache.developer_configs
ausführt, wird automatisch zuerst infra.apache
ausgeführt
- Dies stellt sicher, dass Apache installiert ist und konfiguriert wird, bevor wir unsere benutzerdefinierten Konfigurationen hinzufügen
- Abhängigkeiten werden in der Reihenfolge ausgeführt, in der sie aufgelistet sind
Speichern und beenden.
4. Zusammenstellen und Ausführen des Haupt-Playbooks
Ein Playbook ist wie ein Rezept, das Ansible sagt, was es tun soll und in welcher Reihenfolge. Unser Playbook wird:
- SELinux-Einstellungen konfigurieren (pre_tasks)
- Unsere Rollen ausführen (einschließlich der Abhängigkeitskette)
Erstellen Sie die Haupt-Playbook-Datei:
nano web_dev_server.yml
Fügen Sie den folgenden Inhalt mit detaillierten Erklärungen hinzu:
---
- name: Configure Dev Web Server ## Name des Playbooks
hosts: localhost ## Ausführen auf localhost
pre_tasks: ## Tasks, die vor den Rollen ausgeführt werden
## Task 1: SELinux-Modus konfigurieren
- name: Set SELinux to enforcing mode
ansible.posix.selinux: ## Modul aus der Collection ansible.posix
policy: targeted ## Verwendet die SELinux-Richtlinie 'targeted'
state: "{{ selinux_state }}" ## Verwendet die von uns definierte Variable
when: selinux_state is defined ## Nur ausführen, wenn die Variable definiert ist
## Task 2: SELinux-Ports konfigurieren
- name: Configure SELinux ports for Apache
community.general.seport: ## Modul aus der Collection community.general
ports: "{{ item.ports }}" ## Portnummer
proto: "{{ item.proto }}" ## Protokoll (tcp)
setype: "{{ item.setype }}" ## SELinux-Typ (http_port_t)
state: "{{ item.state }}" ## present oder absent
loop: "{{ selinux_ports }}" ## Schleife durch unsere Portliste
when: selinux_ports is defined ## Nur ausführen, wenn die Variable definiert ist
roles: ## Auszuführende Rollen
- apache.developer_configs ## Unsere benutzerdefinierte Rolle (die infra.apache auslöst)
Verständnis der Ausführungsreihenfolge:
pre_tasks
: Die SELinux-Konfiguration wird zuerst ausgeführt
roles
: Zuerst werden die Rollenabhängigkeiten ausgeführt (infra.apache
), dann unsere benutzerdefinierte Rolle
handlers
: Alle benachrichtigten Handler werden zuletzt ausgeführt
Warum diese Reihenfolge wichtig ist:
- SELinux muss konfiguriert sein, bevor Apache versucht, sich an benutzerdefinierte Ports zu binden
- Apache muss installiert sein, bevor wir Virtual Hosts konfigurieren können
- Dienstneustarts erfolgen, nachdem alle Konfigurationen abgeschlossen sind
Speichern und beenden.
Jetzt sind Sie bereit, Ihre vollständige Automatisierung auszuführen:
ansible-playbook web_dev_server.yml
Das Playbook wird ausgeführt und Sie sehen eine detaillierte Ausgabe. Hier ist, was Sie erwarten können:
PLAY [Configure Dev Web Server] *************************************************
TASK [Gathering Facts] **********************************************************
ok: [localhost] ## Ansible sammelt Systeminformationen
TASK [Set SELinux to enforcing mode] *******************************************
changed: [localhost] ## SELinux-Modus wurde geändert
TASK [Configure SELinux ports for Apache] **************************************
changed: [localhost] => (item={'ports': '9081', 'proto': 'tcp', 'setype': 'http_port_t', 'state': 'present'})
changed: [localhost] => (item={'ports': '9082', 'proto': 'tcp', 'setype': 'http_port_t', 'state': 'present'})
TASK [infra.apache : Ensure Apache is installed.] *******************************
changed: [localhost] ## Apache-Paket wurde installiert
TASK [apache.developer_configs : Create developer user accounts] ****************
changed: [localhost] => (item={'username': 'jdoe', 'port': 9081})
changed: [localhost] => (item={'username': 'jdoe2', 'port': 9082})
TASK [apache.developer_configs : Create developer web root directories] *********
changed: [localhost] => (item={'username': 'jdoe', 'port': 9081})
changed: [localhost] => (item={'username': 'jdoe2', 'port': 9082})
TASK [apache.developer_configs : Create a sample index.html for each developer] *
changed: [localhost] => (item={'username': 'jdoe', 'port': 9081})
changed: [localhost] => (item={'username': 'jdoe2', 'port': 9082})
TASK [apache.developer_configs : Deploy developer apache configs] ***************
changed: [localhost] ## Konfigurationsdatei wurde erstellt
RUNNING HANDLER [apache.developer_configs : restart apache] *********************
changed: [localhost] ## Apache wurde neu gestartet
PLAY RECAP **********************************************************************
localhost : ok=17 changed=12 unreachable=0 failed=0 skipped=3 rescued=0 ignored=0
Sie haben erfolgreich ein komplexes Playbook zusammengestellt und ausgeführt, das mehrere Rollen aus verschiedenen Quellen kombiniert, um eine vollständige Webentwicklungs-Umgebung zu erstellen!