Ir al contenido
  1. Posts/

Ansible: gestiona 10 servidores como si fuera 1

·3334 palabras·16 mins
Tabla de contenido

Cuando tienes un servidor, SSH y un script de Bash funcionan bien. Cuando tienes tres, copiar y pegar comandos todavía es manejable. Cuando llegas a cinco o más, necesitas Ansible.

Yo descubrí Ansible cuando mi homelab pasó de 2 a 8 nodos. Mantener actualizados los sistemas, desplegar configuraciones, instalar paquetes, todo eso manualmente se volvió insostenible. Un día actualicé 7 servidores pero olvidé el octavo. Obvio, ese fue el que falló en producción días después.

Ansible resolvió ese problema. Ahora tengo 14 máquinas (entre Raspberry Pis, VMs en Proxmox, containers LXC, nodos de Kubernetes) y las gestiono todas desde mi portátil con comandos que tardan segundos en ejecutarse. Esto es lo que aprendí.

Qué es Ansible y por qué no es como Chef o Puppet
#

Ansible es una herramienta de automatización que te permite definir el estado deseado de tus servidores en archivos de texto (YAML) y aplicar esos cambios remotamente. No necesitas instalar agentes en los servidores (como requieren Chef o Puppet). Todo funciona sobre SSH.

Imagina que quieres instalar Docker en 10 servidores. Sin Ansible:

1
2
3
4
ssh servidor1 'sudo apt update && sudo apt install docker.io -y'
ssh servidor2 'sudo apt update && sudo apt install docker.io -y'
ssh servidor3 'sudo apt update && sudo apt install docker.io -y'
# ... repite 7 veces más

Con Ansible:

1
ansible all -m apt -a "name=docker.io state=present" --become

Un comando. Todos los servidores. Y si alguno ya tiene Docker instalado, Ansible detecta que no hay cambios necesarios y lo salta (idempotencia).

Ventajas sobre otros sistemas de gestión:

  1. Agentless: no instalas nada en los servidores. Solo necesitan Python (que casi todos los Linux traen) y acceso SSH.

  2. Sintaxis simple: YAML legible, sin DSL complejo como Chef. Si sabes leer indentación, sabes leer Ansible.

  3. Modo push: tú ejecutas Ansible desde tu máquina. Los servidores no “piden” configuración (como en Puppet). Esto es más seguro en homelabs sin IPs públicas.

  4. Comunidad enorme: hay miles de roles y módulos preconstruidos. Necesitas configurar Nginx, hay un rol. PostgreSQL, hay otro. No reinventas la rueda.

Casos de uso reales en mi homelab
#

Antes de explicar cómo instalarlo, te cuento para qué lo uso. Así ves si te sirve:

1. Actualizaciones masivas
#

Cada domingo ejecuto un playbook que actualiza todos los servidores:

1
ansible-playbook playbooks/update-all.yml

El playbook hace apt update, apt upgrade, reinicia servicios si hace falta, y me manda un resumen por Telegram. Sin tocar cada máquina.

2. Despliegue de configuraciones
#

Tengo un rol de Ansible que despliega mi configuración estándar en cualquier servidor nuevo: usuarios, SSH hardening, fail2ban, herramientas comunes (htop, vim, git), timezone, locale. Provisionar un servidor nuevo lleva 3 minutos en lugar de 30.

3. Backups coordinados
#

Cada noche, Ansible ejecuta scripts de backup en varios nodos, comprueba que los backups se crearon correctamente, y sube los archivos a un NAS central. Si algo falla, recibo una alerta.

4. Gestión de certificados SSL
#

Tengo un playbook que renueva certificados de Let’s Encrypt en todos los reverse proxies (Nginx, Traefik) y recarga los servicios. Antes lo hacía manualmente y más de una vez un certificado expiró porque olvidé un servidor.

5. Despliegue de aplicaciones
#

Cuando quiero probar una app nueva (por ejemplo, Uptime Kuma), escribo un playbook que la despliega en un nodo de pruebas, configura el reverse proxy, y si todo va bien, lo ejecuto en producción. Reproducible y versionado en Git.

Instalación de Ansible
#

Ansible se instala en TU máquina (tu portátil, tu estación de trabajo). Los servidores remotos no necesitan nada especial.

