Ansible: Automatització Simple i Potent
3. Ansible: Automatització Simple i Potent
Filosofia i Visió
Ansible va néixer amb una missió clara: fer l'automatització accessible a tothom. El seu creador, Michael DeHaan, volia una eina tan simple que qualsevol administrador de sistemes pogués començar a utilitzar-la en minuts, sense haver d'aprendre un llenguatge de programació complet ni instal·lar infraestructura complexa.
La filosofia d'Ansible es pot resumir en tres principis: simplicitat radical, arquitectura agentless, i potència sense complexitat. Aquests principis es reflecteixen en cada aspecte del disseny de l'eina.
Arquitectura d'Ansible
Ansible utilitza una arquitectura push agentless. Això significa que tens un "control node" (pot ser el teu portàtil, un servidor dedicat, o qualsevol màquina Linux amb Python instal·lat) des del qual "empentes" les configuracions cap als servidors gestionats. No hi ha cap servidor central que els nodes hagin de consultar, ni cap agent executant-se contínuament.
La comunicació es fa via SSH per a servidors Linux/Unix, o WinRM per a Windows. Això vol dir que si ja tens accés SSH als teus servidors, ja tens tot el que necessites per començar amb Ansible. No cal obrir ports addicionals al firewall, no cal instal·lar cap software especial en els servidors gestionats (més enllà de Python, que ja ve instal·lat per defecte en la majoria de distribucions Linux modernes).
Quan executes un playbook d'Ansible (ho explicarem més endavant), el control node connecta via SSH a cada servidor, copia els mòduls d'Ansible necessaris, els executa, recull els resultats, i neteja els fitxers temporals. Tot això passa de manera transparent per l'usuari.
Nota de versió: A l'hora d'escriure aquest document (gener 2025), la versió estable d'Ansible és la 2.16.x dins del paquet ansible-core, i la versió 9.x del paquet ansible complet que inclou col·leccions. Es recomana utilitzar ansible-core 2.16 com a mínim. Podeu verificar la darrera versió a la documentació oficial: https://docs.ansible.com/
Components Clau d'Ansible
Per entendre com funciona Ansible, hem de conèixer els seus components principals.
Inventari: L'inventari és on definim quins servidors volem gestionar i com agrupar-los. Pot ser tan simple com un fitxer de text amb IPs o noms de host, o tan complex com un script que genera la llista dinàmicament consultant l'API d'AWS, Azure o altres proveïdors cloud.
Un inventari bàsic podria ser així:
[webservers]
web1.example.com
web2.example.com
web3.example.com
[databases]
db1.example.com
db2.example.com
[production:children]
webservers
databases
Aquest inventari defineix dos grups: webservers i databases. També crea un grup "production" que conté tots els altres grups. Això ens permet executar tasques contra grups específics de servidors.
Playbooks: Els playbooks són fitxers YAML que descriuen l'estat desitjat dels teus sistemes. Són l'equivalent a "receptes" o "runbooks" en altres eines. El nom "playbook" ve del món esportiu: igual que un entrenador de futbol americà té un playbook amb jugades planificades, tu tens un playbook amb configuracions planificades.
Un playbook simple per instal·lar nginx podria ser:
---
- name: Configurar servidors web
hosts: webservers
become: yes
tasks:
- name: Instal·lar nginx
apt:
name: nginx
state: present
update_cache: yes
- name: Assegurar que nginx està executant-se
service:
name: nginx
state: started
enabled: yes
Aquest playbook és auto-explicatiu, que és una de les grans fortaleses d'Ansible. Fins i tot sense conèixer la sintaxi, és fàcil entendre què fa: instal·la nginx i s'assegura que està executant-se.
Mòduls: Els mòduls són les unitats de treball d'Ansible. Cada tasca en un playbook utilitza un mòdul. Hi ha mòduls per a pràcticament tot el que puguis imaginar: gestionar paquets (apt, yum, dnf), gestionar fitxers (copy, template, file), gestionar serveis (service, systemd), gestionar usuaris (user, group), interactuar amb clouds (ec2, azure_rm, gcp_compute), gestionar bases de dades (mysql_db, postgresql_db), i moltíssims més.
Ansible ve amb centenars de mòduls integrats, i la comunitat n'ha creat milers més disponibles en col·leccions. Fins i tot pots escriure els teus propis mòduls en Python si necessites funcionalitat específica.
Roles: A mesura que els teus playbooks creixen, és útil organitzar-los en roles. Un rol és una manera d'agrupar tasques relacionades, variables, fitxers i templates en una estructura de directoris estandarditzada. Per exemple, podries tenir un rol "nginx" que conté tot el necessari per configurar nginx, i després reutilitzar aquest rol en diferents playbooks.
Variables: Ansible té un sistema de variables potent que permet parametritzar les teves configuracions. Pots definir variables a nivell d'inventari, de grup, de host, de playbook, o de rol. Pots també utilitzar facts (dades sobre els sistemes recopilades automàticament per Ansible) i registrar l'output de tasques com a variables per utilitzar-les més tard.
Templates: Els templates utilitzen el motor de plantilles Jinja2 per generar fitxers de configuració dinàmicament. Això és extremadament útil quan necessites crear fitxers de configuració que varien segons el servidor o l'entorn. Per exemple, pots tenir un template per a la configuració d'nginx que s'adapti automàticament segons la quantitat de memòria RAM del servidor.
Flux de Treball Típic amb Ansible
Vegem com seria un flux de treball típic utilitzant Ansible en un escenari real.
Imagina que has d'afegir un nou servidor web a la teva infraestructura. Primer, afegiries el nou servidor a l'inventari en el grup "webservers". Després, executaries el playbook de configuració de webservers que ja tens preparat. Ansible es connectaria al nou servidor, instal·laria tots els paquets necessaris, copiaria els fitxers de configuració, configuraría el firewall, afegiria el servidor al load balancer, i finalment verificaria que tot funciona correctament. Tot això amb una sola comanda: ansible-playbook webserver.yml.
La clau aquí és que el mateix playbook que utilitzes per configurar un nou servidor també pots utilitzar-lo per actualitzar servidors existents. Si canvies la configuració d'nginx en el teu playbook i el tornes a executar, Ansible detectarà que la configuració dels servidors existents és diferent de l'estat desitjat, i actualitzarà només els fitxers que han canviat, reiniciant el servei si és necessari.
Exemples Pràctics d'Ansible
Vegem alguns exemples pràctics per entendre millor com funciona Ansible en situacions reals.
Exemple 1: Configuració d'un servidor web complet
Imagineu que voleu configurar un servidor web amb nginx, PHP-FPM, i una aplicació web. El playbook seria així:
---
- name: Configuració completa d'un servidor web
hosts: webservers
become: yes
vars:
php_version: "8.2"
app_name: "myapp"
app_domain: "example.com"
tasks:
- name: Actualitzar cache de paquets
apt:
update_cache: yes
cache_valid_time: 3600
- name: Instal·lar paquets necessaris
apt:
name:
- nginx
- "php{{ php_version }}-fpm"
- "php{{ php_version }}-mysql"
- "php{{ php_version }}-curl"
- "php{{ php_version }}-xml"
- git
- ufw
state: present
- name: Configurar firewall
ufw:
rule: allow
port: "{{ item }}"
proto: tcp
loop:
- '22'
- '80'
- '443'
- name: Activar firewall
ufw:
state: enabled
- name: Crear directori de l'aplicació
file:
path: "/var/www/{{ app_name }}"
state: directory
owner: www-data
group: www-data
mode: '0755'
- name: Clonar repositori de l'aplicació
git:
repo: "https://github.com/company/{{ app_name }}.git"
dest: "/var/www/{{ app_name }}"
version: main
force: yes
notify: Reload nginx
- name: Crear configuració d'nginx des de template
template:
src: nginx-site.conf.j2
dest: "/etc/nginx/sites-available/{{ app_name }}"
owner: root
group: root
mode: '0644'
notify: Reload nginx
- name: Activar site d'nginx
file:
src: "/etc/nginx/sites-available/{{ app_name }}"
dest: "/etc/nginx/sites-enabled/{{ app_name }}"
state: link
notify: Reload nginx
- name: Desactivar site per defecte
file:
path: /etc/nginx/sites-enabled/default
state: absent
notify: Reload nginx
- name: Assegurar que nginx està executant-se
service:
name: nginx
state: started
enabled: yes
- name: Assegurar que PHP-FPM està executant-se
service:
name: "php{{ php_version }}-fpm"
state: started
enabled: yes
handlers:
- name: Reload nginx
service:
name: nginx
state: reloaded
Aquest playbook fa moltes coses, però cada pas és clar i comprensible. Primer actualitza la cache de paquets, després instal·la nginx, PHP i altres dependencies. Configura el firewall per permetre tràfic web i SSH. Crea el directori per l'aplicació i clona el codi des de Git. Genera la configuració d'nginx utilitzant un template. Finalment, s'assegura que tots els serveis estan executant-se.
Notem l'ús de "handlers": són tasques especials que només s'executen si alguna altra tasca ha fet canvis. En aquest cas, només recarreguem nginx si hem canviat la seva configuració o el codi de l'aplicació. Això evita reinicis innecessaris.
El template d'nginx (nginx-site.conf.j2) podria ser així:
server {
listen 80;
server_name {{ app_domain }};
root /var/www/{{ app_name }}/public;
index index.php index.html;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php{{ php_version }}-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
location ~ /\.ht {
deny all;
}
}
Aquest template utilitza les variables que hem definit en el playbook (app_domain, app_name, php_version) per generar una configuració personalitzada per cada servidor.
Exemple 2: Gestió d'usuaris i permisos
Un altre cas d'ús comú és la gestió d'usuaris i claus SSH:
---
- name: Gestió d'usuaris del sistema
hosts: all
become: yes
vars:
admin_users:
- name: joan
ssh_key: "ssh-rsa AAAAB3NzaC1yc2EAAAA... joan@company.com"
sudo: yes
- name: maria
ssh_key: "ssh-rsa AAAAB3NzaC1yc2EAAAA... maria@company.com"
sudo: yes
- name: pere
ssh_key: "ssh-rsa AAAAB3NzaC1yc2EAAAA... pere@company.com"
sudo: no
tasks:
- name: Crear usuaris administradors
user:
name: "{{ item.name }}"
state: present
shell: /bin/bash
groups: "{{ 'sudo' if item.sudo else '' }}"
append: yes
loop: "{{ admin_users }}"
- name: Afegir claus SSH públiques
authorized_key:
user: "{{ item.name }}"
key: "{{ item.ssh_key }}"
state: present
loop: "{{ admin_users }}"
- name: Configurar sudoers per usuaris admin
lineinfile:
path: /etc/sudoers.d/admin_users
line: "{{ item.name }} ALL=(ALL) NOPASSWD:ALL"
create: yes
mode: '0440'
validate: 'visudo -cf %s'
loop: "{{ admin_users }}"
when: item.sudo
- name: Deshabilitar autenticació amb password per SSH
lineinfile:
path: /etc/ssh/sshd_config
regexp: '^PasswordAuthentication'
line: 'PasswordAuthentication no'
state: present
notify: Restart sshd
- name: Assegurar que només root pot accedir a /root
file:
path: /root
mode: '0700'
handlers:
- name: Restart sshd
service:
name: sshd
state: restarted
Aquest playbook crea usuaris, configura les seves claus SSH, estableix permisos sudo, i endureix la configuració de SSH. Tota la informació dels usuaris està definida en una variable, fent fàcil afegir o eliminar usuaris simplement editant la llista.
Avantatges d'Ansible
Després d'aquests exemples, podem veure clarament els avantatges d'Ansible. La seva simplicitat fa que sigui accessible per a principiants: la sintaxi YAML és llegible i intuïtiva, no cal aprendre un llenguatge de programació complet per començar. La seva arquitectura agentless significa que pots començar a utilitzar-lo immediatament sense instal·lar agents en els teus servidors. És idempotent, així que pots executar el mateix playbook múltiples vegades sense por de trencar res. Té una comunitat enorme amb milers de roles i mòduls disponibles. I finalment, escala bé des d'uns pocs servidors fins a milers, especialment quan s'utilitza amb Ansible Tower o AWX per gestió centralitzada.
Referència oficial: La documentació completa d'Ansible està disponible a https://docs.ansible.com/. Per començar, es recomana el "Getting Started Guide": https://docs.ansible.com/ansible/latest/getting_started/index.html