Exercicis Bash 04: Ansible Bàsic

Preparatius

1. Instal·lar Ansible

# Debian/Ubuntu
sudo apt install ansible -y

# Verificar
ansible --version

2. Configurar entorn de proves

Necessitareu accés a almenys 2-3 servidors/VMs. Opcions:

Opció A: Contenidors Docker (més fàcil per proves locals)

# Crear xarxa
docker network create ansible-net

# Crear 3 contenidors SSH
for i in 1 2 3; do
    docker run -d --name node$i \
        --network ansible-net \
        -p 222$i:22 \
        rastasheep/ubuntu-sshd:18.04
done

# Obtenir IPs
docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' node1

Opció B: Màquines virtuals (VirtualBox, QEMU, etc.)

Opció C: Servidors reals (si en teniu accés)

3. Configurar SSH

# Generar clau si no en tens
ssh-keygen -t ed25519 -f ~/.ssh/ansible_key

# Copiar a cada node (adapta segons el teu entorn)
ssh-copy-id -i ~/.ssh/ansible_key root@node1
ssh-copy-id -i ~/.ssh/ansible_key root@node2
ssh-copy-id -i ~/.ssh/ansible_key root@node3

# Provar connexió
ssh -i ~/.ssh/ansible_key root@node1

Exercici 1: Primer playbook - Instal·lació de paquets (40 minuts)

Part A: Crear l'inventory

Crea un fitxer inventory/hosts:

[all:vars]
ansible_user=root
ansible_ssh_private_key_file=~/.ssh/ansible_key

[webservers]
node1 ansible_host=192.168.1.10
node2 ansible_host=192.168.1.11

[databases]
node3 ansible_host=192.168.1.12

Adapta les IPs als teus nodes!

Part B: Comprovar connectivitat

# Comprovar tots els hosts
ansible all -m ping -i inventory/hosts

# Comprovar només webservers
ansible webservers -m ping -i inventory/hosts

# Obtenir informació del sistema
ansible all -m setup -i inventory/hosts | grep ansible_distribution

Part C: Crear el playbook

Crea playbooks/install_packages.yml:

---
- name: Instal·lar paquets bàsics a tots els servidors
  hosts: all
  become: yes
  
  tasks:
    - name: Actualitzar cache d'apt
      apt:
        update_cache: yes
        cache_valid_time: 3600
    
    - name: Instal·lar paquets bàsics
      apt:
        name:
          - vim
          - git
          - curl
          - htop
          - net-tools
        state: present
    
    - name: Mostrar missatge de confirmació
      debug:
        msg: "Paquets instal·lats correctament a {{ inventory_hostname }}"

- name: Instal·lar nginx als webservers
  hosts: webservers
  become: yes
  
  tasks:
    - name: Instal·lar nginx
      apt:
        name: nginx
        state: present
    
    - name: Assegurar que nginx està iniciat
      service:
        name: nginx
        state: started
        enabled: yes
    
    - name: Verificar que nginx funciona
      command: curl -s http://localhost
      register: nginx_output
      changed_when: false
    
    - name: Mostrar resultat
      debug:
        msg: "Nginx funcionant: {{ 'OK' if 'nginx' in nginx_output.stdout else 'ERROR' }}"

Tasques

  1. Executa el playbook:

    ansible-playbook playbooks/install_packages.yml -i inventory/hosts
    
  2. Verifica que s'ha instal·lat correctament:

    ansible webservers -m command -a "nginx -v" -i inventory/hosts
    ansible all -m command -a "git --version" -i inventory/hosts
    
  3. Executa el playbook una segona vegada. Què passa? Per què?

  4. Modifica el playbook per afegir més paquets (per exemple: python3-pip, tree, wget)

Resultat esperat

PLAY [Instal·lar paquets bàsics a tots els servidors] *************************

TASK [Gathering Facts] *********************************************************
ok: [node1]
ok: [node2]
ok: [node3]

