Maximizando el rendimiento de Ansible con ControlPersist y Pipelining

Mejora significativamente el rendimiento de tus playbooks de Ansible al habilitar la reutilización de conexiones SSH con ControlPersist y optimizando la ejecución de módulos mediante Pipelining. Esta guía ofrece información clave y configuraciones prácticas para reducir los tiempos de ejecución, especialmente en entornos a gran escala. Aprende a optimizar tu archivo `ansible.cfg` para una automatización de TI más rápida y eficiente.

38 vistas

Maximizando el rendimiento de Ansible con ControlPersist y Pipelining

Ansible es una herramienta potente para automatizar la infraestructura de TI, permitiendo la gestión de configuración y el despliegue de aplicaciones a escala. Sin embargo, en entornos de alto volumen o al gestionar un gran número de nodos, la sobrecarga inherente de establecer conexiones SSH para cada tarea puede convertirse en un cuello de botella significativo. Esto puede provocar tiempos de ejecución de playbooks dolorosamente lentos. Afortunadamente, Ansible ofrece dos características potentes, ControlPersist y Pipelining, que pueden mejorar drásticamente el rendimiento al optimizar cómo Ansible se comunica con los nodos gestionados.

Esta guía le mostrará cómo comprender e implementar ControlPersist y Pipelining. Al aprovechar estas técnicas, puede reducir significativamente los tiempos de ejecución, haciendo que su automatización con Ansible sea más eficiente y receptiva, especialmente en entornos con cientos o miles de hosts. Dominar estas optimizaciones es crucial para cualquiera que busque escalar sus despliegues de Ansible de manera efectiva.

Comprensión del comportamiento de conexión predeterminado de Ansible

Por defecto, Ansible establece una nueva conexión SSH a cada host gestionado por cada tarea ejecutada dentro de un playbook. Para cada conexión, realiza varios pasos:

  1. Iniciar conexión SSH: Se establece una nueva conexión SSH.
  2. Transferir módulos: Ansible transfiere los módulos de Python necesarios (u otros archivos relevantes) al host remoto.
  3. Ejecutar módulo: El módulo se ejecuta en el host remoto.
  4. Recibir salida: Ansible recupera los resultados de la ejecución.
  5. Cerrar conexión: La conexión SSH se termina.

Si bien este enfoque es robusto y garantiza un estado limpio para cada tarea, el proceso repetido de conexión y transferencia de módulos consume una cantidad considerable de tiempo, particularmente cuando se trata de numerosas tareas o un gran inventario.

Optimización de conexiones con ControlPersist

ControlPersist es una característica de SSH que le permite mantener abiertas las conexiones SSH durante un período especificado, incluso después de que haya finalizado el comando inicial. Esto significa que las tareas subsiguientes de Ansible dirigidas al mismo host pueden reutilizar la conexión existente y abierta en lugar de establecer una nueva. Esto reduce significativamente la latencia asociada con la configuración de sesiones SSH.

Cómo funciona ControlPersist

Cuando está habilitado, ControlPersist indica al cliente SSH que mantenga una conexión maestra de control. Las conexiones SSH subsiguientes al mismo host utilizando las mismas credenciales y opciones pueden multiplexarse a través de esta conexión maestra. Ansible aprovecha esto configurando las opciones ControlPath y ControlPersist en su configuración SSH.

Habilitación de ControlPersist en Ansible