En Ubuntu/Debian
#

1
2
sudo apt update
sudo apt install ansible -y

Verifica la instalación:

1
ansible --version

Deberías ver algo como ansible [core 2.16.3] o superior.

En macOS
#

1
brew install ansible

En Arch Linux
#

1
sudo pacman -S ansible

Via pip (cualquier OS con Python)
#

Si quieres la última versión:

1
pip3 install ansible --user

Añade ~/.local/bin a tu PATH si no está ya.

Configuración SSH sin contraseñas
#

Ansible usa SSH para conectarse a los servidores. Necesitas autenticación por clave pública (sin contraseñas interactivas).

Genera una clave SSH si no tienes:

1
ssh-keygen -t ed25519 -C "ansible@homelab"

Copia la clave pública a cada servidor:

1
2
ssh-copy-id usuario@servidor1
ssh-copy-id usuario@servidor2

Prueba la conexión:

1
ssh usuario@servidor1

Deberías entrar sin pedir contraseña. Repite para todos los servidores.

Consejo de seguridad: crea un usuario específico para Ansible (ansible o deploy) con permisos sudo. No uses root directamente.

En cada servidor:

1
2
3
sudo adduser ansible
sudo usermod -aG sudo ansible
echo "ansible ALL=(ALL) NOPASSWD:ALL" | sudo tee /etc/sudoers.d/ansible

Así Ansible puede ejecutar comandos con sudo sin pedir contraseña.

Inventario: define tus servidores
#

El archivo de inventario (inventory.ini o hosts.yml) es donde listas tus servidores. Es el mapa de tu infraestructura.

Crea un archivo ~/ansible/inventory.ini:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
[proxmox]
pve1 ansible_host=192.168.0.10 ansible_user=ansible
pve2 ansible_host=192.168.0.11 ansible_user=ansible
pve3 ansible_host=192.168.0.12 ansible_user=ansible

[k8s_masters]
k8s-cp1 ansible_host=192.168.0.20 ansible_user=ansible
k8s-cp2 ansible_host=192.168.0.21 ansible_user=ansible

[k8s_workers]
k8s-w1 ansible_host=192.168.0.30 ansible_user=ansible
k8s-w2 ansible_host=192.168.0.31 ansible_user=ansible
k8s-w3 ansible_host=192.168.0.32 ansible_user=ansible

[raspberry]
rpi4-dns ansible_host=192.168.0.40 ansible_user=pi
rpi3-sensor ansible_host=192.168.0.41 ansible_user=pi

[all:vars]
ansible_python_interpreter=/usr/bin/python3

Explicación:

  • [proxmox], [k8s_masters], etc. son grupos. Puedes ejecutar comandos en grupos enteros.
  • ansible_host es la IP o hostname del servidor.
  • ansible_user es el usuario SSH.
  • [all:vars] define variables para todos los hosts (por ejemplo, qué Python usar).

Prueba que Ansible puede conectarse:

1
ansible all -i inventory.ini -m ping

Deberías ver SUCCESS para cada servidor. Si no, revisa SSH.

Tu primer comando ad-hoc
#

Los comandos ad-hoc son útiles para tareas rápidas. Sintaxis:

1
ansible <grupo> -i <inventario> -m <módulo> -a "<argumentos>"

Ejemplos:

Comprobar el uptime de todos los servidores
#

1
ansible all -i inventory.ini -m command -a "uptime"

Reiniciar todos los servidores del grupo Proxmox
#

1
ansible proxmox -i inventory.ini -m reboot --become

(--become ejecuta el comando con sudo)

Instalar htop en todos los servidores
#

1
ansible all -i inventory.ini -m apt -a "name=htop state=present" --become

Copiar un archivo a todos los nodos
#

1
ansible all -i inventory.ini -m copy -a "src=/local/config.txt dest=/etc/config.txt mode=0644" --become

Verificar el espacio en disco
#

1
ansible all -i inventory.ini -m shell -a "df -h | grep /dev/sd"

Estos comandos son geniales para emergencias o comprobaciones rápidas. Pero para tareas repetibles, usas playbooks.

Tu primer playbook: actualizar todos los servidores
#