TASK [Actualitzar cache d'apt] *************************************************
changed: [node1]
changed: [node2]
changed: [node3]

TASK [Instal·lar paquets bàsics] ***********************************************
changed: [node1]
changed: [node2]
changed: [node3]

PLAY [Instal·lar nginx als webservers] *****************************************

TASK [Instal·lar nginx] ********************************************************
changed: [node1]
changed: [node2]

TASK [Assegurar que nginx està iniciat] ***************************************
ok: [node1]
ok: [node2]

PLAY RECAP *********************************************************************
node1                      : ok=6    changed=3    unreachable=0    failed=0
node2                      : ok=6    changed=3    unreachable=0    failed=0
node3                      : ok=3    changed=2    unreachable=0    failed=0

Exercici 2: Desplegament de configuració (50 minuts)

Crea un playbook que desplega una aplicació web simple amb configuració personalitzada.

Part A: Preparar fitxers locals

mkdir -p files/web

Crea files/web/index.html:

<!DOCTYPE html>
<html>
<head>
    <title>{{ server_name }}</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <h1>Benvingut a {{ server_name }}</h1>
    <p>Servidor: {{ inventory_hostname }}</p>
    <p>Versió: {{ app_version }}</p>
</body>
</html>

Crea files/web/style.css:

body {
    font-family: Arial, sans-serif;
    max-width: 800px;
    margin: 50px auto;
    padding: 20px;
    background: #f0f0f0;
}
h1 {
    color: #333;
    border-bottom: 2px solid #007bff;
}

Crea files/nginx_site.conf:

server {
    listen 80;
    server_name _;
    
    root /var/www/myapp;
    index index.html;
    
    location / {
        try_files $uri $uri/ =404;
    }
}

Part B: Crear el playbook amb templates

Nota: Ansible usa Jinja2 per templates. Crea templates/index.html.j2 (versió amb variables):

<!DOCTYPE html>
<html>
<head>
    <title>{{ server_name }}</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <h1>Benvingut a {{ server_name }}</h1>
    <p>Servidor: {{ inventory_hostname }}</p>
    <p>IP: {{ ansible_default_ipv4.address }}</p>
    <p>Sistema: {{ ansible_distribution }} {{ ansible_distribution_version }}</p>
    <p>Versió app: {{ app_version }}</p>
    <p>Desplegat el: {{ ansible_date_time.date }} a les {{ ansible_date_time.time }}</p>
</body>
</html>

Crea playbooks/deploy_web.yml:

---
- name: Desplegar aplicació web
  hosts: webservers
  become: yes
  vars:
    app_dir: /var/www/myapp
    server_name: "Mon Servidor Web"
    app_version: "1.0.0"
  
  tasks:
    - name: Crear directori de l'aplicació
      file:
        path: "{{ app_dir }}"
        state: directory
        owner: www-data
        group: www-data
        mode: '0755'
    
    - name: Desplegar index.html amb template
      template:
        src: ../templates/index.html.j2
        dest: "{{ app_dir }}/index.html"
        owner: www-data
        group: www-data
        mode: '0644'
      notify: Reiniciar nginx
    
    - name: Copiar CSS
      copy:
        src: ../files/web/style.css
        dest: "{{ app_dir }}/style.css"
        owner: www-data
        group: www-data
        mode: '0644'
    
    - name: Configurar site nginx
      copy:
        src: ../files/nginx_site.conf
        dest: /etc/nginx/sites-available/myapp
        owner: root
        group: root
        mode: '0644'
      notify: Reiniciar nginx
    
    - name: Activar site
      file:
        src: /etc/nginx/sites-available/myapp
        dest: /etc/nginx/sites-enabled/myapp
        state: link
      notify: Reiniciar nginx
    
    - name: Desactivar site per defecte
      file:
        path: /etc/nginx/sites-enabled/default
        state: absent
      notify: Reiniciar nginx
    
    - name: Verificar configuració nginx
      command: nginx -t
      register: nginx_test
      changed_when: false
    
    - name: Mostrar resultat verificació
      debug:
        var: nginx_test.stderr_lines
  
  handlers:
    - name: Reiniciar nginx
      service:
        name: nginx
        state: restarted

Tasques

  1. Crea l'estructura de directoris i fitxers

  2. Executa el playbook:

    ansible-playbook playbooks/deploy_web.yml -i inventory/hosts
    
  3. Verifica que l'aplicació funciona:

    ansible webservers -m command -a "curl -s http://localhost" -i inventory/hosts
    
  4. Modifica app_version a "2.0.0" i torna a desplegar

  5. Comprova que els handlers només es criden quan hi ha canvis

Bonus

Afegeix una tasca que:


Exercici 3: Audit automatitzat (30 minuts)

Crea un playbook que recull informació de tots els servidors i genera un informe.

Crear playbooks/audit.yml

---
- name: Audit de servidors
  hosts: all
  become: yes
  
  tasks:
    - name: Recollir informació del sistema
      setup:
        gather_subset:
          - 'all'
    
    - name: Obtenir serveis actius
      service_facts:
    
    - name: Llistar paquets instal·lats
      package_facts:
        manager: apt
    
    - name: Comprovar últim login
      command: lastlog -u root
      register: last_login
      changed_when: false
    
    - name: Verificar espai en disc
      command: df -h /
      register: disc_info
      changed_when: false
    
    - name: Generar informe local
      delegate_to: localhost
      become: no
      copy:
        content: |
          ====================================
          INFORME D'AUDIT: {{ inventory_hostname }}
          Data: {{ ansible_date_time.iso8601 }}
          ====================================
          
          SISTEMA:
          - Distribució: {{ ansible_distribution }} {{ ansible_distribution_version }}
          - Kernel: {{ ansible_kernel }}
          - Arquitectura: {{ ansible_architecture }}
          - Hostname: {{ ansible_hostname }}
          - FQDN: {{ ansible_fqdn }}
          
          XARXA:
          - IP principal: {{ ansible_default_ipv4.address }}
          - Gateway: {{ ansible_default_ipv4.gateway }}
          - DNS: {{ ansible_dns.nameservers | join(', ') }}
          
          RECURSOS:
          - CPUs: {{ ansible_processor_vcpus }}
          - Memòria total: {{ ansible_memtotal_mb }} MB
          - Memòria lliure: {{ ansible_memfree_mb }} MB
          - Swap total: {{ ansible_swaptotal_mb }} MB
          
          DISC:
          {{ disc_info.stdout }}
          
          SERVEIS ACTIUS:
          {% for service in ansible_facts.services.keys() | sort %}
          {% if ansible_facts.services[service].state == "running" %}
          - {{ service }}: {{ ansible_facts.services[service].state }}
          {% endif %}
          {% endfor %}
          
          ÚLTIM LOGIN ROOT:
          {{ last_login.stdout }}
          
        dest: "./reports/audit_{{ inventory_hostname }}_{{ ansible_date_time.date }}.txt"
      run_once: false

- name: Generar resum consolidat
  hosts: localhost
  gather_facts: no
  
  tasks:
    - name: Crear resum
      shell: |
        echo "=====================================" > reports/resum.txt
        echo "RESUM D'AUDIT - $(date)" >> reports/resum.txt
        echo "=====================================" >> reports/resum.txt
        echo "" >> reports/resum.txt
        echo "Total servidors auditats: {{ groups['all'] | length }}" >> reports/resum.txt
        echo "" >> reports/resum.txt
        echo "Informes individuals generats:" >> reports/resum.txt
        ls -1 reports/audit_* >> reports/resum.txt
      args:
        creates: reports/resum.txt

Tasques

  1. Crea el directori reports/

  2. Executa el playbook:

    ansible-playbook playbooks/audit.yml -i inventory/hosts
    
  3. Revisa els informes generats:

    cat reports/resum.txt
    cat reports/audit_node1_*.txt
    
  4. Modifica el playbook per afegir més informació:

    • Paquets instal·lats (top 10 per mida)
    • Processos que consumeixen més CPU
    • Ports oberts (netstat/ss)
    • Usuaris del sistema

Resultat esperat

reports/
├── audit_node1_2024-01-08.txt
├── audit_node2_2024-01-08.txt
├── audit_node3_2024-01-08.txt
└── resum.txt

Exercici extra: Actualització massiva

Crea un playbook que actualitza tots els servidors de forma segura:

Requisits

  1. Fer backup abans d'actualitzar
  2. Actualitzar paquets
  3. Comprovar si cal reiniciar
  4. Generar informe amb:
    • Paquets actualitzats
    • Si cal reiniciar
    • Possibles errors

Esquelet

---
- name: Actualització segura de servidors
  hosts: all
  become: yes
  serial: 1  # Actualitzar un servidor cada vegada
  
  tasks:
    - name: Backup de llista de paquets
      shell: dpkg --get-selections > /tmp/packages_backup_{{ ansible_date_time.epoch }}.txt
      changed_when: false
    
    - name: Actualitzar cache
      apt:
        update_cache: yes
    
    - name: Comprovar paquets actualitzables
      command: apt list --upgradable
      register: upgradable_packages
      changed_when: false
    
    - name: Actualitzar tots els paquets
      apt:
        upgrade: dist
      register: upgrade_result
    
    - name: Comprovar si cal reiniciar
      stat:
        path: /var/run/reboot-required
      register: reboot_required
    
    - name: Generar informe
      # ... implementar

Criteris d'avaluació