Teoria Bash 04: Ansible Bàsic

1. Introducció a Ansible

Què és Ansible?

Ansible és una eina d'automatització IT que permet:

Per què Ansible?

Avantatges:

Comparació amb scripts SSH:

# Script SSH tradicional
for servidor in web1 web2 web3; do
    ssh $servidor "apt update && apt install nginx -y"
done

# Problema: No és idempotent, no gestiona errors bé, difícil de mantenir

# Amb Ansible
ansible webservers -m apt -a "name=nginx state=present"
# ✓ Idempotent
# ✓ Gestió d'errors
# ✓ Fàcil de llegir

Conceptes bàsics

2. Instal·lació d'Ansible

En el control node (la teva màquina)

# Debian/Ubuntu
sudo apt update
sudo apt install ansible -y

# Fedora/RHEL
sudo dnf install ansible -y

# macOS
brew install ansible

# Amb pip (qualsevol sistema)
pip3 install ansible

# Verificar instal·lació
ansible --version

Important: Ansible només s'instal·la al control node. Als managed nodes només cal SSH i Python.

Configuració SSH

Ansible usa SSH, així que cal tenir claus configurades:

# Generar clau (si no en tens)
ssh-keygen -t ed25519

# Copiar a cada servidor
ssh-copy-id usuari@servidor1
ssh-copy-id usuari@servidor2

3. Inventory: Definir els servidors

L'inventory és un fitxer que defineix els servidors que Ansible gestionarà.

Format INI (més simple)

# /etc/ansible/hosts o ./hosts

# Hosts individuals
servidor1.exemple.cat
192.168.1.10

# Grups de hosts
[webservers]
web1.exemple.cat
web2.exemple.cat
web3.exemple.cat

[databases]
db1.exemple.cat
db2.exemple.cat

# Grups de grups
[producció:children]
webservers
databases

# Variables per host
[webservers]
web1.exemple.cat ansible_user=admin ansible_port=2222
web2.exemple.cat ansible_user=root

# Variables per grup
[webservers:vars]
ansible_user=deploy
http_port=80

Format YAML (més estructurat)

# inventory.yml
all:
  children:
    webservers:
      hosts:
        web1.exemple.cat:
        web2.exemple.cat:
        web3.exemple.cat:
      vars:
        ansible_user: deploy
        http_port: 80
    
    databases:
      hosts:
        db1.exemple.cat:
        db2.exemple.cat:
      vars:
        ansible_user: postgres

Comprovar l'inventory

# Llistar tots els hosts
ansible all --list-hosts -i hosts

# Llistar hosts d'un grup
ansible webservers --list-hosts -i hosts

# Veure variables d'un host
ansible web1.exemple.cat -m debug -a "var=hostvars[inventory_hostname]" -i hosts

4. Mòduls d'Ansible

Els mòduls són les eines que Ansible usa per fer tasques. Hi ha centenars de mòduls.

Mòduls més comuns

ping - Comprovar connectivitat

ansible all -m ping -i hosts

shell - Executar comandes

ansible webservers -m shell -a "uptime" -i hosts
ansible all -m shell -a "df -h /" -i hosts

command - Executar comandes (més segur que shell)

ansible all -m command -a "hostname" -i hosts

apt - Gestionar paquets (Debian/Ubuntu)

# Instal·lar paquet
ansible webservers -m apt -a "name=nginx state=present" -i hosts -b

# Actualitzar cache
ansible all -m apt -a "update_cache=yes" -i hosts -b

# Actualitzar tots els paquets
ansible all -m apt -a "upgrade=dist" -i hosts -b

yum/dnf - Gestionar paquets (RedHat/CentOS/Fedora)

ansible all -m dnf -a "name=httpd state=present" -i hosts -b

copy - Copiar fitxers

# Copiar fitxer local a remot
ansible webservers -m copy -a "src=/local/file.txt dest=/remote/file.txt" -i hosts

# Amb permisos específics
ansible webservers -m copy -a "src=config.conf dest=/etc/app/config.conf mode=0644 owner=root" -i hosts -b

file - Gestionar fitxers i directoris

# Crear directori
ansible all -m file -a "path=/opt/app state=directory mode=0755" -i hosts -b