Un playbook es un archivo YAML que define una serie de tareas. Crea ~/ansible/playbooks/update-all.yml:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
---
- name: Actualizar todos los servidores
  hosts: all
  become: yes
  tasks:
    - name: Actualizar lista de paquetes
      apt:
        update_cache: yes
        cache_valid_time: 3600

    - name: Actualizar todos los paquetes
      apt:
        upgrade: dist
        autoremove: yes
        autoclean: yes

    - name: Verificar si se requiere reinicio
      stat:
        path: /var/run/reboot-required
      register: reboot_required

    - name: Notificar si se requiere reinicio
      debug:
        msg: "El servidor {{ inventory_hostname }} requiere reinicio"
      when: reboot_required.stat.exists

Ejecútalo:

1
ansible-playbook -i inventory.ini playbooks/update-all.yml

Ansible conecta a todos los servidores, ejecuta las tareas en orden, y te muestra un resumen:

1
2
3
4
PLAY RECAP
pve1        : ok=4    changed=2    unreachable=0    failed=0
k8s-cp1     : ok=4    changed=1    unreachable=0    failed=0
rpi4-dns    : ok=4    changed=0    unreachable=0    failed=0

Breakdown del playbook:

  • hosts: all - ejecutar en todos los servidores del inventario.
  • become: yes - usar sudo para todas las tareas.
  • tasks - lista de acciones a ejecutar.
  • apt - módulo para gestionar paquetes en Debian/Ubuntu.
  • stat - módulo para comprobar si un archivo existe.
  • register - guardar el resultado de una tarea en una variable.
  • when - ejecutar una tarea solo si se cumple una condición.

Playbook más complejo: provisionar un servidor nuevo
#

Este playbook configura un servidor desde cero con mi setup estándar. playbooks/provision-server.yml:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
---
- name: Provisionar servidor nuevo
  hosts: all
  become: yes
  vars:
    admin_user: luis
    admin_ssh_key: "ssh-ed25519 AAAAC3... tu-clave-publica"
    timezone: "Europe/Madrid"

  tasks:
    - name: Actualizar sistema
      apt:
        update_cache: yes
        upgrade: dist

    - name: Instalar paquetes básicos
      apt:
        name:
          - vim
          - git
          - htop
          - curl
          - wget
          - tmux
          - fail2ban
          - ufw
          - python3-pip
        state: present

    - name: Configurar timezone
      timezone:
        name: "{{ timezone }}"

    - name: Crear usuario administrador
      user:
        name: "{{ admin_user }}"
        groups: sudo
        shell: /bin/bash
        create_home: yes
        state: present

    - name: Añadir clave SSH al usuario
      authorized_key:
        user: "{{ admin_user }}"
        key: "{{ admin_ssh_key }}"
        state: present

    - name: Configurar sudo sin contraseña
      lineinfile:
        path: /etc/sudoers.d/{{ admin_user }}
        line: "{{ admin_user }} ALL=(ALL) NOPASSWD:ALL"
        create: yes
        mode: '0440'

    - name: Configurar SSH (deshabilitar root, solo clave pública)
      lineinfile:
        path: /etc/ssh/sshd_config
        regexp: "{{ item.regexp }}"
        line: "{{ item.line }}"
        state: present
      with_items:
        - { regexp: '^PermitRootLogin', line: 'PermitRootLogin no' }
        - { regexp: '^PasswordAuthentication', line: 'PasswordAuthentication no' }
        - { regexp: '^PubkeyAuthentication', line: 'PubkeyAuthentication yes' }
      notify: Reiniciar SSH

    - name: Configurar firewall UFW (permitir SSH, denegar resto)
      ufw:
        rule: allow
        port: '22'
        proto: tcp

    - name: Habilitar UFW
      ufw:
        state: enabled

    - name: Habilitar fail2ban
      systemd:
        name: fail2ban
        enabled: yes
        state: started

  handlers:
    - name: Reiniciar SSH
      systemd:
        name: sshd
        state: restarted

Nuevos conceptos aquí:

  • vars - variables que puedes reutilizar en el playbook.
  • with_items - bucle para ejecutar una tarea múltiples veces con diferentes valores.
  • handlers - tareas que solo se ejecutan si otra tarea hace cambios (por ejemplo, reiniciar SSH solo si modificaste su configuración).
  • notify - llama a un handler.

