Saltar al contenido principal

Roles en Ansible y Ansible Galaxy: modulariza nuestro código

Hasta ahora hemos escrito playbooks lineales. Cuando un proyecto crece, esos ficheros se vuelven inmanejables. En este capítulo aprendemos a modularizar nuestro código con roles, reutilizamos trabajo de la comunidad con Ansible Galaxy y aplicamos buenas prácticas que mantendrán nuestro repositorio sano a largo plazo.

Los roles usan templates Jinja2 para generar configuraciones dinámicas — si necesitamos repasar la sintaxis de Jinja2, volvemos al módulo 4.

Roles y modularidad 📦​

Organizamos nuestro código como un profesional usando la estructura de roles.

🎥 Vídeo completo, utilicemos los capítulos de youtube para saltar a la sección que nos interese: https://youtu.be/5tH-uroFfW8

Roles y Ansible Galaxy: reutiliza tu código - Curso Ansible #7

Introducción: ¿por qué roles?​

Hasta ahora, hemos escrito playbooks que son listas largas de tareas. Esto funciona bien para 10 o 20 tareas, pero ¿qué pasa cuando tenemos 500? ¿O cuando queremos configurar Nginx en 10 proyectos diferentes?

Código espagueti vs receta de espaguetis​

Imaginemos improvisar la misma receta cada vez que cocinamos, sin apuntar cantidades ni pasos: un día sale salada, otro se nos queda caldosa, en fin. Eso pasa también con un playbook gigante sin estructura: funciona, pero cada vez sale un poco distinto y nadie se atreve a tocarlo.

Los roles son como una receta de cocina bien escrita.

  • Tenemos una cocina donde preparamos los platos, que serían los servidores.
  • Queremos preparar un plato concreto (servidor web).
  • En lugar de improvisar los pasos cada vez, seguimos la receta "Nginx a la plancha" (rol webserver), con sus pasos fijos (tasks) y sus cantidades de ingredientes por defecto (defaults).
  • ¡Listo! El mismo plato, servido igual en cualquier cocina, ajustando solo la sal a nuestro gusto (variables).

La estructura de un rol​

Ansible espera una estructura de carpetas muy específica. Si la respetamos, la magia ocurre sola (autoloading).

🌳 Anatomía visual​

Diccionario de carpetas​

  • tasks/: Aquí van los módulos (apt, copy, service). Es lo que antes teníamos en la sección tasks: del playbook.
  • handlers/: Los disparadores (restart nginx).
  • templates/: Nuestros archivos .j2.
  • files/: Archivos que se copian tal cual (certificados, imágenes).
  • defaults/: Variables con la prioridad más baja. Están hechas para ser sobrescritas fácilmente por el usuario del rol.
  • vars/: Variables con prioridad alta. Las usamos para constantes que rara vez cambian.
  • meta/: Metadatos del rol: información del autor, licencia y dependencias de otros roles.

Creando nuestro primer rol​

Vamos a refactorizar. Tomaremos el "código espagueti" de un servidor web y lo convertiremos en un rol elegante.

Paso 1: inicializar la estructura​

Ansible tiene un comando para crear el esqueleto por nosotros:

ansible-galaxy init webserver

Paso 2: mover las piezas (refactorización)​

Supongamos que ya tenemos el playbook de la práctica del módulo 3: instala Nginx, configura el firewall con ufw y publica una página personalizada:

# site.yml (espagueti) ❌
- name: Configurar servidor web con handlers, loops y tags
hosts: target1
become: true

tasks:
- name: Actualizar índices de paquetes
apt:
update_cache: yes
cache_valid_time: 3600

- name: Instalar paquetes necesarios
apt:
name: "{{ item }}"
state: present
loop:
- nginx
- ufw
tags:
- install

- name: Configurar firewall
ufw:
rule: allow
port: "{{ item }}"
loop:
- "22"
- "80"
- "443"
tags:
- security
- config

- name: Copiar configuración de Nginx
copy:
src: ./nginx.conf
dest: /etc/nginx/nginx.conf
owner: nginx
group: nginx
mode: '0644'
backup: yes
validate: 'nginx -t -c %s'
notify: Recargar nginx
tags:
- config
- nginx