# Eliminar fitxer
ansible all -m file -a "path=/tmp/old.log state=absent" -i hosts

service/systemd - Gestionar serveis

# Iniciar servei
ansible webservers -m service -a "name=nginx state=started" -i hosts -b

# Reiniciar servei
ansible webservers -m service -a "name=nginx state=restarted" -i hosts -b

# Enable al boot
ansible webservers -m service -a "name=nginx enabled=yes" -i hosts -b

user - Gestionar usuaris

# Crear usuari
ansible all -m user -a "name=deploy state=present shell=/bin/bash" -i hosts -b

# Afegir a grup
ansible all -m user -a "name=deploy groups=sudo append=yes" -i hosts -b

Opcions de línia de comandes

# -i: Especificar inventory
ansible all -m ping -i hosts

# -b o --become: Executar com a root (sudo)
ansible all -m apt -a "name=nginx state=present" -i hosts -b

# --become-user: Executar com a un usuari específic
ansible all -m shell -a "whoami" -i hosts -b --become-user=postgres

# -u: Especificar usuari SSH
ansible all -m ping -i hosts -u admin

# -k o --ask-pass: Demanar contrasenya SSH
ansible all -m ping -i hosts -k

# -K o --ask-become-pass: Demanar contrasenya sudo
ansible all -m apt -a "name=nginx state=present" -i hosts -b -K

# -v, -vv, -vvv: Verbositat (debug)
ansible all -m ping -i hosts -v

5. Playbooks: Automatització avançada

Els playbooks són fitxers YAML que defineixen conjunts de tasques.

Estructura bàsica d'un playbook

---
# playbook.yml

- name: Nom descriptiu del play
  hosts: grup_de_hosts
  become: yes  # Executar com a root
  vars:
    # Variables locals
    variable1: valor1
    variable2: valor2
  
  tasks:
    - name: Descripció de la tasca
      mòdul:
        paràmetre1: valor1
        paràmetre2: valor2

Exemple 1: Instal·lar i configurar nginx

---
# nginx.yml

- name: Instal·lar i configurar nginx
  hosts: webservers
  become: yes
  
  tasks:
    - name: Actualitzar cache d'apt
      apt:
        update_cache: yes
    
    - name: Instal·lar nginx
      apt:
        name: nginx
        state: present
    
    - name: Copiar fitxer de configuració
      copy:
        src: files/nginx.conf
        dest: /etc/nginx/nginx.conf
        owner: root
        group: root
        mode: '0644'
    
    - name: Assegurar que nginx està iniciat
      service:
        name: nginx
        state: started
        enabled: yes
    
    - name: Reiniciar nginx per aplicar canvis
      service:
        name: nginx
        state: restarted

Executar el playbook:

ansible-playbook nginx.yml -i hosts

Exemple 2: Desplegar aplicació web

---
# deploy_web.yml

- name: Desplegar aplicació web
  hosts: webservers
  become: yes
  vars:
    app_dir: /var/www/html
    app_user: www-data
  
  tasks:
    - name: Crear directori de l'aplicació
      file:
        path: "{{ app_dir }}"
        state: directory
        owner: "{{ app_user }}"
        mode: '0755'
    
    - name: Copiar fitxers de l'aplicació
      copy:
        src: "{{ item }}"
        dest: "{{ app_dir }}/"
        owner: "{{ app_user }}"
      loop:
        - files/index.html
        - files/style.css
        - files/script.js
    
    - name: Copiar imatges
      copy:
        src: files/images/
        dest: "{{ app_dir }}/images/"
        owner: "{{ app_user }}"

Variables en playbooks

---
- name: Exemple de variables
  hosts: all
  vars:
    # Variables simples
    nom_paquet: nginx
    port: 80
    
    # Llistes
    paquets:
      - git
      - curl
      - vim
    
    # Diccionaris
    usuari:
      nom: deploy
      grup: deploy
      shell: /bin/bash
  
  tasks:
    - name: Instal·lar paquet
      apt:
        name: "{{ nom_paquet }}"
        state: present
    
    - name: Instal·lar múltiples paquets
      apt:
        name: "{{ item }}"
        state: present
      loop: "{{ paquets }}"
    
    - name: Crear usuari
      user:
        name: "{{ usuari.nom }}"
        group: "{{ usuari.grup }}"
        shell: "{{ usuari.shell }}"

