DataSkills Hub

Ansible

Ansible es la herramienta de automatización agentless para orquestación de infraestructura. Se utiliza para desplegar, configurar y mantener componentes como clusters de Trino, Spark, Kafka, NiFi y PostgreSQL. Los playbooks se versionan en el repositorio de infraestructura y se ejecutan desde la máquina de control (bastion host).

#Getting Started

#Instalación y verificación

Verificar que Ansible está instalado en el bastion host

ansible --version
# Esperado: ansible [core 2.15.x]

ansible-inventory --list -i inventory/
# Verifica que el inventario es válido

#Estructura básica de archivos

ansible/
├── playbooks/           # Playbooks principales
│   ├── deploy-trino.yml
│   ├── deploy-spark.yml
│   └── deploy-kafka.yml
├── roles/               # Roles reutilizables
│   ├── java/
│   ├── hadoop/
│   └── database/
├── inventory/           # Inventario de hosts
│   ├── production/
│   └── staging/
├── group_vars/          # Variables por grupo de hosts
├── host_vars/           # Variables por host específico
└── ansible.cfg          # Configuración global de Ansible

#Acceder a bastion host

ssh -i ~/.ssh/platform-key ubuntu@<tu-url>

# Verificar inventario
cd ~/ansible
ansible-inventory --list -i inventory/production/

#Inventory

#Estructura de inventario

inventory/production/
├── hosts.yml           # Definición de hosts y grupos
└── group_vars/
    ├── trino.yml       # Variables para grupo Trino
    ├── spark.yml       # Variables para grupo Spark
    └── kafka.yml       # Variables para grupo Kafka

#Ejemplo: hosts.yml

all:
  children:
    trino:
      hosts:
        <tu-url>:
          ansible_host: <ip-host>
          ansible_user: ubuntu
          jvm_memory: '64g'
        <trino-worker-host-1>:
          ansible_host: <ip-host>
          ansible_user: ubuntu
        <trino-worker-host-2>:
          ansible_host: <ip-host>
          ansible_user: ubuntu

    spark:
      hosts:
        <tu-url>:
          ansible_host: <ip-host>
        <spark-worker-host-[1:3]>:

    kafka:
      vars:
        kafka_version: '3.6.0'
      hosts:
        <kafka-broker-host-[1:3]>:

#Variables por grupo (group_vars)

Archivo: group_vars/trino.yml

# Versión de Trino a desplegar
trino_version: '430'

# Catálogos disponibles
trino_catalogs:
  - name: 'hive'
    connector: 'hive'
    metastore_uri: '<metastore-url>'
  - name: 'postgres'
    connector: 'postgresql'
    host: '<tu-url>'

# Configuración JVM
trino_jvm_max_memory: '64GB'
trino_discovery_uri: '<tu-url>'

#Verificar conectividad

# Ping a todos los hosts del inventario
ansible all -i inventory/production/ -m ping

# Ping a hosts específicos de un grupo
ansible trino -i inventory/production/ -m ping

# Ejecutar comando shell en grupo Kafka
ansible kafka -i inventory/production/ -m shell -a "hostname"

#Playbooks

#Estructura básica de un Playbook

---
- name: Desplegar Trino cluster
  hosts: trino
  become: yes # Ejecutar con sudo
  vars:
    service_name: trino

  roles:
    - role: java
      vars:
        java_version: '17'
    - role: trino
      vars:
        trino_version: '430'

#Ejecutar un Playbook

# Ejecución simple
ansible-playbook playbooks/deploy-trino.yml -i inventory/production/

# Con verbose (ver detalles)
ansible-playbook playbooks/deploy-trino.yml -i inventory/production/ -vv

# Dry-run (no aplicar cambios, solo mostrar lo que haría)
ansible-playbook playbooks/deploy-trino.yml -i inventory/production/ --check

# Limitar a hosts específicos
ansible-playbook playbooks/deploy-trino.yml -i inventory/production/ --limit trino-coordinator

#Ejemplo: Playbook para actualizar sistema