Ejecuta este playbook en un servidor nuevo:

1
ansible-playbook -i inventory.ini playbooks/provision-server.yml --limit servidor-nuevo

(--limit restringe la ejecución a un solo host)

Roles: organiza tus playbooks
#

Cuando los playbooks crecen, se vuelven difíciles de mantener. Los roles son la forma de modularizar. Un rol es un paquete reutilizable de tareas, plantillas, archivos, y variables.

Estructura típica de un rol:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
roles/
└── common/
    ├── tasks/
    │   └── main.yml
    ├── handlers/
    │   └── main.yml
    ├── templates/
    │   └── config.j2
    ├── files/
    │   └── script.sh
    ├── vars/
    │   └── main.yml
    └── defaults/
        └── main.yml

Ejemplo: rol para instalar y configurar Docker.

Crea la estructura:

1
mkdir -p roles/docker/{tasks,handlers,templates}

roles/docker/tasks/main.yml:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
---
- name: Instalar dependencias de Docker
  apt:
    name:
      - apt-transport-https
      - ca-certificates
      - curl
      - gnupg
      - lsb-release
    state: present

- name: Añadir clave GPG de Docker
  apt_key:
    url: https://download.docker.com/linux/ubuntu/gpg
    state: present

- name: Añadir repositorio de Docker
  apt_repository:
    repo: "deb [arch=amd64] https://download.docker.com/linux/ubuntu {{ ansible_distribution_release }} stable"
    state: present

- name: Instalar Docker
  apt:
    name:
      - docker-ce
      - docker-ce-cli
      - containerd.io
    state: present
    update_cache: yes

- name: Añadir usuario al grupo docker
  user:
    name: "{{ ansible_user }}"
    groups: docker
    append: yes

- name: Habilitar Docker al inicio
  systemd:
    name: docker
    enabled: yes
    state: started

Ahora puedes usar este rol en cualquier playbook:

1
2
3
4
5
6
---
- name: Instalar Docker en todos los workers
  hosts: k8s_workers
  become: yes
  roles:
    - docker

Ejecuta:

1
ansible-playbook -i inventory.ini playbooks/setup-docker.yml

Ventaja de roles: puedes compartirlos entre playbooks o descargar roles de Ansible Galaxy (repositorio público de roles).

Por ejemplo, instalar el rol geerlingguy.docker:

1
ansible-galaxy install geerlingguy.docker

Y usarlo:

1
2
roles:
  - geerlingguy.docker

Variables y plantillas (Jinja2)
#

Ansible usa Jinja2 para generar archivos de configuración dinámicos.

Supón que quieres desplegar una configuración de Nginx con el nombre del servidor y la IP. Crea una plantilla templates/nginx.conf.j2:

1
2
3
4
5
6
7
8
9
server {
    listen 80;
    server_name {{ inventory_hostname }};

    location / {
        proxy_pass http://{{ ansible_default_ipv4.address }}:8080;
        proxy_set_header Host $host;
    }
}

En tu playbook:

1
2
3
4
5
- name: Desplegar configuración de Nginx
  template:
    src: templates/nginx.conf.j2
    dest: /etc/nginx/sites-available/{{ inventory_hostname }}.conf
  notify: Reiniciar Nginx

Ansible reemplaza {{ inventory_hostname }} y {{ ansible_default_ipv4.address }} con los valores reales de cada servidor. Si ejecutas el playbook en 5 servidores, cada uno recibe una configuración adaptada a su contexto.

Ansible Vault: gestiona secretos
#

Nunca metas contraseñas o tokens en plain text en tus playbooks. Usa Ansible Vault para encriptar archivos.

Crea un archivo de secretos:

1
ansible-vault create secrets.yml

Te pedirá una contraseña. Dentro, escribe:

1
2
db_password: mi-password-super-secreto
api_token: abc123xyz789

Guarda y sal. El archivo está encriptado.

Para usarlo en un playbook:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
---
- name: Configurar base de datos
  hosts: db_servers
  become: yes
  vars_files:
    - secrets.yml
  tasks:
    - name: Configurar PostgreSQL
      postgresql_user:
        name: appuser
        password: "{{ db_password }}"

