Zusammenstellen und Ausführen eines Playbooks mit benutzerdefinierten, 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 erfüllt einen 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 Aufgaben, die 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 das Inventar findet.
Erstellen Sie die Datei ansible.cfg mit nano. Diese Datei teilt Ansible mit, wo es Ihre Rollen, Collections und das Inventar findet.
nano ansible.cfg
Fügen Sie den folgenden Inhalt hinzu. Lassen Sie uns jede Zeile verstehen:
[defaults]
inventory = inventory
roles_path = roles
collections_paths = collections
host_key_checking = False
[privilege_escalation]
become = True
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 Aufgaben bei Bedarf automatisch mit erhöhten Berechtigungen 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 zu verwenden, werden lokale Verbindungen genutzt (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 Aufgaben zu schreiben, definieren Sie diese in Variablendateien. Dies macht Ihre Automatisierung flexibel und wiederverwendbar.
Das Verzeichnis group_vars/all ist ein spezieller Ort, 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 wird diese Liste durchlaufen, um Konfigurationen für jeden Entwickler zu erstellen
Speichern und beenden.
Als Nächstes erstellen Sie 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 ## SELinux in den Modus "enforcing" setzen (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ührt
- Handlers: Spezielle Aufgaben, die nur ausgeführt werden, wenn sie benachrichtigt 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 ein Jinja2-Template 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 erstellt dieses Template 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
- Geeignete 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: ## Verwenden des 'user'-Moduls
name: "{{ item.username }}" ## Benutzer mit diesem Namen erstellen
state: present ## Sicherstellen, dass der Benutzer existiert
loop: "{{ web_developers }}" ## Dies für jeden Entwickler in der Liste tun
## Task 2: Erstellen von Webverzeichnissen für jeden Entwickler
- name: Create developer web root directories
ansible.builtin.file: ## Verwenden des 'file'-Moduls
path: "/var/www/{{ item.username }}" ## Dieses Verzeichnis erstellen
state: directory ## Sicherstellen, dass es ein Verzeichnis ist
owner: "{{ item.username }}" ## Besitzer festlegen
group: "{{ item.username }}" ## Gruppe festlegen
mode: "0755" ## Berechtigungen festlegen (rwxr-xr-x)
loop: "{{ web_developers }}"
## Task 3: Erstellen einer Beispiel-Webseite für jeden Entwickler
- name: Create a sample index.html for each developer
ansible.builtin.copy: ## Verwenden des 'copy'-Moduls
content: "Welcome to {{ item.username }}'s dev space\n" ## Dateiinhalt
dest: "/var/www/{{ item.username }}/index.html" ## Speicherort der Datei
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: ## Verwenden des 'template'-Moduls
src: developer.conf.j2 ## Quelldatei des Templates
dest: /etc/httpd/conf.d/developer.conf ## Ziel auf dem Server
mode: "0644" ## Dateiberechtigungen
notify: restart apache ## Den Neustart-Handler auslösen, wenn dies geändert wird
Verständnis wichtiger Konzepte:
loop: Wiederholt die Aufgabe für jedes Element in der Liste
{{ item.username }}: Bezieht sich auf den Benutzernamen des aktuellen Elements in der Schleife
notify: restart apache: Wenn diese Aufgabe Änderungen vornimmt, löst sie 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.
Handlers sind spezielle Aufgaben, die nur ausgeführt werden, wenn sie von anderen Aufgaben 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: ## Verwenden des 'service'-Moduls
name: httpd ## Der Dienstname (Apache heißt auf RHEL 'httpd')
state: restarted ## Den Dienst neu starten
Warum Handler verwenden?
- Effizienz: Der Dienst wird nur neu gestartet, wenn sich die Konfiguration tatsächlich geändert hat
- Reihenfolge: Alle Aufgaben werden zuerst ausgeführt, dann alle Handler am Ende
- Idempotenz: Mehrere Aufgaben 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 zuerst automatisch infra.apache ausgeführt
- Dies stellt sicher, dass Apache installiert und konfiguriert ist, bevor wir unsere benutzerdefinierten Konfigurationen hinzufügen
- Abhängigkeiten werden in der Reihenfolge ausgeführt, in der sie aufgeführt sind
Speichern und beenden.
4. Zusammenstellen und Ausführen des Haupt-Playbooks
Ein Playbook ist wie ein Rezept, das Ansible sagt, was zu tun ist 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 ## Auf localhost ausführen
pre_tasks: ## Aufgaben, 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 ## Die 'targeted' SELinux-Policy verwenden
state: "{{ selinux_state }}" ## Die von uns definierte Variable verwenden
when: selinux_state is defined ## Nur ausführen, wenn die Variable definiert ist
## Task 2: SELinux-Ports für Apache 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 }}" ## Durch unsere Portliste iterieren
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: Rollenabhängigkeiten werden 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 detaillierte Ausgaben. Hier ist, was Sie erwarten können (zum Beispiel):
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!