Ansible roles

Zoals gezegd, bij complexere omgevingen is het verstandig om een structuur aan te brengen op de Ansible master. In feite kan dit vanuit elke directory zijn en we maken een structuur in de /apps/ansible/ directory. Deze ziet er alsvolgt uit:

.
├── group_vars
└── roles
    ├── common
    │   ├── handlers
    │   ├── tasks
    │   └── templates
    └── musicplayers
        ├── handlers
        ├── tasks
        └── templates

In de hoofd-directory (/apps/ansible/) maken we een bestand genaamd ‘musicplayers‘ waarin we de host-specificaties zetten. Dit bestand vervangt dan het algemene /etc/ansible/hosts bestand. De inhoud is hetzelfde, namelijk een alias, het IP adres van de node en de gebruiker op de nodes waarmee we de instructies geven. Deze gebruiker heeft dan onze publieke sleutel in de authorized_keys staan.

[musicplayers]
huiskamer  ansible_host=192.168.1.31 ansible_user=ansible
demoruimte ansible_host=192.168.1.21 ansible_user=ansible
badkamer   ansible_host=192.168.1.41 ansible_user=ansible
#tuin       ansible_host=192.168.1.51 ansible_user=ansible

In deze directory staat ook het playbook, genaamd musicplayers.yml met de volgende inhoud:

---
# This playbook deploys the whole application stack in this site.

- name: apply common configuration to all nodes
  hosts: all
  roles:
     - common

- name: configure and deploy the musicplayer nodes
  hosts: musicplayers
  roles:
      - musicplayers

Wat we hiermee aangeven is dat op alle nodes (all) de roles uit de ‘common‘ directory uitgevoerd moeten gaan worden en op de nodes van de groep ‘musicplayers‘ willen we de roles uit de directory ‘musicplayers‘ uit voeren.

Roles

Nu volgt een directory genaamd ‘roles‘ waarin subdirectories staan. Deze kun je vergelijken met de ‘manifests’ in puppet. We hebben ‘common‘ voor alle nodes en ‘musicplayers‘ voor onze muziek-streamers.

Tasks

Per role staat onder andere de ‘tasks‘ directory. In roles/common/tasks/ vinden we main.yml met de volgende inhoud:

---
# this is the common playbook for all nodes

- name: Install ntp
  yum: name=ntp state=present
  tags: ntp

- name: Configure ntp file
  template: src=ntp.conf.j2 dest=/etc/ntp.conf
  tags: ntp
  notify: restart ntp

- name: Start the ntp service
  service: name=ntpd state=started enabled=yes
  tags: ntp

Een aantal zaken vallen hier op, te beginnen met de tags: aanduiding. Hiermee kunnen we de 3 losse taken tot één geheel maken. Het playbook zou dan uitgevoerd kunnen worden met de optie –tags: “ntp”. Naast de yum-instructie (of ‘apt’ op Ubuntu/Debian systemen) die feitelijk voor zichzelf spreekt zien we template: en notify:

template: gebruikt een template-bestand die terug te vinden is in de ‘templates‘ directory. De ‘dest’ geeft aan waar het uiteindelijk bestand moet komen.

notify: is een trigger-instructie die een bepaalde handler zal activeren. Deze staat dan in de ‘handlers‘ directory.

Tasks kunnen ook ge-nest worden en dat kan met ‘include_tasks’ of ‘import_tasks’. Het verschil hiertussen is dat import_tasks de tasks-list van te voren al in laadt en met include_tasks worden de taken geladen op het moment dat de include-instructie aan de beurt is. Een voorbeeld:

# Include OS specific tasks
- include_tasks: CentOS.yml
  when: ansible_distribution == "CentOS"
- include_tasks: Ubuntu.yml
  when: ansible_distribution == "Ubuntu"

Templates

De template die we gebruiken voor de ntp-service heeft de volgende inhoud:

driftfile /var/lib/ntp/drift

restrict 127.0.0.1
restrict -6 ::1

server {{ ntpserver }}

includefile /etc/ntp/crypto/pw

keys /etc/ntp/keys

Group variables

Er wordt hier gebruik gemaakt van een group-variable en deze is terug te vinden (vanuit de hoofd-directory) in de subdirectory ‘group_vars‘. Hier staat een bestand genaamd ‘all‘ met de volgende inhoud:

---
# Variables listed here are applicable to all host groups

ntpserver: 0.nl.pool.ntp.org

Hier kunnen uiteraard nog meer time-servers opgegeven worden maar het gaat even om het idee. Rest nog de handler:

Handlers

Om de service te kunnen herstarten nadat de config-file is aangepast laten we een handler dit werk doen. Deze staat dus in de handlers directory en heet ook hier ‘main.yml‘ met de volgende inhoud:

---
# Handler to handle common notifications. Handlers are called by other plays.
# See http://docs.ansible.com/playbooks_intro.html for more information about handlers.

- name: restart ntp
 service: name=ntpd state=restarted

De naam is in de notify: regel van de task gedefinieerd en komt overeen met de name:, namelijk ‘restart ntp

Samengevat ziet de roles/common-tree er dan zo uit:

.
├── handlers
│   └── main.yml
├── tasks
│   └── main.yml
└── templates
    └── ntp.conf.j2

Specifieke configuraties en services (lees: tasks) worden verder beheerd in de musicplayers-role waarbij de structuur gelijk is aan de common-role.

Bijvoorbeeld modules voor sudoers, een motd-bestand, mail-functies, crontab jobs, etc… maar dat is voor een volgende keer…

Mochten er trouwens bestanden op de nodes gekopieerd moeten worden dan kan per role nog voor dit doel een ‘files‘ directory gemaakt worden.

Ansible-playbook

Om nu dit playbook uit te voeren op de musicplayers geven we vanuit de hoofd-directory /apps/ansible/ het volgende commando:

ansible-playbook -i musicplayers musicplayers.yml

De optie ‘-i musicplayers’ zorgt ervoor dat het juiste hosts-bestand wordt aangeroepen.

Resultaat

PLAY [apply common configuration to all nodes] ******************************************************************************************************

TASK [Gathering Facts] ******************************************************************************************************************************
ok: [huiskamer]
ok: [demoruimte]
ok: [badkamer]

TASK [common : Install ntp] *************************************************************************************************************************
ok: [huiskamer]
ok: [demoruimte]
ok: [badkamer]

TASK [common : Configure ntp file] ******************************************************************************************************************
ok: [huiskamer]
ok: [demoruimte]
ok: [badkamer]

TASK [common : Start the ntp service] ***************************************************************************************************************
ok: [huiskamer]
ok: [demoruimte]
ok: [badkamer]

PLAY [configure and deploy the musicplayer nodes] ***************************************************************************************************

TASK [Gathering Facts] ******************************************************************************************************************************
ok: [huiskamer]
ok: [demoruimte]
ok: [badkamer]

PLAY RECAP ******************************************************************************************************************************************
badkamer   : ok=5 changed=0 unreachable=0 failed=0
demoruimte : ok=5 changed=0 unreachable=0 failed=0
huiskamer  : ok=5 changed=0 unreachable=0 failed=0

Hieraan is te zien dat op alle nodes de ntp-service al geïnstalleerd was, zie ‘changed=0’. Hoe dan ook, het playbook is succesvol uitgevoerd!

Indien je een nieuw project start dan is het mogelijk dat je Ansible de directory structuur laat aanmaken. Dit kan voor bijvoorbeeld het project ‘projectnaam‘ met het volgende commando:

ansible-galaxy init projectnaam

De structuur die aangemaakt wordt ziet er dan als volgt uit:

.
├── defaults
├── files
├── handlers
├── meta
├── tasks
├── templates
├── tests
└── vars