Ansible - Erweiterte Konfigurationsbeispiel: Roles
Grundlagen
Bevor wir nun in die Welt der roles bei Ansible eintauchen, werfen wir kurz noch einen Blick auf zwei gängige Szenarien:
- Bsp. 1:
Hat man nur eine Aufgabe, wie z.B. den automatisierten Bau eines Freifunk-Offloaders auf Basis eines Raspberry 4B zu bewältigen, liegt es natürlich nahe, ein Playbook anzulegen, in dem alle Schritte nacheinander aufgeführt werden, die zum Erledigen der Aufgabe nötig sind. Ehe man sich versieht hat man am Ende ein Playbook vor Augen welches 390 Zeilen umfasst. So was kann natürlich alsbald doch sehr umfangreich und vor allem pflegeintensiv werden!
- Bsp. 2:
In ambitionierteren Umgebungen hat man es meist mit einer Vielzahl unterschiedlicher Systeme, wie z.B. Web-, Datenbank-, Mail-, Infrastrukturserver und/oder Loadbalancer-Systeme zu tun. In Ihren Aufgabestellungen unterscheiden sich diese doch erheblich, haben aber jedoch in aller Regel eine grundlegende Basisinstallation und Konfiguration. Die sind z.B. Definitionen zu Admin-Acounts, NTP-Client-Definitionen oder z.B. beim MTA-Relayhost. Nun könnte man natürlich auch hier pragmatisch vorgehend und ein Playbook mit diesen grundlegenden Einzelaufgaben wie z.B. Userkontenanlage oder NTP-Clientinstallation und -konfiguration als Vorlage erstellen wollen. So eine Vorlage könnte man dann entsprechend vervielfältigen und mit den Hostspezifischen Installations- und Konfigurationsanweisung anreichern.
Aus folgenden Gründen ist so ein Vorgehen aber nicht zu empfehlen:- Bei Änderungen an grundlegenden gemeinsamen Punkte, wie z.B. neuer Mitarbeiter, müsste man später jedes einzelne Playbook anfassen und anpassen.
- Je nach Freunde am Umgang mit Ansible, kann im Arbeitsverzeichnis des Ansible-Nutzers es durch die vielen Playbooks und/oder inkludierten Konfigurationsdateien sehr schnell unübersichtlich werden.
- Daten wie Aufgaben (tasks), Variablen (vars) oder „Spezielle Aufgaben“ (handlers) sind so mehrfach definiert und vorhanden, was eine fortlaufende Pflege mehr als erschwert.
- Da es keine Trennung zwischen variablen Daten und den Aufgaben (tasks und handlers) gibt, ist es sehr schwierig unser spezielles Ansible-Playbook oder auch Teile daraus wiederzuverwenden oder mit anderen zu teilen bzw. weiterzugeben. In aller Regel sind nämlich die Daten eines Playbook organisations- und firmenspezifisch, der dazu verwendete Code natürlich allgemeingültig und allgemein an- und verwendbar. Sind die Daten und der Code nun in einer großen Datei (Playbook) zusammengefasst, ist es damit nicht mehr möglich Inhalte zu teilen oder wiederzuverwenden!
Wenn wir das Thema nun nüchtern und wertfrei betrachten werden wir feststellen, dass wir so eine Vielzahl von Systemen nicht auf Dauer ohne große Aufwände mit Ansible verwalten können. Um nun diese Herausforderungen elegant zu lösen bringt uns Ansible die Funktion der Rollen (roles) mit.
Rollen sind im Grunde nichts anderes als Verzeichnisse, die auf eine bestimmte Art und Weise angelegt sind. Rollen folgen vordefinierten Verzeichnis-Layout-Konventionen und erwarten, dass sich dabei die zugehörigen Komponenten in dem für sie vorgesehenen Verzeichnispfad befindet. Bei der Grundkonfiguration unseres Ansible-Hosts hatte wir bereits diese Verzeichnisstruktur beim Anlegen des Ansible: Directory Layout angelegt.
/home/ansible/ansible/roles/
└── roles # Verzeichnis für die einzelnen (unterschiedlichen) Rollen
└── common # Verzeichnis "role" common mit seinen entsprechenden Definitionen - Vorlage zum Kopieren
├── defaults # Verzeichnis "defaults"
│ └── main.yml # Standardvariablen mit niedrigerer Priorität für diese Rolle
├── files # Verzeichnis "files"
│ └── main.yml # (Skript-)Dateien zur Verwendung als Kopier- bzw. Script-Rressource
├── handlers # Verzeichnis "handlers"
│ └── main.yml # Datei mit den Definitionen zu den rollenspezifischen "handlers"
├── library # Verzeichnis für benutzerdefinierte Module einer der Rolle (role) "common"
├── lookup_plugin # Verzeichnis für weitere Arten von Plugins, wie in diesem Fall "lookup"
├── meta # Verzeichnis "meta" für Rollenspezifische Definitionen/Abhängigkeiten
│ └── main.yml # Datei mit Rollenspezifischen Definitionen
├── module_utils # Verzeichnis "module_utils", die benutzerdefinierte module_utils der Rollen enthalten könnte
├── tasks # Verzeichnis "tasks" für kleinere Aufgabendateien
│ └── main.yml # Datei für kleinere Aufgaben, falls diese benötigt werden würden
├── templates # Verzeichnis mit den Templates
│ └── main.j2 # Template-Datei mit dem Dateisuffix/-Ende .j2
└── vars # Verzeichnis "vars", mit den zu dieser Rolle zugeordneten Variablen
└── main.yml # Datei mit den Rollenspezifischen Variablen
Diese Kopiervorlage common
brauchen wir nur noch für jede entsprechende Rolle dann kopieren, so z.B. für die Rolle postfix
$ cd ~/ansible/roles $ cp -avr common/ postfix/
Konfigurationsbeispiel
In folgendem Konfigurationsbeispiel wollen wir uns zu folgendem Szenario eine handelbare Lösung genauer betrachten. Wir gehen dabei von folgendem Einsatzszenario aus:
Aufgabenstellung
Es ist ein Webserver mit Hilfe von Ansible zu erstellen. Am Host soll sich der verantwortliche WEB-Admin ruben anmelden können und der Host soll sich des NTP-Servers im der eigenen Zone bedienen. Dies sind Standardkonfigurationsaufgaben, die auf jedem Server in der betreffenden Sicherheitszone zutreffen. Nach der Installation des Webserver-Daemon apache soll dieser konfiguriert, die initiale Homepage Hello World installiert und zum Schluss der Webserver gestartet werden.
Lösung
Als erstes zerlegen wir die Aufgabenstellung in einzelne Arbeitspakete und unterteilen diese Pakete in einzelne Aufgaben, als da wären:
- Basiskonfiguration
- Gruppe für den Webentwickler ruben anlegen (unter CentOS ist dabei die Gruppe gleich dem Benutzernamen).
- User(konto) für den Webentwickler ruben anlegen.
- Initiales Passwort für den Webentwickler ruben setzen.
- NTP-Client
- Installation des NTP-clients chrony
- Sichern der originalen chrony-Konfigurationsdatei
- Konfiguration von chrony
- Starten des NTP-Clients/-Daemon und Sicherstellen dass dieser auch bei einem Systemneustart gestartet wird.
- Host-/Aufgabenspezifische Installation: Apache-Webserver
- Installation des http-Daemon
- Sichern der originalen Apache-Konfigurationsdatei
- Konfigurieren des Apache Webservers
- Kopieren der initialen Webseite nach
DOCUMENT_ROOT
des Apache-Webservers - Starten des Webserver/-Daemon und sicherstellen dass dieser auch bei einem Systemneustart gestartet wird.
Um möglichst für die Zukunft flexibel zu sein, werden wir unser Ansible Playbook oder bessere gesagt den darunter liegenden Code, möglichst flexibel halten. Das bedeutet, dass wir sowohl für die Grundkonfiguration (User/Gruppe anlegen, wie Installation des Chrony-Daemon) wie auch für die spätere Host-/Aufgabenspezifische Installation des Webservers (Apache) eigene Rollen definieren werden. So können wir später die Rollen mühelos erweitern, wenn wir z.B. weitere Dienste wie z.B. einen PHP-Interpreter oder die zum Apachen zugehörige TLS-Konfiguration vornehmen werden.
Folgende Struktur soll definiert werden:
site.yml
- beinhaltet alle Site-spezifischen Playbooks, wie z.B.
- Datenbank
db.yml
(spätere erweiterte Konfiguration) - Mailserver
postfix.yml
(spätere erweiterte Konfiguration) - …
- Webserver
web.yml
- sein zugehöriges Playbook
web.yml
bedient sich der Rollen:base
über die die Benutzeranlage erfolgtchrony
mit Hilfe deren die NTP-Client-Konfiguration erledigt wirdapache
Installation und Konfiguration des Apache Webservers mit Hilfe vontasks
,files
undhandlers
Systemweite Host/Playbook-Definition : site.yml
Zunächst erstellen und befüllen wir der Playbook-Konfigurationsdatei site_generation.yml
. Diese Datei wird später alle Definitionen unserer Systemumgebung enthalten, also nicht nur die für den Apache-Webserver, sondern auch für den Datenbank-, Mail- und sonstige Server. Die spezifischen Playbooks werden dann hier nur noch inkludiert bzw. importiert.
$ vim ~/ansible/playbooks/site_generation.yml
- ~/ansible/playbooks/site_generation.yml
--- # Start des systemweiten Playbooks site_generation.yml - import_playbook: web.yml # Playbook zum Konfigurieren unseres Webservers einbinden ... # Ende unseres systemweiten Playbooks
Webserver Host/Playbook-Definition : web_server.yml
Für die Konfiguration des Webservers an sich verwenden wir dann die Konfigurationsdatei web_server.yml
; die wir in der zuvor angelegten systemweiten Konfigurationsdatei site_generation.yml
inkludiert hatten. Da die Konfiguration auf allen WEB-Hosts erfolgen soll, geben wir beim Parameter hosts
den Namen der Hostgruppe aus unserer Inventory-Definition an. Bei der Definition der Rollen geben wir die drei roles
an, die wir in unseren zuvor angestellten Überlegungen gewählt hatten.
$ vim ~/ansible/playbooks/web.yml
- web_server.yml
--- # Start des Playbooks für den Web-Server - hosts: www roles: - base # Basiskonfiguration (User anlegen) - chrony # Installation und Konfiguration NTP-Client - www # Installation und Konfiguration Apache Webserver ... # Start des Playbooks für den Web-Server
Unser Kopiervorlage common
für die Rollen kopieren wir nun für die gewählten Arbeitspakete (roles), als erstes also für die Rolle base
, bei der wir den verantwortlichen Web-Admin anlegen werden.
$ cd ~/ansible/roles $ cp -avr common/ base/
Unser Playbook-Beispiel 01 passen wir nun an und speichern dieses im Verzeichnis ~/ansible/roles/base/tasks/
unter den Namen main.yml
$ vim ~/ansible/roles/base/tasks/main.yml
- ~/ansible/roles/base/tasks/main.yml
--- # Grundlegende Konfiguration für alle Hosts - name: "***base*** : Gruppe für (WEB-Entwickler) '{{ createuser }}' erstellen" ansible.builtin.group: # https://docs.ansible.com/ansible/latest/modules/group_module.html name: '{{ createuser }}' gid: '{{ createguid }}' state: present - name: "***base*** : WEB-Admin Nutzerkonto für den User '{{ createuser }}' mit frn zugehörigen UID '{{ createguid }}' anlegen un der Gruppe '{{ createuser }}' zuordnen." ansible.builtin.user: # https://docs.ansible.com/ansible/latest/modules/user_module.html name: '{{ createuser }}' comment: '{{ createusername }}' uid: '{{ createguid }}' group: '{{ createuser }}' state: present - name: "***base*** : Initiales Passwort für den WEB-Admin '{{ createuser }}' hinterlegen" ansible.builtin.shell: # https://docs.ansible.com/ansible/latest/modules/shell_module.html cmd: usermod -p $(echo '{{ createpassword }}' | openssl passwd -1 -stdin) {{ createuser }}
Wie wir sehen, beinhaltet diese Datei nur noch die Definition der tasks aber keine Sitespezifischen Variablen, da wir diese in eine separate Date i auslagern werden. Wir könnten als jederzeit diese Datei auf andere Installationsumgebungen portieren oder an interessierte Adminkollegen weitergeben!
Natürlich benötigen wir nun die Definition der Rollenspezifischen Variablen, die je Rolle hier ~/ansible/roles/base/vars/main.yml
abzulegen sind.
$ vim ~/ansible/roles/base/vars/main.yml
- ~/ansible/roles/base/vars/main.yml
--- # Definition der rollenspezifische Variablen createguid : '1010' # GID/UID des Benutzers00 createuser : 'ruben' # Username createusername: 'Ruben Nausch' # Vollständiger Name createpassword: 'M31nP4p4157d3r4113r83573!' # Initialpasswort (ungecrypted!)
Da wir dort ein Passwort vorhalten, werden wir Dank unserer Ansible-Vault-Konfiguration diese Datei nun verschlüsseln.
$ ansyble-vault encrypt ~/ansible/roles/base/vars/main.yml
Die nächste Rolle, die wir konfigurieren müssen, ist die für den NTP-Daemon chrony
. Auch hier kopieren wir zunächst das Default-role-template common.
$ cd ~/ansible/roles $ cp -avr common/ chrony/
Auch hier greifen wir wieder auf das bereits bekannte Playbook-Beispiel 05 zurück, passen dieses an und speichern es im Verzeichnis ~/ansible/roles/chrony/tasks/
unter den Namen main.yml
. Bei diesem Konfigurationsbeispiel besteht das Playbook aber lediglich aus vier tasks, die wir als eigenständige Dateien auslagern und hier nur inkludieren werden.
$ vim ~/ansible/roles/chrony/tasks/main.yml
- ~/ansible/roles/chrony/tasks/main.yml
--- # Hauptinstallations-/Konfigurationsdatei für den Dienst chrony - include: install.yml # Installation - include: config-backup.yml # original-Konfig sichern - include: configure.yml # Konfiguration - include: service.yml # Service starten
Die vier tasks hinterlegen wir dann anschließend in der zugehörigen YML-Datei.
$ vim ~/ansible/roles/chrony/tasks/install.yml
- ~/ansible/roles/chrony/tasks/install.yml
--- - name: "***chrony*** : Installation des Deamon '{{ daemon_name }}' (in der aktuellsten Version)" ansible.builtin.dnf: #https://docs.ansible.com/ansible/latest/modules/dnf_module.html name: '{{ daemon_name }}' state: latest
$ vim ~/ansible/roles/chrony/tasks/config-backup.yml
- ~/ansible/roles/chrony/tasks/config-backup.yml
--- - name: "***chrony*** : 1) Überprüfen ob das Backup der Konfigurationsdatei '{{ config_file }}' bereits existiert" ansible.builtin.stat: # https://docs.ansible.com/ansible/latest/modules/stat_module.html path: /etc/chrony.conf.orig register: stat_result - name: "***chrony*** : 2) Von der bestehenden originalen Konfigurationsdatei '{{ config_file }}' ein Backup '{{ config_file }}'.orig erstellen" ansible.builtin.copy: # https://docs.ansible.com/ansible/latest/modules/copy_module.html remote_src: yes src: '{{ config_file }}' dest: /etc/chrony.conf.orig when: stat_result.stat.exists == False
$ vim ~/ansible/roles/chrony/tasks/configure.yml
- ~/ansible/roles/chrony/tasks/configure.yml
--- - name: "***chrony*** : Template Konfigurationsdatei an Ort und Stelle kopieren und Variablen setzen" ansible.builtin.template: # https://docs.ansible.com/ansible/latest/modules/template_module.html src: templates/chrony-client.conf.j2 dest: "{{ config_file }}"
Das zugehörige Template für die Konfigurationsdatei legen wir im zugehörigen Verzeichnis ~/ansible/roles/chrony/templates
ab.
$ vim ~/ansible/roles/chrony/templates/chrony-client.conf.j2
- ~/ansible/roles/chrony/templates/chrony-client.conf.j2
# Use public servers from the pool.ntp.org project. # Please consider joining the pool (http://www.pool.ntp.org/join.html). {{ chrony_pool }} # Ignore stratum in source selection {{ chrony_stratumweight }} # Record the rate at which the system clock gains/losses time. driftfile /var/lib/chrony/drift # Allow the system clock to be stepped in the first three updates # if its offset is larger than 1 second. makestep 1.0 3 # Enable kernel synchronization of the real-time clock (RTC). rtcsync # In first three updates step the system clock instead of slew # if the adjustment is larger than 10 seconds. {{ chrony_makestep }} # Enable hardware timestamping on all interfaces that support it. #hwtimestamp * # Increase the minimum number of selectable sources required to adjust # the system clock. #minsources 2 # Allow NTP client access from local network. #allow 192.168.0.0/16 # Serve time even if not synchronized to a time source. #local stratum 10 # Specify file containing keys for NTP authentication. keyfile /etc/chrony.keys # Get TAI-UTC offset and leap seconds from the system tz database. leapsectz right/UTC # Specify directory for log files. logdir /var/log/chrony # Select which information is logged. #log measurements statistics tracking
Der task zum Starten des Daemon legen wir im Verzeichnis task
ab.
$ vim ~/ansible/roles/chrony/tasks/service.yml
- ~/ansible/roles/chrony/tasks/service.yml
--- - name: "***chrony*** : Sicherstellen dass der Daemon '{{ daemon_name }}' (beim Systemstart) gestartet wird und läuft" ansible.builtin.service: # https://docs.ansible.com/ansible/latest/modules/service_module.html name: chronyd state: started enabled: yes
Zu guter letzt benötigen wir auch hier eine zur Rolle gehörige Parameter-Datei mit den Definitionen der Variablen.
$ vim ~/ansible/roles/chrony/vars/main.yml
- ~/ansible/roles/chrony/vars/main.yml
--- # Definition der rollenspezifische Variablen zum Dienst chrony daemon_name : chrony config_file : /etc/chrony.conf # chronyd client config-options chrony_pool : "server time.dmz.nausch.org iburst" chrony_stratumweight: "stratumweight 0" chrony_makestep : "makestep 10 3"
Alle bisher getroffenen Konfigurationseinstellungen gelten für alle Applikations-Hosts und wir müssen lediglich die beiden Rollen base
und chrony
bei den entsprechenden Playbook-Dateien includieren!
Nun folgt der Webserverspezifische Teil unseres Ansible-Musterkonfiguration eines Webserversmit der Definition der Role www
. Zunächst benötigen wir natürlich auch für diese Rolle die altbekannte Verzeichnisstruktur.
$ cd ~/ansible/roles $ cp -avr common/ www/
Angelehnt an die Rolle chrony
definieren wir auch hier als erstes das playbook mit fünf einzelnen tasks, die wir als eigenständige Dateien auslagern und hier nur includieren werden. In dieses Falle sindes fünf tasks, also einer mehr wie bei der Rolle chrony
, da wir ja hier unsere initialen Webseite nach DOCUMENT_ROOT
des Apache-Webservers noch kopieren wollen.
$ vim ~/ansible/roles/www/tasks/main.yml
- ~/ansible/roles/www/tasks/main.yml
--- # Hauptinstallations-/Konfigurationsdatei für den Apache-Webserver - include: install.yml # Installation - include: config-backup.yml # original-Konfig sichern - include: configure.yml # Konfiguration - include: content.yml # Initiale Webseite befüllen - include: service.yml # Service starten
Da wir das Rad ja bekanntlicher Weise nicht 2x erfinden müssen, greifen wir bei der Konfiguration der einzelnen tasks der Rolle www
auf altbewährtes, nämlich der Konfigurationsvorlage der zuvor erstellten Rolle chrony
zurück. Wir kopieren uns die Datei und verändern diese entsprechend.
$ cp ~/ansible/roles/chrony/tasks/install.yml ~/ansible/roles/www/tasks/install.yml $ vim ~/ansible/roles/www/tasks/install.yml
- ~/ansible/roles/www/tasks/install.yml
--- - name: "***www*** : Installation des Deamon '{{ daemon_name }}' (in der aktuellsten Version)" ansible.builtin.dnf: #https://docs.ansible.com/ansible/latest/modules/dnf_module.html name: '{{ daemon_name }}' state: latest
Ähnlich verfahren wir mit dem task zum Sichern der originalen Konfigurationsdatei config-backup.yml
sowie zum Konfigurieren des Daemon configure.yml
.
$ cp ~/ansible/roles/chrony/tasks/config-backup.yml ~/ansible/roles/www/tasks/config-backup.yml $ vim ~/ansible/roles/www/tasks/config-backup.yml
- ~/ansible/roles/www/tasks/config-backup.yml
--- - name: "***www*** : 1) Überprüfen ob das Backup der Konfigurationsdatei '{{ config_file }}' bereits existiert" ansible.builtin.stat: # https://docs.ansible.com/ansible/latest/modules/stat_module.html path: '{{ backup_file }}' register: stat_result - name: "***www*** : 2) Von der bestehenden originalen Konfigurationsdatei '{{ config_file }}' ein Backup '{{ backup_file }}' erstellen" copy: # https://docs.ansible.com/ansible/latest/modules/copy_module.html remote_src: yes src: '{{ config_file }}' dest: '{{ backup_file }}' when: stat_result.stat.exists == False
$ cp ~/ansible/roles/chrony/tasks/configure.yml ~/ansible/roles/www/tasks/configure.yml $ vim ~/ansible/roles/www/tasks/configure.yml
- ~/ansible/roles/www/tasks/configure.yml
--- - name: "***www*** : Template Konfigurationsdatei an Ort und Stelle kopieren und Variablen setzen" ansible.builtin.template: # https://docs.ansible.com/ansible/latest/modules/template_module.html src: templates/httpd-server.conf.j2 dest: "{{ config_file }}"
Auch hier benötigen wir eine Datei, in der die Variablen für den Task www vorgehalten werden.
$ vim ~/ansible/roles/www/vars/main.yml
- ~/ansible/roles/www/vars/main.yml
--- # Definition der rollenspezifische Variablen zum Apache-Webserver httpd daemon_name : httpd config_file : /etc/httpd/conf/httpd.conf backup_file : /etc/httpd/conf/httpd.conf.orig # httpd-Server config-options httpd_server_admin : "ServerAdmin webmaster@nausch.org" httpd_server_http_header : "ServerTokens Prod\nServerSignature Off\nHeader always unset \"X-Powered-By\"\nHeader unset \"X-Powered-By\"" httpd_server_extendedstatus: "ExtendedStatus On" httpd_server_traceenable : "TraceEnable off"
Zu guter letzt müssen wir natürlich auch noch Sorge Tragen dass der HTTP-Daemon läuft und beim Systemstart auch geladen wird. Auch hier kopieren wir uns der Einfachheit halber das passende Gegenstück aus unserem Erfahrungsschatz.
$ cp ~/ansible/roles/chrony/tasks/service.yml ~/ansible/roles/www/tasks/service.yml $ vim ~/ansible/roles/www/tasks/service.yml
- ~/ansible/roles/www/tasks/service.yml
--- - name: "***www*** : Sicherstellen dass der Daemon '{{ daemon_name }}' (beim Systemstart) gestartet wird und läuft" ansible.builtin.service: # https://docs.ansible.com/ansible/latest/modules/service_module.html name: httpd state: started enabled: yes - name: "***www*** : Paketfilter anpassen und Port 80 (HTTP) öffnen" ansible.builtin.firewalld: # https://docs.ansible.com/ansible/latest/modules/firewalld_module.html service: http permanent: yes state: enabled
Wir haben also ein modular aufgebautes Installationsplaybook für unseren Webserver, mit den drei Rollen base, chrony und www und jeweils abgetrennte lokale individuelle Konfigurationsparameter, sowie das Playbook web.yml
und der übergeordneten Site-Konfiguration site.yml
.
/home/ansible/ansible/ ├── filter_plugins ├── inventories │ ├── production │ │ ├── group_vars │ │ ├── hosts.yml │ │ └── host_vars │ └── staging │ ├── group_vars │ ├── hosts.yml │ └── host_vars ├── library ├── module_utils ├── roles │ ├── base │ │ ├── defaults │ │ │ └── main.yml │ │ ├── files │ │ │ └── main.yml │ │ ├── handlers │ │ │ └── main.yml │ │ ├── library │ │ ├── lookup_plugin │ │ ├── meta │ │ │ └── main.yml │ │ ├── module_utils │ │ ├── tasks │ │ │ └── main.yml │ │ ├── templates │ │ │ └── main.yml │ │ └── vars │ │ └── main.yml │ ├── chrony │ │ ├── defaults │ │ │ └── main.yml │ │ ├── files │ │ │ └── main.yml │ │ ├── handlers │ │ │ └── main.yml │ │ ├── library │ │ ├── lookup_plugin │ │ ├── meta │ │ │ └── main.yml │ │ ├── module_utils │ │ ├── tasks │ │ │ ├── config-backup.yml │ │ │ ├── configure.yml │ │ │ ├── install.yml │ │ │ ├── main.yml │ │ │ └── service.yml │ │ ├── templates │ │ │ ├── chrony-client.conf.j2 │ │ │ └── main.yml │ │ └── vars │ │ └── main.yml │ ├── common │ │ ├── defaults │ │ │ └── main.yml │ │ ├── files │ │ │ └── main.yml │ │ ├── handlers │ │ │ └── main.yml │ │ ├── library │ │ ├── lookup_plugin │ │ ├── meta │ │ │ └── main.yml │ │ ├── module_utils │ │ ├── tasks │ │ │ └── main.yml │ │ ├── templates │ │ │ └── main.yml │ │ └── vars │ │ └── main.yml │ └── www │ ├── defaults │ │ └── main.yml │ ├── files │ │ └── main.yml │ ├── handlers │ │ └── main.yml │ ├── library │ ├── lookup_plugin │ ├── meta │ │ └── main.yml │ ├── module_utils │ ├── tasks │ │ ├── config-backup.yml │ │ ├── configure.yml │ │ ├── content.yml │ │ ├── install.yml │ │ ├── main.yml │ │ └── service.yml │ ├── templates │ │ ├── homepage.conf.j2 │ │ ├── httpd-server.conf.j2 │ │ └── main.yml │ └── vars │ └── main.yml ├── site.yml └── web.yml
Script ausführen
Zum Schluss rufen wir unser erstes role-based Playbook auf uns installieren und konfigurieren unseren Webserver.
$ ansible-playbook site.yml
BECOME password: PLAY [demo] ***************************************************************************************************************************************************** TASK [Gathering Facts] ****************************************************************************************************************************************** ok: [demo]
TASK [***base*** : Gruppe für (WEB-Entwickler) 'ruben' erstellen] *********************************************************************************************** changed: [demo]
TASK [***base*** : WEB-Admin Nutzerkonto für den User 'ruben' mit frn zugehörigen UID '1010' anlegen un der Gruppe 'ruben' zuordnen.] *************************** changed: [demo]
TASK [***base*** : Initiales Passwort für den WEB-Admin 'ruben' hinterlegen] ************************************************************************************ changed: [demo]
TASK [***chrony*** : Installation des Deamon 'chrony' (in der aktuellsten Version)] ***************************************************************************** ok: [demo]
TASK [***chrony*** : 1) Überprüfen ob das Backup der Konfigurationsdatei '/etc/chrony.conf' bereits existiert] ************************************************** ok: [demo]
TASK [***chrony*** : 2) Von der bestehenden originalen Konfigurationsdatei '/etc/chrony.conf' ein Backup '/etc/chrony.conf'.orig erstellen] ********************* changed: [demo]
TASK [***chrony*** : Template Konfigurationsdatei an Ort und Stelle kopieren und Variablen setzen] ************************************************************** changed: [demo]
TASK [***chrony*** : Sicherstellen dass der Daemon 'chrony' (beim Systemstart) gestartet wird und läuft] ******************************************************* ok: [demo]
TASK [***www*** : Installation des Deamon 'httpd' (in der aktuellsten Version)] ********************************************************************************* changed: [demo]
TASK [***www*** : 1) Überprüfen ob das Backup der Konfigurationsdatei '/etc/httpd/conf/httpd.conf' bereits existiert] ******************************************* ok: [demo]
TASK [***www*** : 2) Von der bestehenden originalen Konfigurationsdatei '/etc/httpd/conf/httpd.conf' ein Backup '/etc/httpd/conf/httpd.conf.orig' erstellen] **** changed: [demo]
TASK [***www*** : Template Konfigurationsdatei an Ort und Stelle kopieren und Variablen setzen] ***************************************************************** changed: [demo]
TASK [***www*** : default-Homepage an Ort und Stelle kopieren] ************************************************************************************************** changed: [demo]
TASK [***www*** : Sicherstellen dass der Daemon 'httpd' (beim Systemstart) gestartet wird und läuft] *********************************************************** changed: [demo]
TASK [***www*** : Paketfilter anpassen und Port 80 (HTTP) öffnen] *********************************************************************************************** changed: [demo]
PLAY RECAP ****************************************************************************************************************************************************** demo : ok=16 changed=11 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Rollen (Beispiele)
Fazit und Ausblick
Abschließend kann man sich nun berechtigter Weise die Frage stellen, warum man nun mehrere Dateien erstellt haben,um den Code und die Variablen dazu, der die Pakete installiert und die Dienste verwaltet, separat zu speichern? Wir sind so sehr leicht in der Lage zum, Beispiel Dienste in mehreren Phasen bereitstellen. In einer ersten Phase können wir so Anwendungen lediglich installieren und konfigurieren und erst in der zweiten Phase dann die Dienste dann starten. Natürlich haben es wir so auch leichter Teile des Codes wieder zu verwenden, als wenn man eine große Datei verwenden würde in der alle Einzelschritte selektiv aufgeführt sind!