Puede habilitar ControlPersist de varias maneras:

  1. A través de ansible.cfg (Recomendado para configuraciones globales o específicas del proyecto):
    Edite o cree su archivo ansible.cfg (ubicado en su directorio de proyecto de Ansible, ~/.ansible.cfg, o /etc/ansible/ansible.cfg). Agregue la siguiente configuración a la sección [ssh_connection]:

    ini [ssh_connection] ssh_args = -o ControlMaster=auto -o ControlPersist=600 -o ControlPath=~/.ssh/ansible_control_%r@%h:%p

    • -o ControlMaster=auto: Habilita el uso compartido de conexiones. Si existe una conexión maestra, la usa; de lo contrario, crea una.
    • -o ControlPersist=600: Mantiene la conexión de control abierta durante 600 segundos (10 minutos). Ajuste este valor según su flujo de trabajo y políticas de seguridad. Una duración más larga significa más reutilización potencial, pero también más recursos mantenidos abiertos.
    • -o ControlPath=~/.ssh/ansible_control_%r@%h:%p: Define la ruta para el socket de control. %r es el nombre de usuario remoto, %h es el nombre del host y %p es el puerto. Esto asegura sockets únicos para diferentes conexiones.
  2. A través de la variable de entorno:
    Puede configurar los argumentos SSH directamente usando una variable de entorno:

    bash export ANSIBLE_SSH_ARGS='-o ControlMaster=auto -o ControlPersist=600 -o ControlPath=~/.ssh/ansible_control_%r@%h:%p' ansible-playbook your_playbook.yml

  3. A través del Playbook (menos común para esta configuración):
    Si bien es posible, generalmente no se recomienda establecer opciones SSH persistentes dentro del playbook en sí, ya que es una configuración a nivel de conexión. Sin embargo, a modo de exhaustividad, podría usar ansible.builtin.set_fact o similar para influir en ella, pero se prefiere ansible.cfg.

Consideraciones para ControlPersist

  • Seguridad: Asegúrese de que el ControlPath esté protegido para que solo los usuarios autorizados puedan acceder a los sockets de control. La ruta predeterminada en el ejemplo suele ser segura para las configuraciones a nivel de usuario.
  • Uso de recursos: Mantener las conexiones abiertas consume recursos tanto en el nodo de control como en los nodos gestionados. Supervise el uso de recursos si tiene un número muy grande de conexiones persistentes.
  • Restablecimiento de la conexión: Si un dispositivo de red intermedio o el servidor SSH remoto impone tiempos de espera de conexión más cortos que ControlPersist, la conexión aún podría caer. ControlPersist funciona mejor con entornos de red estables.

Agilización de la ejecución de módulos con Pipelining

Pipelining es otra potente optimización de Ansible que reduce aún más la sobrecarga de la ejecución de tareas. En lugar de transferir módulos al host remoto, ejecutarlos y luego recuperar la salida, el pipelining transmite comandos directamente a través de la conexión SSH. Esto significa que Ansible no necesita colocar módulos en el sistema de archivos remoto ni crear archivos temporales para la salida.

Cómo funciona Pipelining

Cuando el pipelining está habilitado, Ansible ejecuta módulos directamente a través de ssh en el host remoto. La salida estándar y el error estándar del módulo se canalizan de vuelta a Ansible a través de la misma conexión SSH. Esto elimina la necesidad de que Ansible escriba archivos en el sistema de archivos remoto (como /usr/bin/ansible_module_name o archivos temporales) y luego los ejecute. Esto es particularmente efectivo para módulos que no requieren escalada de privilegios o una interacción significativa con el sistema de archivos remoto.

Habilitación de Pipelining en Ansible

El pipelining se habilita a través del archivo ansible.cfg o variables de entorno.

  1. A través de ansible.cfg:
    Agregue o modifique la sección [ssh_connection]:

    ini [ssh_connection] pipelining = True

  2. A través de la variable de entorno:
    bash export ANSIBLE_PIPELINING=True ansible-playbook your_playbook.yml

Consideraciones para Pipelining

  • Escalado de privilegios: El pipelining funciona mejor con módulos que no requieren escalado de privilegios (por ejemplo, usando become: yes o sudo). Cuando se usa become, Ansible normalmente necesita copiar archivos al sistema remoto. Si usa become con frecuencia, el pipelining podría no ofrecer tantos beneficios o incluso causar problemas con ciertos tipos de módulos.
  • Compatibilidad de módulos: La mayoría de los módulos integrados de Ansible funcionan bien con el pipelining. Sin embargo, los módulos personalizados o aquellos que dependen en gran medida de las operaciones del sistema de archivos remoto pueden comportarse de manera diferente. Pruebe a fondo.
  • Estabilidad de la conexión: Una conexión SSH estable es crucial para que el pipelining funcione correctamente.
  • Configuración SSH requiretty: El pipelining es incompatible con la opción SSH requiretty en el servidor remoto. Si su servidor SSH tiene Defaults requiretty en /etc/sudoers, es posible que deba deshabilitarla o usar !requiretty para el usuario específico con el que se conecta Ansible.