---
- name: Actualizar OS en todos los nodos
  hosts: all
  become: yes

  tasks:
    - name: Actualizar lista de paquetes
      apt:
        update_cache: yes

    - name: Upgrade paquetes
      apt:
        upgrade: dist
        autoremove: yes
        autoclean: yes

    - name: Reiniciar si es necesario
      reboot:
        msg: 'Sistema siendo actualizado'
        reboot_timeout: 300

#Roles

#Estructura de un Role

roles/java/
├── defaults/
│   └── main.yml        # Variables por defecto
├── tasks/
│   └── main.yml        # Tareas a ejecutar
├── handlers/
│   └── main.yml        # Handlers (reiniciar servicio, etc.)
├── templates/
│   └── config.j2       # Templates de archivos
├── files/
│   └── script.sh       # Archivos para copiar
└── vars/
    └── main.yml        # Variables de role (prioridad alta)

#Ejemplo: Role para instalar Java

Archivo: roles/java/defaults/main.yml

java_version: '17'
java_home: '/usr/lib/jvm/java-{{ java_version }}-openjdk-amd64'

Archivo: roles/java/tasks/main.yml

---
- name: Instalar OpenJDK {{ java_version }}
  apt:
    name: 'openjdk-{{ java_version }}-jdk'
    state: present
    update_cache: yes

- name: Verificar instalación
  shell: java -version
  register: java_check
  changed_when: false

- name: Mostrar versión instalada
  debug:
    msg: '{{ java_check.stderr_lines }}'

#Usar un Role en Playbook

---
- name: Setup base para cluster Kafka
  hosts: kafka
  become: yes

  roles:
    - role: java
      vars:
        java_version: '21'
    - role: base-packages
    - kafka

#Módulos Comunes

#Módulos para Administración de Paquetes

Módulo Descripción Ejemplo
apt Gestionar paquetes Debian/Ubuntu apt: name=curl state=present
yum Gestionar paquetes RedHat/CentOS yum: name=git state=latest
pip Instalar paquetes Python pip: name=pandas version=1.5.0

#Módulos para Servicios

Módulo Descripción Ejemplo
service Control de servicios systemd service: name=trino state=started
systemd Gestión de servicios (recomendado) systemd: name=kafka enabled=yes
docker_container Manage Docker containers docker_container: name=spark image=spark:latest

#Módulos para Archivos

Módulo Descripción Ejemplo
copy Copiar archivos a hosts copy: src=files/config.xml dest=/opt/
template Copiar con variables Jinja2 template: src=config.j2 dest=/etc/app/
lineinfile Modificar líneas en archivo lineinfile: path=/etc/config line="key=value"
file Crear, eliminar, cambiar permisos file: path=/opt/data owner=ubuntu mode=0755

#Módulos para Ejecución

Módulo Descripción Ejemplo
shell Ejecutar comando shell shell: "curl http://<tu-url>:<puerto>/health"
command Ejecutar comando (más seguro) command: ls -la /opt
script Ejecutar script local script: scripts/setup.sh

#Variables y Facts

#Orden de precedencia de variables (mayor a menor)

1. Variables en línea de comando (ansible-playbook --extra-vars)
2. Variables en playbook (vars: section)
3. Variables en role (roles/.../vars/)
4. group_vars/ (grupo específico)
5. host_vars/ (host específico)
6. defaults/ en roles
7. Facts de Ansible (variables automáticas)

#Usar variables

---
- name: Variables en Playbook
  hosts: trino
  vars:
    service_name: 'trino'
    port: <puerto>

  tasks:
    - name: Usar variables
      debug:
        msg: 'Servicio {{ service_name }} en puerto {{ port }}'

    - name: Usar facts de Ansible
      debug:
        msg: 'IP: {{ ansible_default_ipv4.address }}'

#Registrar salida de comandos

- name: Obtener versión de Java
  command: java -version
  register: java_output
  changed_when: false

- name: Mostrar resultado
  debug:
    var: java_output.stderr_lines

#Secrets y Vault

#Crear archivo encriptado con Vault

# Crear archivo de secretos encriptado
ansible-vault create roles/kafka/vars/secrets.yml

# Editar archivo existente
ansible-vault edit roles/kafka/vars/secrets.yml

# Ver contenido sin editar
ansible-vault view roles/kafka/vars/secrets.yml

#Contenido de archivo Vault (secretos.yml)

---
kafka_admin_user: admin
kafka_admin_password: <password-encriptado>
broker_ssl_key_password: <password-encriptado>
db_password: <password-encriptado>

#Usar secretos en Playbook

---
- name: Setup Kafka con credenciales
  hosts: kafka
  become: yes
  vars_files:
    - roles/kafka/vars/secrets.yml # Cargado automáticamente si está encriptado

  tasks:
    - name: Crear usuario admin
      shell: |
        kafka-configs.sh --alter \
          --add-config="SCRAM-SHA-256=[password={{ kafka_admin_password }}]" \
          --entity-type users \
          --entity-name "{{ kafka_admin_user }}"

#Ejecutar Playbook con Vault

# Será pedida la contraseña del vault
ansible-playbook playbooks/deploy-kafka.yml --ask-vault-pass

# O usar archivo de contraseña (más seguro con control de acceso)
ansible-playbook playbooks/deploy-kafka.yml --vault-password-file ~/.vault-pass

#Handlers y Notificaciones

#Handlers para reiniciar servicios

Archivo: roles/trino/handlers/main.yml

---
- name: Reiniciar Trino
  systemd:
    name: trino
    state: restarted
    daemon_reload: yes

- name: Recargar configuración Trino
  systemd:
    name: trino
    state: reloaded

Archivo: roles/trino/tasks/main.yml

---
- name: Copiar configuración Trino
  template:
    src: config.properties.j2
    dest: /etc/trino/config.properties
  notify: Reiniciar Trino

- name: Copiar catálogo Hive
  copy:
    src: files/hive.properties
    dest: /etc/trino/catalog/
  notify: Recargar configuración Trino

#Mejores Prácticas

#Convenciones para Playbooks

Convención Descripción
Nombre deploy-<componente>.yml o update-<componente>.yml
Idempotencia Playbooks deben ser seguros de ejecutar múltiples veces
Handlers Usar siempre handlers, no reinicios directos
Dry-run first Ejecutar con --check antes de aplicar cambios
Limit carefully Usar --limit para no afectar otros clusters

#Checklist antes de desplegar

  • Playbook pasa --check sin errores
  • Inventario es correcto: ansible-inventory --list
  • Credenciales/SSH keys funcionan: ansible all -m ping
  • Rol específico fue testeado en staging primero
  • Variables se interpolaron correctamente: ansible-playbook -e para verificar
  • Rollback plan definido si algo falla

#Monitoreo post-deploy

# Verificar que servicios están activos
ansible trino -m systemd -a "name=trino state=started enabled=yes"

# Health check
ansible trino -m uri -a "url=http://<tu-url>:<puerto>/ui/ status_code=200"

# Ver logs después de deploy
ansible trino -m shell -a "tail -20 /var/log/trino/launcher.log"

#Troubleshooting

#Host no responde

# Verificar conectividad SSH
ansible <hostname> -i inventory/production/ -m ping -vv

# Revisar configuración SSH en ansible.cfg
cat ansible.cfg

# Conexión directa
ssh -v ubuntu@<tu-url>

#Módulo falla con permiso denegado

# Asegurar que become está activado
- hosts: trino
  become: yes # Ejecutar con sudo
  become_user: root # O especificar usuario

#Task toma demasiado tiempo

Agregar timeout:

- name: Tarea que tarda
  command: long_running_script.sh
  timeout: 600 # Timeout en segundos
  async: 0 # Ejecutar en background

#Variables no se interpolan

# Verificar variables disponibles para un host
ansible <hostname> -m debug -a "var=hostvars[inventory_hostname]"

#Also see