Ejecuta el playbook:

1
ansible-playbook -i inventory.ini playbooks/setup-db.yml --ask-vault-pass

Ansible te pide la contraseña del vault, desencripta secrets.yml, y usa las variables.

Consejo: guarda la contraseña del vault en un archivo y pásala con --vault-password-file:

1
2
3
echo "mi-password-del-vault" > ~/.vault_pass
chmod 600 ~/.vault_pass
ansible-playbook --vault-password-file ~/.vault_pass playbooks/setup-db.yml

Tags: ejecuta solo parte de un playbook
#

Si tienes un playbook largo y solo quieres ejecutar ciertas tareas, usa tags.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
tasks:
  - name: Actualizar paquetes
    apt:
      update_cache: yes
      upgrade: dist
    tags:
      - update

  - name: Instalar Docker
    apt:
      name: docker.io
      state: present
    tags:
      - docker

  - name: Configurar firewall
    ufw:
      rule: allow
      port: '22'
    tags:
      - firewall

Ejecuta solo las tareas con tag docker:

1
ansible-playbook playbooks/setup.yml --tags docker

O excluye tareas con cierto tag:

1
ansible-playbook playbooks/setup.yml --skip-tags update

Esto es útil cuando estás depurando o cuando solo necesitas aplicar cambios específicos.

Integración con Git
#

Tus playbooks, roles, inventarios, todo debería estar en Git. Así tienes historial de cambios, puedes revertir si algo rompe, y otros pueden colaborar.

Estructura recomendada de tu repo:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
ansible-homelab/
├── inventory.ini
├── ansible.cfg
├── playbooks/
│   ├── update-all.yml
│   ├── provision-server.yml
│   └── deploy-app.yml
├── roles/
│   ├── common/
│   ├── docker/
│   └── nginx/
├── group_vars/
│   ├── all.yml
│   └── proxmox.yml
├── host_vars/
│   └── pve1.yml
└── secrets.yml (encriptado con Vault)

ansible.cfg define configuración global:

1
2
3
4
5
[defaults]
inventory = inventory.ini
host_key_checking = False
retry_files_enabled = False
roles_path = ./roles

Haz commit de todo (excepto .vault_pass y cualquier secreto no encriptado):

1
2
3
4
5
git init
git add .
git commit -m "Initial Ansible setup"
git remote add origin [email protected]:tu-usuario/ansible-homelab.git
git push -u origin main

Ahora puedes clonar el repo en cualquier máquina y ejecutar playbooks. Reproducibilidad total.

Estrategias de despliegue
#

Cuando ejecutas un playbook en múltiples servidores, Ansible por defecto los procesa en paralelo (hasta forks servidores a la vez, por defecto 5). Esto es rápido pero si algo rompe, rompes 5 servidores a la vez.

Para despliegues más seguros, usa serial:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
---
- name: Actualizar servidores de forma escalonada
  hosts: all
  become: yes
  serial: 1
  tasks:
    - name: Actualizar paquetes
      apt:
        update_cache: yes
        upgrade: dist

    - name: Reiniciar si es necesario
      reboot:
        reboot_timeout: 300
      when: reboot_required

serial: 1 procesa un servidor a la vez. Si falla en el primero, Ansible se detiene antes de tocar el resto. Para clusters grandes, puedes hacer serial: "25%" (procesa 25% de los hosts a la vez).

También existe max_fail_percentage:

1
2
3
- name: Despliegue con tolerancia a fallos
  hosts: all
  max_fail_percentage: 10

Si más del 10% de los hosts fallan, Ansible aborta.

Troubleshooting común
#

Ansible no encuentra Python
#

Error: /usr/bin/python: not found

Solución: en inventario, añade:

1
2
[all:vars]
ansible_python_interpreter=/usr/bin/python3

Permisos denegados en sudo
#

Error: FAILED! => {"msg": "Missing sudo password"}

Solución: ejecuta con -K (pide contraseña de sudo):

1
ansible-playbook playbooks/setup.yml -K

O configura NOPASSWD en /etc/sudoers como expliqué antes.

Fallos intermitentes por SSH
#