Combinación de ControlPersist y Pipelining para el máximo rendimiento

Para obtener las ganancias de rendimiento más significativas, es muy recomendable habilitar tanto ControlPersist como Pipelining. Esta combinación aborda las dos sobrecargas principales: el establecimiento de conexiones y la ejecución de módulos.

Así es como podría verse su ansible.cfg con ambos habilitados:

[ssh_connection]
ssh_args = -o ControlMaster=auto -o ControlPersist=600 -o ControlPath=~/.ssh/ansible_control_%r@%h:%p
pipelining = True

Cuando ambos están activos:

  1. Ansible inicia una conexión SSH y establece un ControlMaster si no existe (ControlPersist).
  2. Para tareas posteriores, se reutiliza la conexión abierta existente.
  3. Los módulos se ejecutan directamente sobre el flujo sin copiarse al sistema de archivos (Pipelining).

Esta sinergia reduce drásticamente el tiempo que Ansible dedica a comunicarse con cada nodo gestionado, lo que resulta en ejecuciones de playbooks mucho más rápidas.

Escenario de ejemplo práctico

Imaginemos un playbook que necesita ejecutar 10 tareas simples en 100 hosts.

Sin optimizaciones:
Cada tarea requiere una nueva conexión SSH, transferencia de módulo, ejecución y cierre de conexión. Esto equivale a 100 hosts * 10 tareas * (tiempo_conexión + tiempo_transferencia_módulo). Si tiempo_conexión es de 0.5 segundos y tiempo_transferencia_módulo es de 0.2 segundos, eso son 100 * 10 * 0.7 = 700 segundos de sobrecarga solo por comunicación y transferencias, sin incluir la ejecución real del módulo.

Con ControlPersist y Pipelining habilitados:

  1. La primera tarea en cada host establece la conexión inicial y configura el ControlMaster.
  2. Las 9 tareas posteriores en ese host reutilizan la conexión abierta y transmiten la ejecución del módulo.

La sobrecarga por host se acerca más a tiempo_conexión + (9 * sobrecarga_mínima_de_streaming). El tiempo total se reduce significativamente, y la mayor parte del tiempo de ejecución del playbook se dedica al trabajo real que realizan los módulos, en lugar de a la mecánica de comunicación.

Cuándo ser cauteloso

Aunque estas optimizaciones son potentes, no son universalmente aplicables sin consideración:

  • Entornos con firewalls estrictos o restricciones de red: Las caídas frecuentes de conexión o la inspección con estado podrían interferir con ControlPersist.
  • Entornos de alta seguridad: Las conexiones SSH de mayor duración podrían ser una preocupación de seguridad en entornos altamente regulados. Ajuste la duración de ControlPersist en consecuencia.
  • Playbooks que dependen mucho de become y operaciones de archivos: La efectividad del pipelining se reduce cuando become se usa constantemente, ya que a menudo requiere operaciones de archivos. Pruebe el impacto en el rendimiento.

Conclusión

Optimizar la comunicación de Ansible con los nodos gestionados es un paso clave hacia una automatización eficiente y escalable. Al comprender e implementar ControlPersist y Pipelining, puede reducir drásticamente los tiempos de ejecución de los playbooks. ControlPersist mantiene vivas las conexiones SSH, reduciendo la sobrecarga de conexión, mientras que Pipelining transmite la ejecución de módulos, eliminando la necesidad de transferencias de archivos. Combinar estas dos configuraciones, principalmente a través de ansible.cfg, es una práctica recomendada para cualquier usuario de Ansible que administre un número significativo de hosts o ejecute playbooks complejos. Pruebe siempre estas configuraciones en su entorno específico para ajustar el rendimiento y garantizar la compatibilidad.