Dopo aver preso confidenza con l’ambiente Ansible, cominciamo ad usarlo per automatizzare i compiti di ogni giorno.
A titolo didattico scriveremo un playbook per installare un ambiente apache+php su un nuovo server e per provare il funzionamento faremo il deploy di una semplice pagina web.
Attiviamo quindi la macchina virtuale di cui avevamo fatto il provisioning nello scorso articolo:
$ vagrant up |
e apriamo un editor per iniziare a scrivere il nostro playbook :
--- - name: installa apache+php e una pagina di esempio remote_user: root sudo: yes hosts: web tasks: - name: installazione Apache yum: name=httpd state=present - name: installazione PHP yum: name=php state=present - name: avvio servizio http service: name=httpd state=running enabled=yes - name: deploy script PHP copy: src=index.php dest=/var/www/html/index.php mode=0664
possiamo notare nel playbook una lista di task, uno per ogni “step” del nostro compito: è come dire a qualcuno di eseguire queste azioni passo-passo.
prima di lanciare il playbook, prepariamo il file da copiare…
$ echo "<?php phpinfo(); ?>" > index.php |
se usiamo virtualbox come hypervisor, dobbiamo aggiungere una riga al file di configurazione di Vagrant perché attivi il forwarding della porta 80 della guest sulla porta 8000 del nostro pc
(vedi https://docs.vagrantup.com/v2/networking/forwarded_ports.html)
config.vm.network "forwarded_port", guest: 80, host: 8000 |
e dare il comando per ricaricare la virtual machine con la nuova configurazione:
vagrant reload |
Ora possiamo lanciare il playbook
$ ansible-playbook apache_php.yml PLAY [installa apache+php e una pagina di esempio] **************************** GATHERING FACTS *************************************************************** ok: [127.0.0.1] TASK: [installazione Apache] ************************************************** changed: [127.0.0.1] TASK: [installazione PHP] ***************************************************** changed: [127.0.0.1] TASK: [avvio servizio http] *************************************************** changed: [127.0.0.1] TASK: [deploy script PHP] ****************************************************** changed: [127.0.0.1] PLAY RECAP ******************************************************************** 127.0.0.1 : ok=5 changed=4 unreachable=0 failed=0 |
ansible ci dice che è andato tutto bene… Possiamo controllare l’esito aprendo il browser su http://localhost:8000 e… Non funziona 🙂
Sulla guest Centos è attivo iptables, che blocca la comunicazione verso la porta 80. Potremmo semplicemente fermare il servizio firewall, ma ne approfitteremo per scrivere un nuovo playbook generico, che configuri iptables secondo le nostre esigenze. In prima istanza potremmo pensare che basterebbe aggiungere al playbook un task come questo
- name: Apache | add apache iptable rule command: /sbin/iptables -I INPUT 1 -p tcp --dport http -j ACCEPT -m comment --comment "Apache" sudo: true |
però sarebbe un errore, perché violerebbe il principio di idempotenza: eseguendo più volte lo stesso task, continueremo ad accodare la stessa regola, cosa da evitare.
Per risolvere ci sono varie alternative, tra cui la seguente:
- hosts: all tasks: - name: Open the correct IPTables ports lineinfile: dest=/etc/sysconfig/iptables regexp="^-A INPUT -m state --state NEW -m {{item.protocol}} -p {{item.protocol}} --dport {{item.port}} -j ACCEPT$" line="-A INPUT -m state --state NEW -m {{item.protocol}} -p {{item.protocol}} --dport {{item.port}} -j ACCEPT" insertafter="^:OUTPUT ACCEPT \[\d*:\d*\]$" with_items: - { protocol: tcp, port: 80 } - { protocol: tcp, port: 22 } notify: - restart iptables handlers: - name: restart iptables action: service name=iptables state=restarted |
come funziona ? usiamo il modulo lineinfile per identificare tutte le linee di
/etc/sysconfig/iptables
che soddisfino la regexp, e la sostituiamo con un valore parametrico, il cui contenuto cioè è specificato tramite variabili.
Ne approfittiamo per introdurre il concetto di handlers, che a livello di sintassi sono normali task ma hanno la caratteristica di venire invocati quando in un task è presenta la direttiva “notify” e quando il task notifica che è stato cambiato qualcosa. L’esempio tipico è la necessità di riavviare un servizio solo quando il file di configurazione è stato effettivamente modificato.
Salviamo il playbook come iptables.yml e lo includiamo nel nostro script iniziale:
--- - name: installa apache+php e una pagina di esempio remote_user: root sudo: yes hosts: web tasks: - name: installazione Apache yum: name=httpd state=present - name: installazione PHP yum: name=php state=present - name: avvio servizio http service: name=httpd state=running enabled=yes - name: deploy script PHP copy: src=index.php dest=/var/www/index.php mode=0664 - include: iptables.yml |
e dopo averlo lanciato godiamoci il risultato, il nostro server è pronto per ospitare pagine php:
Al di là dell’attività tutto sommato semplice, abbiamo ottenuto due cose molto importanti:
- una “descrizione” di come è configurato il server
- un setup riproducibile a piacimento in maniera pressochè automatica partendo da un server appena installato
Questa è solo una introduzione al mondo di Ansible, e prima di concludere invito i lettori a visitare qualche sito per approfondirne la conoscenza.
Anzitutto Ansible non è solo linea di comando ma presso il sito ufficiale è disponibile una web dashboard che permette di controllare i job, avere report, statistiche e così via:
Ansible Galaxy è invece un repository comunitario di “ricette”, playbooks, task moduli e tutto quello che si può immaginare … Se dovete installare e configurare software come Tomcat, Oracle, mongodb, jenkins, nginx, Drupal, rabbitmq e tanti altri trovate già tutto pronto, di sicuro una base di partenza molto comoda per le vostre personalizzazioni!
Se ciò non bastasse, Ansible ha una API estremamente chiara e flessibile per scrivere moduli custom in Python o qualsiasi altro linguaggio, un esempio concreto qui: http://www.rohit.io/blog/contributing-to-ansible-is-super-easy.html
Ultimo link ma più importante di tutti, l’ottima documentazione, reperibile su http://docs.ansible.com/
Buona automazione!