Handlers: Executar tasques quan hi ha canvis

---
- name: Configurar servei
  hosts: webservers
  become: yes
  
  tasks:
    - name: Copiar configuració
      copy:
        src: files/app.conf
        dest: /etc/app/app.conf
      notify: Reiniciar app  # Crida al handler si hi ha canvis
    
    - name: Copiar certificat SSL
      copy:
        src: files/cert.pem
        dest: /etc/ssl/cert.pem
      notify: Reiniciar app
  
  handlers:
    - name: Reiniciar app
      service:
        name: app
        state: restarted

Els handlers només s'executen:

Condicionals

---
- name: Tasques condicionals
  hosts: all
  
  tasks:
    - name: Instal·lar nginx (només Ubuntu/Debian)
      apt:
        name: nginx
        state: present
      when: ansible_os_family == "Debian"
    
    - name: Instal·lar httpd (només RedHat/CentOS)
      yum:
        name: httpd
        state: present
      when: ansible_os_family == "RedHat"
    
    - name: Crear usuari si no existeix
      user:
        name: deploy
        state: present
      when: ansible_user_id != "deploy"

Bucles

---
- name: Exemple de bucles
  hosts: all
  
  tasks:
    - name: Crear múltiples usuaris
      user:
        name: "{{ item }}"
        state: present
      loop:
        - user1
        - user2
        - user3
    
    - name: Crear usuaris amb més dades
      user:
        name: "{{ item.name }}"
        group: "{{ item.group }}"
        shell: "{{ item.shell }}"
      loop:
        - { name: 'user1', group: 'users', shell: '/bin/bash' }
        - { name: 'user2', group: 'admin', shell: '/bin/zsh' }

6. Organització de projectes Ansible

Estructura recomanada

projecte_ansible/
├── ansible.cfg          # Configuració d'Ansible
├── inventory/
│   ├── hosts            # Inventory principal
│   ├── group_vars/      # Variables per grup
│   │   ├── all.yml
│   │   ├── webservers.yml
│   │   └── databases.yml
│   └── host_vars/       # Variables per host
│       ├── web1.yml
│       └── db1.yml
├── playbooks/
│   ├── site.yml         # Playbook principal
│   ├── webservers.yml
│   └── databases.yml
├── roles/               # Roles (avançat)
├── files/               # Fitxers a copiar
└── templates/           # Plantilles Jinja2

Fitxer ansible.cfg

[defaults]
inventory = ./inventory/hosts
remote_user = deploy
host_key_checking = False
retry_files_enabled = False

[privilege_escalation]
become = True
become_method = sudo
become_user = root
become_ask_pass = False

7. Depuració i resolució de problemes

Debug de variables

- name: Mostrar variables
  hosts: all
  tasks:
    - name: Mostrar tots els facts
      debug:
        var: ansible_facts
    
    - name: Mostrar variable específica
      debug:
        var: ansible_distribution
    
    - name: Missatge personalitzat
      debug:
        msg: "El servidor és {{ inventory_hostname }}"

Dry-run (check mode)

# Veure què faria sense fer-ho
ansible-playbook playbook.yml -i hosts --check

# Mostrar diferències
ansible-playbook playbook.yml -i hosts --check --diff

Executar només algunes tasques

# Executar només tasques amb tag específic
ansible-playbook playbook.yml -i hosts --tags "config"

# Saltar tasques amb tag
ansible-playbook playbook.yml -i hosts --skip-tags "slow"
---
- name: Playbook amb tags
  hosts: all
  tasks:
    - name: Instal·lar paquets
      apt:
        name: nginx
      tags: install
    
    - name: Configurar servei
      copy:
        src: config.conf
        dest: /etc/nginx/
      tags: config

8. Bones pràctiques

  1. Usar inventory dinàmic per entorns cloud
  2. Organitzar en roles per a projectes grans
  3. Usar ansible-vault per secrets
  4. Idempotència: Playbooks han de poder executar-se múltiples vegades
  5. Documentar: Usar name: descriptius
  6. Testejar: Usar --check abans de desplegar
  7. Control de versions: Git per a playbooks i inventory
  8. Separar entorns: inventory/production, inventory/development

Resum