- name: Crear página web personalizada
copy:
dest: /var/www/html/index.html
content: |
<h1>¡Hola desde Ansible! 🚀</h1>
<p>Este servidor ha sido configurado automáticamente.</p>
<p>SO: {{ ansible_facts['distribution'] }} {{ ansible_facts['distribution_version'] }}</p>
owner: nginx
tags:
- config
- nginx

- name: Asegurar que Nginx está corriendo
service:
name: nginx
state: started
enabled: yes
tags:
- nginx

- name: Mostrar IP del servidor (solo en Debian)
debug:
msg: "Servidor accesible en: http://{{ ansible_facts['default_ipv4']['address'] }}"
when: ansible_facts['distribution'] == "Debian"
tags:
- ip

handlers:
- name: Recargar nginx
service:
name: nginx
state: reloaded

Funciona, pero todo vive apelmazado en un único fichero: instalación, firewall, configuración y contenido mezclados. Si mañana queremos este mismo servidor en otro proyecto, copiamos y pegamos las 60 líneas enteras. Eso es espagueti.

Ahora, "descuartizamos" las tareas y ponemos cada cosa en su lugar dentro de la carpeta webserver/:

1. roles/webserver/tasks/main.yml

- name: Actualizar índices de paquetes
apt:
update_cache: yes
cache_valid_time: 3600

- name: Instalar paquetes necesarios
apt:
name: "{{ item }}"
state: present
loop: "{{ webserver_packages }}"
tags:
- install

- name: Configurar firewall
ufw:
rule: allow
port: "{{ item }}"
loop: "{{ webserver_allowed_ports }}"
tags:
- security
- config

- name: Crear usuario nginx
user:
name: nginx
shell: /usr/sbin/nologin
system: yes

- name: Copiar configuración de Nginx
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
owner: nginx
group: nginx
mode: '0644'
backup: yes
validate: 'nginx -t -c %s'
notify: Recargar nginx
tags:
- config
- nginx

- name: Crear página web personalizada
copy:
dest: "{{ webserver_html_root }}/index.html"
content: |
<h1>¡Hola desde Ansible! 🚀</h1>
<p>Este servidor ha sido configurado automáticamente.</p>
<p>SO: {{ ansible_facts['distribution'] }} {{ ansible_facts['distribution_version'] }}</p>
owner: nginx
tags:
- config
- nginx

- name: Asegurar que Nginx está corriendo
service:
name: nginx
state: started
enabled: yes
tags:
- nginx

- name: Mostrar IP del servidor (solo en Debian)
debug:
msg: "Servidor accesible en: http://{{ ansible_facts['default_ipv4']['address'] }}"
when: ansible_facts['distribution'] == "Debian"
tags:
- ip

2. roles/webserver/handlers/main.yml

- name: Recargar nginx
service:
name: nginx
state: reloaded

3. roles/webserver/defaults/main.yml

webserver_packages:
- nginx
- ufw
webserver_allowed_ports:
- "22"
- "80"
- "443"
webserver_html_root: /var/www/html

4. roles/webserver/templates/nginx.conf.j2

El ./nginx.conf estático que copiábamos a pelo ahora vive dentro del rol como plantilla Jinja2. Aunque hoy no interpole ninguna variable, en cuanto necesitemos que cambie por entorno (workers, límites, dominio) ya está en el sitio correcto.

Paso 3: el resultado final (limpio y profesional)​

Nuestro playbook principal (site.yml) ahora queda así de minimalista:

# site.yml (modular) ✅
- hosts: servers
roles:
- webserver

¡Y si mañana queremos abrir un puerto extra o cambiar los paquetes instalados, tocamos webserver_allowed_ports o webserver_packages en un sitio y listo! Podemos usar el rol webserver en cualquier proyecto simplemente añadiéndolo a nuestro requirements.yml.

Usar un rol desde site.yml​

Una vez creado el rol, por ejemplo con ansible-galaxy init roles/webserver, podemos llamarlo desde el playbook principal usando únicamente el nombre de la carpeta del rol:

- name: Configurar servidores web
hosts: target1
become: true

roles:
- webserver

Con la estructura habitual roles/webserver/, Ansible lo encuentra automáticamente al ejecutar ansible-playbook site.yml desde la raíz del proyecto. Si el rol está en otra ubicación, debemos añadir esa ruta en ansible.cfg mediante roles_path:

[defaults]
roles_path = ./roles:../roles-compartidos

Ansible buscará primero en ./roles/ y después en ../roles-compartidos/. Las rutas se separan con : en macOS y Linux. En Windows se separan con ;.

Dependencias entre roles​

Los roles pueden depender de otros roles. Por ejemplo, si nuestro rol webserver necesita que PostgreSQL esté configurado antes de publicar la aplicación, podemos declarar esa dependencia en el archivo meta/main.yml del propio rol webserver.

🔗 Ejemplo de dependencias​

La estructura mínima del proyecto sería:

roles/
├── postgresql/
│ └── tasks/main.yml
└── webserver/
├── meta/main.yml
└── tasks/main.yml

roles/webserver/meta/main.yml

dependencies:
- role: postgresql
vars:
postgresql_database: app_db
postgresql_user: app_user

El nombre postgresql debe coincidir exactamente con el nombre de la carpeta del rol. La dependencia se ejecuta antes de las tareas de webserver, pero no se instala automáticamente: ambos roles deben existir en una ruta incluida en roles_path.

Si el rol postgresql utiliza la collection community.docker, necesitamos instalarla en el nodo de control. Ni ansible-galaxy install del rol ni dependencies: de meta/main.yml descargan collections automáticamente, así que la declaramos en requirements.yml:

requirements.yml

# Los roles postgresql y webserver son locales: viven en ./roles/,
# no hace falta listarlos aquí.

# Collections que necesitan las tasks de esos roles
collections:
- name: community.docker
version: 3.4.11

¿Cómo funciona?​

  1. Cuando ejecutamos el rol webserver, Ansible primero ejecuta postgresql y después las tareas propias de webserver.
  2. Los roles se ejecutan solo una vez, aunque múltiples roles los tengan como dependencia.
  3. Podemos pasar variables específicas a cada dependencia usando vars:.

Usar roles en playbooks con dependencias​

# site.yml
- hosts: servers
roles:
- webserver # Ejecutará postgresql → webserver

Ejecutando el conjunto​

  1. Instalamos las collections del proyecto (los roles locales ya están en ./roles/, no hace falta "instalarlos"):
    ansible-galaxy install -r requirements.yml
  2. Comprobamos el roles_path: postgresql y webserver deben convivir en una ruta incluida en roles_path (normalmente ./roles/, configurada en ansible.cfg). Las dependencies: de meta/main.yml se resuelven en local: si postgresql no está ahí, el playbook falla al arrancar, no se descarga sobre la marcha.
  3. Lanzamos el playbook como cualquier otro:
    ansible-playbook -i inventory site.yml
  4. Ansible construye el grafo de dependencias de webserver y ejecuta, en orden: postgresql (con las variables de base de datos) → las tareas propias de webserver.
  5. Como cada rol es idempotente, si volvemos a lanzar el mismo comando no se recrea la base de datos ni se repiten las configuraciones ya aplicadas; Ansible solo hace los cambios que falten.

💡 Buenas prácticas​

  • No abusemos: Si tenemos 10 niveles de dependencias, algo está mal en nuestro diseño.
  • Documentemos: Siempre indicamos en el README qué roles son prerequisitos.
  • Versionemos: Si usamos roles de Galaxy, fijamos las versiones en requirements.yml.

Ansible galaxy y collections​

No reinventemos la rueda. Probablemente alguien ya ha creado el rol perfecto para instalar Docker, Kubernetes o MySQL.

🌌 Ansible galaxy (el "app store")​

Es el repositorio oficial de contenido comunitario.

  • Buscar roles: ansible-galaxy search elasticsearch
  • Instalar un rol: ansible-galaxy install geerlingguy.elasticsearch

📦 Content collections (el nuevo estándar)​

Antiguamente, Galaxy solo tenía roles. Ahora, con la complejidad de la nube, usamos collections. Una collection es un paquete que incluye: roles + módulos + plugins.

Por ejemplo, la collection amazon.aws incluye módulos para EC2, S3, Lambda, etc.

Comandos esenciales​
# Instalar una colección
ansible-galaxy collection install amazon.aws

# Listar lo que tienes instalado
ansible-galaxy collection list
Usando collections en un playbook​
- hosts: localhost
collections:
- amazon.aws # Declaramos que usaremos esta colección
tasks:
- name: Crear instancia EC2
ec2_instance: # Módulo que viene dentro de la colección
instance_type: t2.micro

Resumen​

  1. Divide y vencerás: Usamos roles para separar responsabilidades.
  2. Estandaricemos: Respetamos la estructura de carpetas (tasks, vars, templates) para que cualquiera entienda nuestro código.
  3. Reutilicemos: Antes de escribir código, buscamos en Ansible Galaxy. Si tenemos que escribirlo, lo hacemos pensando en que sea un rol genérico para el futuro.
  4. Declaremos dependencias: Usamos meta/main.yml para especificar qué roles necesita nuestro rol antes de ejecutarse.

Ansible Galaxy y Collections 🌌​

Aprendemos a reutilizar código de la comunidad y a compartir nuestros propios roles con el mundo.

¿Qué es Ansible Galaxy?​

🌟 El "App Store" de Ansible​

Imaginemos que necesitamos configurar un servidor con Docker. Podríamos escribir todas las tareas desde cero (instalar dependencias, añadir repositorios, configurar el daemon, etc.), o simplemente descargar un rol ya probado y mantenido por la comunidad.

Ansible Galaxy es el repositorio oficial donde miles de desarrolladores comparten roles, collections y plugins listos para usar.

🎯 Ventajas de usar Galaxy​

  • Ahorro de tiempo: No reinventemos la rueda. Usamos roles probados en producción.
  • Calidad: Los roles populares tienen miles de descargas y están bien mantenidos.
  • Estandarización: Aprendemos buenas prácticas viendo código de expertos.
  • Comunidad: Contribuimos con mejoras y reportamos bugs.

🌐 Galaxy vs Collections​

  • Galaxy (tradicional): Repositorio de roles individuales.
  • Collections (moderno): Paquetes que incluyen roles + módulos + plugins + documentación.

Buscando roles en Galaxy​

🔍 Búsqueda desde línea de comandos​

# Buscar roles relacionados con "docker"
ansible-galaxy search docker

# Buscar con un término más específico
ansible-galaxy search mysql --author geerlingguy

# Ver detalles de un rol específico
ansible-galaxy info geerlingguy.docker

📊 Output de ejemplo​

$ ansible-galaxy search nginx

Found 523 roles matching your search:

Name Description
---- -----------
geerlingguy.nginx Nginx installation for Linux
jdauphant.nginx Install and configure nginx
nginxinc.nginx Official NGINX role
...

🌐 Búsqueda en la web​

La forma más cómoda es buscar en galaxy.ansible.com:

  • Filtros: Por plataforma (Ubuntu, CentOS, etc.), categoría, autor.
  • Métricas: Descargas, estrellas, fecha de última actualización.
  • Documentación: README, dependencias, versiones compatibles.

💡 Criterios para elegir un buen rol​

Criterio¿Qué buscar?
PopularidadMás de 1000 descargas, estrellas altas
MantenimientoÚltima actualización reciente (< 6 meses)
CompatibilidadSoporta nuestra distribución y versión de Ansible
DocumentaciónREADME completo con ejemplos
LicenciaOpen source (MIT, Apache, BSD)

Instalando roles desde Galaxy​

📥 Instalación básica​

# Instalar un rol (se guarda en ~/.ansible/roles/)
ansible-galaxy install geerlingguy.docker

# Instalar en una ruta específica
ansible-galaxy install geerlingguy.nginx -p ./roles/

# Instalar una versión específica
ansible-galaxy install geerlingguy.mysql,3.4.0

📦 Usando requirements.yml​

Para proyectos profesionales, nunca instalemos roles manualmente. Usamos un archivo requirements.yml para documentar todas las dependencias.

requirements.yml

# Roles desde Galaxy
roles:
- name: geerlingguy.docker
version: 6.1.0

- name: geerlingguy.nginx
version: 3.1.4

- name: geerlingguy.mysql
version: 4.3.3

- name: geerlingguy.redis
version: 1.8.0

# Collections
collections:
- name: community.general
version: 8.1.0

- name: ansible.posix
version: 1.5.4

- name: amazon.aws
version: 7.1.0

🚀 Instalación desde requirements.yml​

# Instalar todos los roles y collections del archivo
ansible-galaxy install -r requirements.yml

# Forzar reinstalación (útil para actualizar)
ansible-galaxy install -r requirements.yml --force

# Instalar en ruta específica
ansible-galaxy install -r requirements.yml -p ./roles/

🔗 Instalando desde Git​

Podemos instalar roles directamente desde repositorios Git (GitHub, GitLab, etc.):

requirements.yml

roles:
# Desde GitHub
- src: https://github.com/usuario/mi-rol.git
name: mi_rol_custom
version: main # Branch, tag o commit

# Desde GitLab
- src: git@gitlab.com:empresa/rol-interno.git
name: rol_interno
scm: git

# Desde Galaxy con nombre personalizado
- src: geerlingguy.apache
name: apache_role
version: 3.2.0

Usando roles instalados en playbooks​

Una vez instalados, los roles se usan como cualquier otro rol local:

📝 Ejemplo: playbook con roles de Galaxy​

site.yml

- name: Configurar servidor web con roles de Galaxy
hosts: servers
become: true

vars:
# Variables para geerlingguy.docker
docker_users:
- deployer
- jenkins

# Variables para geerlingguy.nginx
nginx_vhosts:
- listen: "80"
server_name: "ejemplo.com www.ejemplo.com"
root: "/var/www/ejemplo"

roles:
- geerlingguy.docker
- geerlingguy.nginx
- geerlingguy.certbot

post_tasks:
- name: Verificar que Docker está corriendo
service:
name: docker
state: started

🔧 Sobrescribiendo variables de roles​

Los roles de Galaxy suelen tener muchas variables configurables. Revisamos su documentación:

# Ver variables disponibles de un rol
cat ~/.ansible/roles/geerlingguy.docker/defaults/main.yml

# O en GitHub:
# https://github.com/geerlingguy/ansible-role-docker#role-variables

Ejemplo de sobrescritura:

- hosts: servers
roles:
- role: geerlingguy.mysql
vars:
mysql_root_password: "secreto123"
mysql_databases:
- name: wordpress
encoding: utf8mb4
mysql_users:
- name: wpuser
password: "pass123"
priv: "wordpress.*:ALL"

Collections: el nuevo estándar​

📦 ¿Qué es una Collection?​

Una collection es un paquete que puede incluir:

  • Roles: Como los tradicionales
  • Módulos: Nuevas funcionalidades (aws_ec2, docker_container)
  • Plugins: Filtros, callbacks, inventarios
  • Documentación: Guías y ejemplos

🌍 Collections oficiales importantes​

CollectionDescripciónEjemplo de uso
community.generalMódulos generales de la comunidadtimezone, snap, git_config
ansible.posixHerramientas POSIX/Unixmount, sysctl, firewalld
amazon.awsServicios de AWSec2, s3, rds, lambda
azure.azcollectionMicrosoft Azureazure_rm_virtualmachine
google.cloudGoogle Cloud Platformgcp_compute_instance
community.dockerGestión de Dockerdocker_container, docker_image
community.mysqlBase de datos MySQLmysql_db, mysql_user
community.kubernetesKubernetes/K8sk8s, helm

📥 Instalando collections​

# Instalar una collection
ansible-galaxy collection install community.general

# Instalar versión específica
ansible-galaxy collection install amazon.aws:7.1.0

# Instalar desde requirements.yml
ansible-galaxy collection install -r requirements.yml

# Listar collections instaladas
ansible-galaxy collection list

# Ver información de una collection
ansible-galaxy collection info community.docker

🗂️ Ubicación de collections​

Las collections se instalan en:

  • Sistema: /usr/share/ansible/collections/
  • Usuario: ~/.ansible/collections/ansible_collections/
  • Proyecto: ./collections/ansible_collections/

📝 Usando collections en playbooks​

Opción 1: Declarar a nivel de play

- name: Gestionar AWS EC2
hosts: localhost
collections:
- amazon.aws # Todos los módulos de esta collection están disponibles

tasks:
- name: Crear instancia EC2
ec2_instance: # Módulo de amazon.aws
name: target1
instance_type: t3.micro
image_id: ami-0c55b159cbfafe1f0
region: us-east-1
key_name: mi-llave
state: running

Opción 2: Usar FQCN (Fully Qualified Collection Name)

- name: Gestionar Docker
hosts: servidores
tasks:
- name: Crear contenedor Nginx
community.docker.docker_container: # FQCN completo
name: nginx
image: nginx:latest
ports:
- "80:80"
state: started

- name: Configurar timezone
community.general.timezone: # FQCN completo
name: Europe/Madrid

Recomendación: Usamos FQCN para evitar conflictos si dos collections tienen módulos con el mismo nombre.

Creando y publicando nuestro propio rol​

🛠️ Paso 1: Inicializar el rol​

# Crear estructura del rol
ansible-galaxy init webserver

# Estructura generada:
# webserver/
# ├── README.md
# ├── defaults/
# │ └── main.yml
# ├── files/
# ├── handlers/
# │ └── main.yml
# ├── meta/
# │ └── main.yml
# ├── tasks/
# │ └── main.yml
# ├── templates/
# ├── tests/
# │ ├── inventory
# │ └── test.yml
# └── vars/
# └── main.yml

📝 Paso 2: Escribir el código del rol​

tasks/main.yml

- name: Actualizar índices de paquetes
apt:
update_cache: yes
cache_valid_time: 3600

- name: Instalar paquetes necesarios
apt:
name: "{{ item }}"
state: present
loop: "{{ webserver_packages }}"
tags:
- install

- name: Configurar firewall
ufw:
rule: allow
port: "{{ item }}"
loop: "{{ webserver_allowed_ports }}"
tags:
- security
- config

- name: Copiar configuración de Nginx
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
owner: nginx
group: nginx
mode: '0644'
backup: yes
validate: 'nginx -t -c %s'
notify: Recargar nginx
tags:
- config
- nginx

- name: Crear página web personalizada
copy:
dest: "{{ webserver_html_root }}/index.html"
content: |
<h1>¡Hola desde Ansible! 🚀</h1>
<p>Este servidor ha sido configurado automáticamente.</p>
<p>SO: {{ ansible_facts['distribution'] }} {{ ansible_facts['distribution_version'] }}</p>
owner: nginx
tags:
- config
- nginx

- name: Asegurar que Nginx está corriendo
service:
name: nginx
state: started
enabled: yes
tags:
- nginx

- name: Mostrar IP del servidor (solo en Debian)
debug:
msg: "Servidor accesible en: http://{{ ansible_facts['default_ipv4']['address'] }}"
when: ansible_facts['distribution'] == "Debian"
tags:
- ip

defaults/main.yml

webserver_packages:
- nginx
- ufw
webserver_allowed_ports:
- "22"
- "80"
- "443"
webserver_html_root: /var/www/html

handlers/main.yml

- name: Recargar nginx
service:
name: nginx
state: reloaded

📄 Paso 3: Documentar en meta/main.yml​

meta/main.yml

galaxy_info:
author: Tu Nombre
description: Instalación y configuración de Nginx como servidor web
company: Tu Empresa (opcional)
license: MIT
min_ansible_version: "2.2"

platforms:
- name: Ubuntu
versions:
- focal
- jammy
- name: Debian
versions:
- bullseye
- bookworm

galaxy_tags:
- nginx
- web
- firewall
- ufw

dependencies: []

✍️ Paso 4: Escribir README.md completo​

README.md

# Rol Ansible: webserver

Instala y configura Nginx como servidor web, con el firewall gestionado por `ufw`.

## Requisitos

- Ansible >= 2.14
- Hosts Debian/Ubuntu con `apt`

## Variables

| Variable | Default | Descripción |
|----------|---------|-------------|
| `webserver_packages` | `[nginx, ufw]` | Paquetes a instalar |
| `webserver_allowed_ports` | `["22", "80", "443"]` | Puertos permitidos en el firewall |
| `webserver_html_root` | `/var/www/html` | Directorio con el HTML servido |

## Ejemplo de uso

```yaml
- hosts: servers
roles:
- role: webserver
vars:
webserver_html_root: /data/html
webserver_allowed_ports:
- "22"
- "80"

Licencia​

MIT

Autor​

Tu Nombre (@tu_usuario)


#### 🧪 Paso 5: Probar el rol localmente

```bash
# Ejecutar el test incluido
ansible-playbook tests/test.yml -i tests/inventory

# O crear un playbook de prueba
cat > test-rol.yml <<EOF
- hosts: localhost
become: true
roles:
- webserver
EOF

ansible-playbook test-rol.yml

📤 Paso 6: Publicar en Galaxy​

6.1. Subir a GitHub

cd webserver
git init
git add .
git commit -m "Versión inicial"
git remote add origin https://github.com/tu_usuario/ansible-role-webserver.git
git push -u origin main

# Crear un tag de versión
git tag 1.0.0
git push origin 1.0.0

6.2. Importar en Galaxy

  1. Vamos a galaxy.ansible.com
  2. Iniciamos sesión con GitHub
  3. Vamos a "Roles" → "Import role"
  4. Seleccionamos nuestro repositorio webserver
  5. Galaxy importará automáticamente nuestro rol

6.3. Actualizar versiones

# Hacer cambios en el código
git add .
git commit -m "Añadida compatibilidad con SSL"
git tag 1.1.0
git push origin main --tags

# Galaxy detectará el nuevo tag automáticamente

Buenas prácticas con Galaxy​

✅ DO:​

  • Fijamos versiones en requirements.yml: Evitamos sorpresas con actualizaciones.
  • Leemos el README antes de instalar: Entendemos qué hace el rol.
  • Revisamos el código: Especialmente en roles con pocos downloads.
  • Contribuimos con issues y PRs: Ayudamos a mejorar los roles que usamos.
  • Usamos FQCN en collections: Mayor claridad y evitamos conflictos.

❌ DON'T:​

  • No usemos roles sin mantenimiento: Buscamos alternativas activas.
  • No instalemos sin probar primero: Usamos --check mode.
  • No expongamos credenciales: Usamos Ansible Vault para secretos.
  • No dependamos de un solo rol: Tenemos un plan B si el autor lo abandona.

🔒 Seguridad​

# Verificar el código antes de ejecutar
cat ~/.ansible/roles/nombre_rol/tasks/main.yml

# Ejecutar en modo dry-run
ansible-playbook site.yml --check

# Limitar a un host de pruebas primero
ansible-playbook site.yml --limit test-server

Creando nuestra propia collection​

🎯 Cuándo crear una collection​

Creamos una collection cuando tengamos:

  • Múltiples roles relacionados
  • Módulos personalizados
  • Plugins o filtros custom
  • Documentación extensa

🛠️ Inicializar collection​

# Crear estructura de collection
ansible-galaxy collection init mi_namespace.mi_collection

# Estructura generada:
# mi_namespace/
# └── mi_collection/
# ├── README.md
# ├── galaxy.yml # Metadatos de la collection
# ├── docs/
# ├── plugins/
# │ ├── modules/ # Tus módulos custom
# │ ├── inventory/
# │ ├── lookup/
# │ └── filter/
# ├── roles/ # Roles incluidos
# └── playbooks/ # Playbooks de ejemplo

📝 Configurar galaxy.yml​

galaxy.yml

namespace: mi_namespace
name: mi_collection
version: 1.0.0
readme: README.md
authors:
- Tu Nombre <email@ejemplo.com>

description: Collection para gestión de infraestructura web

license:
- MIT

tags:
- web
- infrastructure
- automation

dependencies: {}

repository: https://github.com/tu_usuario/mi_collection
documentation: https://docs.ejemplo.com
homepage: https://ejemplo.com
issues: https://github.com/tu_usuario/mi_collection/issues

📦 Build y publicar​

# Construir la collection (crea un .tar.gz)
ansible-galaxy collection build

# Publicar en Galaxy (necesitas API key)
ansible-galaxy collection publish mi_namespace-mi_collection-1.0.0.tar.gz --api-key=TU_API_KEY

# Instalar localmente para pruebas
ansible-galaxy collection install ./mi_namespace-mi_collection-1.0.0.tar.gz

Ejemplo completo: proyecto con Galaxy​

Estructura del proyecto:

mi-proyecto/
├── ansible.cfg
├── requirements.yml
├── inventory/
│ └── hosts.yml
├── group_vars/
│ └── all.yml
├── playbooks/
│ └── site.yml
└── roles/ # Roles locales custom
└── mi_rol/

ansible.cfg

[defaults]
roles_path = ./roles:~/.ansible/roles
collections_path = ./collections:~/.ansible/collections
inventory = inventory/hosts.yml

requirements.yml

roles:
- name: geerlingguy.docker
version: 6.1.0
- name: geerlingguy.nginx
version: 3.1.4

collections:
- name: community.general
version: 8.1.0
- name: community.docker
version: 3.4.11

Workflow:

# 1. Instalar dependencias
ansible-galaxy install -r requirements.yml

# 2. Ejecutar playbook
ansible-playbook playbooks/site.yml

# 3. Actualizar dependencias cuando sea necesario
ansible-galaxy install -r requirements.yml --force

Comandos de referencia rápida​

# === ROLES ===
# Buscar roles
ansible-galaxy search <término>

# Instalar rol
ansible-galaxy install <autor>.<rol>

# Instalar desde requirements
ansible-galaxy install -r requirements.yml

# Listar roles instalados
ansible-galaxy list

# Eliminar rol
ansible-galaxy remove <autor>.<rol>

# Ver información de un rol
ansible-galaxy info <autor>.<rol>

# === COLLECTIONS ===
# Buscar collections
ansible-galaxy collection search <término>

# Instalar collection
ansible-galaxy collection install <namespace>.<collection>

# Listar collections instaladas
ansible-galaxy collection list

# Ver información
ansible-galaxy collection info <namespace>.<collection>

# === CREACIÓN ===
# Inicializar rol
ansible-galaxy init <nombre_rol>

# Inicializar collection
ansible-galaxy collection init <namespace>.<collection>

# Build collection
ansible-galaxy collection build

# Publicar collection
ansible-galaxy collection publish <archivo.tar.gz> --api-key=<KEY>

Resumen​

En este capítulo hemos aprendido:

✅ Qué es Ansible Galaxy: El repositorio oficial de contenido de la comunidad. ✅ Buscar e instalar roles: Cómo encontrar y usar roles de calidad. ✅ Requirements.yml: Gestión profesional de dependencias. ✅ Collections: El nuevo estándar que incluye roles, módulos y plugins. ✅ Publicar nuestro contenido: Compartimos nuestros roles con la comunidad. ✅ Buenas prácticas: Seguridad, versiones fijas y documentación.

💡 Puntos clave​

  1. No reinventemos la rueda: Usamos roles de Galaxy cuando sea posible.
  2. Fijamos versiones: requirements.yml es nuestro mejor amigo.
  3. Leemos el código: Especialmente de roles con pocos usuarios.
  4. Contribuimos: Reportamos bugs, enviamos PRs, mejoramos la comunidad.
  5. Usamos FQCN: Claridad y compatibilidad a largo plazo.