Si tienes muchos hosts, SSH puede timeoutear. Aumenta el timeout en ansible.cfg:

1
2
3
[ssh_connection]
ssh_args = -o ControlMaster=auto -o ControlPersist=60s
timeout = 30

Playbook muy lento
#

Ansible por defecto recoge información de cada host al inicio (facts gathering). Si no necesitas esos datos, deshabilítalo:

1
2
3
4
5
6
7
8
9
---
- name: Playbook rápido
  hosts: all
  gather_facts: no
  tasks:
    - name: Reiniciar servicio
      systemd:
        name: nginx
        state: restarted

Pasa de 10 segundos a 2 segundos en playbooks simples.

Casos de uso avanzados
#

CI/CD con Ansible
#

Puedes integrar Ansible en pipelines de GitLab CI o GitHub Actions. Cada vez que haces push a main, el pipeline ejecuta playbooks automáticamente.

Ejemplo de .gitlab-ci.yml:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
stages:
  - deploy

deploy_production:
  stage: deploy
  image: willhallonline/ansible:latest
  script:
    - eval $(ssh-agent -s)
    - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add -
    - ansible-playbook -i inventory.ini playbooks/deploy-app.yml
  only:
    - main

Dynamic inventory con scripts
#

Si tus servidores cambian frecuentemente (por ejemplo, VMs en la nube), puedes usar inventarios dinámicos. Ansible ejecuta un script que genera el inventario en JSON.

Ejemplo: script que consulta la API de Proxmox y lista todas las VMs.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
#!/usr/bin/env python3
import json
import requests

API_URL = "https://proxmox.local:8006/api2/json"
TOKEN = "tu-token-api"

response = requests.get(f"{API_URL}/cluster/resources?type=vm", 
                        headers={"Authorization": f"PVEAPIToken={TOKEN}"})
vms = response.json()['data']

inventory = {"all": {"hosts": []}}
for vm in vms:
    inventory["all"]["hosts"].append(vm['name'])

print(json.dumps(inventory))

Guárdalo como dynamic_inventory.py, hazlo ejecutable, y úsalo:

1
ansible all -i dynamic_inventory.py -m ping

Integración con AWX/Ansible Tower
#

Si tu homelab crece mucho, considera instalar AWX (la versión open source de Ansible Tower). Es una UI web que:

  • Ejecuta playbooks desde el navegador.
  • Programa ejecuciones periódicas (cron jobs visuales).
  • Gestiona inventarios dinámicos.
  • Logs y auditoría de todos los despliegues.

Yo no lo uso porque mi homelab es pequeño, pero si gestiono más de 20 servidores lo montaría.

Comparación con otras herramientas
#

Terraform vs Ansible: Terraform es para provisionar infraestructura (crear VMs, redes, DNS). Ansible es para configurar lo que ya existe. Úsalos juntos: Terraform crea la VM, Ansible la configura.

Docker/Kubernetes vs Ansible: containers son para aplicaciones, Ansible es para configurar el sistema base. En mi caso, Ansible prepara los nodos (instala Docker, configura red, usuarios) y luego despliego containers encima.

Bash scripts vs Ansible: Bash es más rápido de escribir para cosas simples. Ansible escala mejor, es más legible, y tiene idempotencia incorporada. Usa Bash para scripts de una sola máquina, Ansible para fleets.

Conclusión: escala tu homelab sin perder la cordura
#

Ansible es de esas herramientas que al principio piensas “esto es overkill para mi homelab”. Y luego, cuando tu homelab crece, te preguntas cómo sobrevivías sin ella.

La curva de aprendizaje es suave. Empiezas con comandos ad-hoc, luego playbooks simples, luego roles, y de repente estás orquestando despliegues multi-servidor con un solo comando.

En mi caso, Ansible me devolvió horas cada semana. Las actualizaciones de seguridad que antes llevaban una tarde ahora son 5 minutos. Provisionar un servidor nuevo que llevaba una hora ahora es automático. Y lo mejor: todo está documentado en código, versionado en Git, reproducible.

Si tienes más de 3 servidores en tu homelab, monta Ansible este fin de semana. Si tienes menos de 3, móntalo de todas formas. Cuando llegues a 5, estarás agradecido.


Recursos para profundizar: