Skip to main content

WORKSHOP 7: Roles

Tot nu toe creëerden we playbooks met meerdere taken erin. Maar we willen graag deeltaken die we in de playbooks gebruikten liefst hergebruiken in meerdere situaties. Hiervoor kunnen Ansible roles gebruikt worden.

Doelstelling

In deze workshop leer je:

  • de folder-structuur opbouwen van een Ansible Role.
  • hoe een Ansible Role op te bouwen.
  • een Ansible Play te maken om een Role te gebruiken.

Workshop

Bij een Ansible role gaan we onze playbook terug uiteen rafelen in kleinere, herbruikbare stukken en in een aparte mappen-structuur plaatsen. Dit is meer in detail besproken in de online documentatie.

Stap 1 - De Ansible Role-structuur

Roles volgen een heel bepaalde structuur. De naam van de rol wordt bepaald door de "bovenste" map (top-level directory). Veel van de onderliggende mappen bevatten YAML-files met de naam main.yml. De bestands- en templates-folders bevatten elementen waarnaar in die YAML-files gerefereerd wordt.

Een voorbeeld-structuur van een role met de naam apache ziet er als volgt uit:

roles/  
apache/
├── defaults/
│ └── main.yml
├── files/
├── handlers/
│ └── main.yml
├── meta/
│ └── main.yml
├── README.md
├── tasks/
│ └── main.yml
├── templates/
├── tests/
│ ├── inventory
│ └── test.yml
└── vars/
└── main.yml

De verschillende main.yml bestanden bevatten inhoud i.f.v. hun locatie in de mappenstructuur. De vars/main.yml bevat referenties naar variabelen, de handlers/main.yml beschrijft de handlers, enzovoort.

info

In tegenstelling tot playbooks bevatten de main.yml-bestanden enkel de specifieke inhoud en niet de klassieke playbook-informatie zoals hosts, become,...

tip

Er zijn eigenlijk 2 mappen voorzien voor variabelen: vars en default. "default"-variabelen hebben de laagste prioriteit en bevatten meestal enkel variabelen vastgelegd door de role-auteurs en zullen meestal overschreven worden door specifiekere waarden, meestal in vars/main.yml (meer info in de documentatie).

Ansible gaat dus standaard zoeken in elke map binnen de role naar bestanden met de naam main.yml.

Gebruik van meerdere rollen samen met hun playbooks organiseer je als volgt: (Ansible verwacht een map roles onderliggend aan de playbook(s) waarin de rollen opgenomen werden)

site.yml                  # main playbook
webservers.yml # playbook for webserver tier
fooservers.yml # playbook for fooserver tier
roles/
common/ # this hierarchy represents a "role"
tasks/
handlers/
files/
templates/
vars/
defaults/
meta/
webservers/
tasks/
handlers/
files/
...

Roles gebruiken is vrij eenvoudig aan te geven in een playbook:

webservers.yml
---
- name: launch roles
hosts: web
roles:
- common
- webservers

Voor elke rol hierboven onder roles zullen de tasks, de handlers en de vars van die rol opgenomen worden. Elk script, elke template, elke... in de rol kan refereren naar relevante bestanden, templates of taken zonder absolute of relatieve paden! Ansible zal die bestanden automatisch zoeken in de mappen files,templates of tasks van de respectievelijke rol.

Stap 2 - role mappen-structuur aanmaken

Zoals eerder gezegd zal Ansible zoeken naar roles in de submappen van de map roles van je projectmap. Elke rol heeft dus zijn eigen mappenstructuur en kunnen we makkelijk automatisch aanmaken met de tool ansible-galaxy.

tip

Ansible Galaxy website is een centrale plaats waar je verschillende Ansible inhoud kan vinden (typisch "roles" en "collections") om veel gebruikte taken uit te voeren.

  • We bouwen nu eerst een rol die Apache zal installeren en configureren om virtuele sites te hosten.\

  • Voer volgende opdrachten uit in je projectfolder ./ansible-files:

    [student@ControlHost ansible-files]$ mkdir roles
    [student@ControlHost ansible-files]$ ansible-galaxy init roles/apache_vhost
  • Bekijk de folder-structuur die Ansible-galaxy aangemaakt heeft:

    [student@ControlHost ansible-files]$ tree roles
    roles
    └── apache_vhost
    ├── defaults
    │ └── main.yml
    ├── files
    ├── handlers
    │ └── main.yml
    ├── meta
    │ └── main.yml
    ├── README.md
    ├── tasks
    │ └── main.yml
    ├── templates
    ├── tests
    │ ├── inventory
    │ └── test.yml
    └── vars
    └── main.yml

Stap 3 - het Tasks-bestand in Roles

Het bestand main.yml in de folder tasks van deze rol moet het volgende uitvoeren:

  • er voor zorgen dat Apache geïnstalleerd is
  • er voor zorgen dat Apache gestart is en dat permanent (na reboots)
  • HTML-inhoud voorzien in de Apache root-folder
  • de voorziene template installeren om een virtuele host (vhost) te configureren.
caution

Zoals eerder al aangegeven kan de main.yml enkel tasks bevatten en géén klassieke playbook-informatie.

  • Pas de inhoud van roles/apache_vhost/tasks/main.yml aan:

    main.yml
    ---
    # tasks file for roles/apache_vhost
    - name: Install Apache2
    ansible.builtin.apt:
    name: apache2
    state: latest

    - name: Start and enable Apache2 service
    ansible.builtin.service:
    name: apache2
    state: started
    enabled: true

    Bovenstaande zorgt nu al voor een correct werkende Apache-installatie!

  • Voeg nog 2 extra taken toe die de vhost mappen-structuur voorzien en html-pagina's kopieert.

    main.yml
    - name: Ensure vhost directory is present
    ansible.builtin.file:
    path: "/var/www/vhosts/{{ ansible_hostname }}"
    state: directory
    mode: "655"

    - name: Deliver html content
    ansible.builtin.copy:
    src: web.html
    dest: "/var/www/vhosts/{{ ansible_hostname }}/index.html"
    mode: "644"

    Bovenstaande gebruikt de module file om de mappen-structuur eventueel aan te maken (zie documentatie). Het bestand web.html wordt gekopieerd van de control host naar de juiste locatie op de doelhost.
    Het bestand web.html wordt verder in deze workshop nog aangemaakt.

  • een volgende taak die we nog toevoegen aan deze YAML-file gebruikt de template module om de vhost-configuratie van de webserver aan te maken en te kopiëren.

    main.yml
    - name: Template vhost file
    ansible.builtin.template:
    src: vhost.conf.j2
    dest: "/etc/apache2/sites-available/{{ ansible_hostname }}.conf"
    owner: root
    group: root
    mode: "644"

    Ook hier moet de template zelf (vhost.conf.j2) nog aangemaakt worden. Dit doen we wat verder in deze workshop. De module kopieert de template over het default bestand 000-default.conf om de vhosts te definiëren.

  • Na het toevoegen van een virtuele host aan Apache moet deze "enabled" worden. Dit gebeurt met de apache-tool a2ensite. Zoals je hieronder ziet gebruikt deze deeltaak een handler met de naam Restart_apache2. De handler wordt ook later aangemaakt.

  • De volledige task binnen deze rol (tasks/main.yml) ziet er nu als volgt uit:

    ---
    # tasks file for roles/apache_vhost
    - name: Install Apache2
    ansible.builtin.apt:
    name: apache2
    state: latest

    - name: Start and enable Apache2 service
    ansible.builtin.service:
    name: apache2
    state: started
    enabled: true

    - name: Ensure vhost directory is present
    ansible.builtin.file:
    path: "/var/www/vhosts/{{ ansible_hostname }}"
    state: directory
    mode: "655"

    - name: Deliver html content
    ansible.builtin.copy:
    src: web.html
    dest: "/var/www/vhosts/{{ ansible_hostname }}/index.html"
    mode: "644"

    - name: Template vhost file
    ansible.builtin.template:
    src: vhost.conf.j2
    dest: "/etc/apache2/sites-available/{{ ansible_hostname }}.conf"
    owner: root
    group: root
    mode: "644"

    - name: Enable new site
    ansible.builtin.shell:
    cmd: /usr/sbin/a2ensite {{ ansible_hostname }}
    notify:
    - Restart_apache2

Stap 4 - De handler voorzien

In het bestand roles/apache_vhost/handlers/main.yml maken we de handler aan die Apache zal herstarten als die aangeroepen wordt door een notify in de "template"-taak.

roles/apache_vhost/handlers/main.yml
---
# handlers file for roles/apache_vhost
- name: Restart_apache2
ansible.builtin.service:
name: apache2
state: restarted

Stap 5 - Voorzie een web.html bestand en vhost.conf.j2 template

  • Maak een bestand web.html aan met de HTML-content voor de webserver in de map files van de rol:

    <html>
    <head>
    <title>Welcome to Apache virtual host!</title>
    </head>
    <body>
    <h1>Success! The virtual host is working!</h1>
    </body>
    </html>
  • Maak een template aan met de naam vhost.conf.j2 in de map templates van de rol:

    # {{ ansible_managed }}

    <VirtualHost *:80>
    ServerAdmin webmaster@{{ ansible_hostname }}
    ServerName {{ ansible_hostname }}
    ErrorLog ${APACHE_LOG_DIR}/{{ ansible_hostname }}-error.log
    CustomLog ${APACHE_LOG_DIR}/{{ ansible_hostname }}-common.log common
    DocumentRoot /var/www/vhosts/{{ ansible_hostname }}/

    <Directory /var/www/vhosts/{{ ansible_hostname }}/>
    Options +Indexes +FollowSymlinks +Includes
    Order allow,deny
    Allow from all
    </Directory>
    </VirtualHost>

Stap 6 - Test de role

We gaan deze role toepassen op node2. Maar aangezien we een rol niet rechtstreeks kunnen toewijzen aan een node moeten we eerst een playbook voorzien waarin we de hosts en de roles samenbrengen.

  • Maak een playbook aan met de naam test_apache_role.yml in je projectmap:

    test_apache_role.yml
    ---
    - name: Use apache_vhost role playbook
    hosts: node2
    become: true

    pre_tasks:
    - name: Pre tasks
    ansible.builtin.debug:
    msg: 'Beginning web server configuration.'

    roles:
    - apache_vhost

    post_tasks:
    - name: Post tasks
    ansible.builtin.debug:
    msg: 'Web server has been configured.'

    In bovenstaande zie je 2 nieuwe keywordspre_tasks en post_tasks. Normaal gesproken worden de taken van rollen uitgevoerd vóór de taken van een playbook. Om de volgorde van uitvoering te controleren, worden pre_tasks uitgevoerd voordat rollen worden toegepast. post_tasks worden uitgevoerd nadat alle rollen zijn voltooid. Hier gebruiken we ze gewoon om beter te markeren wanneer de daadwerkelijke rol wordt uitgevoerd.

  • playbook uitvoeren:

    [student@ControlHost ansible-files]$ ansible-playbook test_apache_role.yml
  • Controleer of je op node2 de nieuwe virtuele site kan bekijken:

    [student@ControlHost ansible-files]$ ansible node2 -m setup | grep ansible_hostname
    "ansible_hostname": "iac-Managed-Host-2",
    [student@ControlHost ansible-files]$ ansible node2 -m command -a "curl -s http://iac-Managed-Host-2"

    node2 | CHANGED | rc=0 >>
    <html>
    <head>
    <title>Welcome to Apache virtual host!</title>
    </head>
    <body>
    <h1>Success! The virtual host is working!</h1>
    </body>
    </html>

    [student@ControlHost ansible-files]$
  • Controleer het verschil met de default site van je webserver:

      [student@ControlHost ansible-files]$ ansible node2 -m command -a "curl -s http://localhost"

    Aangezien je nu met virtuele sites (vhosts) werkt zou Apache nu bij bovenstaand commando een andere, eerder geconfigureerde, site moeten tonen.

© Deze workshop werd gebaseerd op de informatie van Red Hat Ansible Automation Platform