Introducción
Courtyard Sessions tiene un sitio operativo en dos servidores. El nuevo programa está listo, pero actualizar ambos nodos a la vez podría dejar a los visitantes sin sitio disponible. Usa Ansible para inspeccionar el estado y publicar el paquete nuevo en un servidor cada vez.
Necesitas navegación básica por terminal y práctica con un inventario pequeño de Ansible, variables y tareas file/copy. La puerta de enlace, el acceso SSH y los paquetes están preparados. Este laboratorio explica la ubicación de ejecución, la delegación, los lotes, los enlaces de versión y las comprobaciones HTTP completas antes de utilizarlos. La duración es una estimación del autor que incluye lectura y correcciones habituales.
Comprueba dónde se ejecuta cada tarea
En este paso, crearás un playbook de inspección de solo lectura que muestra la versión activa de cada servidor y el grupo de enrutamiento realmente activo.
Courtyard Sessions ya tiene un sitio operativo para visitantes. Abre la pestaña Website. Lee Good things, around the corner. y pulsa The program. La página se desplaza hasta dos sesiones, empezando por Coffee in the courtyard. Pulsa Download the program (CSV) y abre el archivo descargado: la cabecera es time,session,place, seguida de las dos sesiones mostradas. Un CSV es una tabla de texto con campos separados por comas. Esta descarga real debe seguir disponible durante la actualización.
La puerta de enlace distribuye solicitudes HTTP breves entre dos servidores. Retirar un servidor del grupo activo impide que reciba nuevas solicitudes de la puerta de enlace; añadirlo lo devuelve a la rotación. Esta pequeña puerta de enlace preparada no drena conexiones de larga duración ni simula una plataforma completa de publicación en la nube. Ambos servidores son contenedores gestionados mediante SSH que comparten el núcleo de esta VM de formación. El controlador es la máquina que ejecuta Ansible y la puerta de enlace.
Cambia a la pestaña Controller. Empieza en /home/labex/project. pwd muestra el directorio actual y cat imprime un archivo:
pwd
cat inventory.yml
cat group_vars/all.yml
El inventario contiene datos estructurados compatibles con YAML. Su grupo website contiene web1 y web2, cada uno con su dirección real ansible_host y los datos SSH preparados. El grupo control contiene controller con conexión local. Usa inventory.yml, seleccionado por el ansible.cfg del proyecto; el inventory.ini inicial de la imagen no es el inventario del curso.
Las variables de grupo proporcionan backend_port (8090), pool_api exclusivo del controlador, el release_root permitido, el package_root local y los identificadores de versión. baseline_release es courtyard-preview; approved_release es courtyard-weekend. Son nombres de directorio, no versiones de Ansible ni del software. Un puerto HTTP identifica un servicio que escucha en una dirección. /identity devuelve JSON, texto estructurado que identifica la versión realmente ejecutada. /pool devuelve la lista actual de nodos activos del controlador.
Si un comando muestra “No such file or directory”, comprueba la escritura con ls y vuelve con cd /home/labex/project si hace falta. Puedes repetir una lectura con seguridad. Conserva todos los archivos de los paquetes, los datos de conexión, los archivos de la versión original y las notas privadas del organizador.
Por defecto, Ansible ejecuta una tarea mediante SSH en cada servidor seleccionado. Allí, 127.0.0.1 significa ese propio servidor. delegate_to: controller ejecuta esa tarea concreta en el controlador, cuyo propio 127.0.0.1 aloja la API del grupo. La delegación no cambia inventory_hostname: sigue nombrando el servidor gestionado en ese momento. Así una solicitud del controlador puede referirse al servidor correcto.
Crea inspect.yml. cat > filename escribe un archivo y sustituye otro existente con ese nombre. <<'YAML' inicia un here-document: pega hasta el YAML final en una línea independiente. El delimitador entre comillas mantiene literal el texto pegado; Ansible procesa las expresiones cuando ejecuta el playbook. La sangría usa espacios. {{ variable }} inserta una variable de Ansible. gather_facts: false omite la recopilación de datos de máquina ajenos al ejercicio.
El módulo uri envía una solicitud HTTP real; su método predeterminado GET lee un recurso. register guarda el resultado real con un nombre. En respuestas JSON, .json contiene los campos analizados. debug imprime esas observaciones guardadas; no crea la versión ni el estado del grupo.
cat > inspect.yml <<'YAML'
- name: Inspect the running website without changing it
hosts: website
gather_facts: false
tasks:
- name: Read this backend on its own loopback address
ansible.builtin.uri:
url: "http://127.0.0.1:{{ backend_port }}/identity"
register: backend
- name: Read the pool on the controller
ansible.builtin.uri:
url: "{{ pool_api }}/pool"
delegate_to: controller
register: pool
- name: Show the actual release and active pool
ansible.builtin.debug:
msg:
node: "{{ inventory_hostname }}"
release: "{{ backend.json.release }}"
active: "{{ pool.json.active }}"
YAML
Ejecuta el playbook. ansible-playbook lee las tareas y las aplica al inventario:
ansible-playbook inspect.yml
Cada servidor debe mostrar release: courtyard-preview, y active debe incluir web1 y web2. El formato y las direcciones pueden variar. Observa que el primer uri se ejecuta en el servidor, mientras que la lectura del grupo muestra una delegación como web1 -> controller. Ambas tareas son de solo lectura.
Si la sangría YAML es incorrecta, vuelve a copiar el bloque completo para corregir el archivo y reinténtalo. Este playbook nunca debe copiar archivos ni cambiar el grupo. Ya tienes una herramienta útil para volver a observar el estado después de publicar.
Publica en un servidor cada vez
En este paso, entregarás el paquete web aprobado por SSH, validarás su contenido real para visitantes y devolverás cada servidor al servicio antes de iniciar el siguiente.
Permanece en la pestaña Controller, en /home/labex/project. Lista los paquetes y lee el programa aprobado. ls enumera las entradas del directorio:
ls packages
cat packages/courtyard-weekend/schedule.csv
El programa aprobado contiene tres sesiones: Bread and stories, Acoustic afternoon y Print a postcard. Una página inicial correcta no basta: los visitantes necesitan la descarga completa correspondiente. El paquete courtyard-incomplete se reserva para el siguiente laboratorio; aquí selecciona courtyard-weekend, como ya hace la variable release_id.
El playbook procesa un lote de un host mediante serial: 1. Dentro del lote retira el nodo del grupo, copia el paquete, cambia el enlace de versión activa, comprueba ambos recursos y reincorpora el nodo. Solo entonces comienza el siguiente lote. order: sorted hace que la demostración empiece con web1. any_errors_fatal: true propaga explícitamente un fallo no controlado para detener el play. En estos lotes de un host, el fallo de ese host ya hace fallar todo el lote. La opción no deshace las tareas completadas. El siguiente laboratorio añade recuperación.
La API del grupo acepta un HTTP POST a /pool con un cuerpo JSON: node nombra el nodo gestionado y enabled es el booleano false para retirarlo o true para añadirlo. body_format: json serializa correctamente el cuerpo. Las tareas del grupo se ejecutan en el controlador; las de archivos, en el servidor SSH seleccionado.
file con state: directory crea un directorio; el modo '0755' permite escribir al propietario y leer o atravesar el directorio a todos. copy envía el paquete seleccionado del controlador a ese servidor. La / final de src copia su contenido, con modo '0644' para archivos legibles. file con state: link crea o actualiza un enlace simbólico: current apunta a un directorio de versión. El servidor HTTP preparado sirve archivos reales a través del enlace en cada solicitud. Cambiarlo activa el sitio sin reiniciar el servidor y mantiene intacto el directorio original.
En las sondas HTTP ejecutadas en el controlador, hostvars[inventory_hostname].ansible_host obtiene explícitamente la dirección del servidor gestionado. Durante la delegación, una variable de conexión sin esa referencia puede corresponder al host delegado. return_content: true guarda el cuerpo real como .content.
assert exige que su expresión that sea verdadera. lookup('file', ...) lee el archivo esperado del paquete en el controlador; ~ une cadenas de ruta. rstrip=False conserva los saltos de línea finales para comparar el cuerpo completo, no un fragmento recortado. La página completa del candidato y el CSV aprobado completo deben coincidir antes de reincorporar el nodo. Un 404 significa que el servidor respondió pero falta ese recurso; un error de conexión significa que el servicio no pudo alcanzarse. Ninguno indica una versión saludable.
Escribe el despliegue completo. El here-document usa el mismo método que la herramienta de inspección:
cat > rollout.yml <<'YAML'
- name: Release one website backend at a time
hosts: website
order: sorted
gather_facts: false
serial: 1
any_errors_fatal: true
tasks:
- name: Drain this backend from the pool
ansible.builtin.uri:
url: "{{ pool_api }}/pool"
method: POST
body_format: json
body:
node: "{{ inventory_hostname }}"
enabled: false
delegate_to: controller
- name: Create this release directory
ansible.builtin.file:
path: "{{ release_root }}/releases/{{ release_id }}"
state: directory
mode: '0755'
- name: Copy the selected package over SSH
ansible.builtin.copy:
src: "{{ package_root }}/{{ release_id }}/"
dest: "{{ release_root }}/releases/{{ release_id }}/"
mode: '0644'
- name: Activate the selected release
ansible.builtin.file:
src: "{{ release_root }}/releases/{{ release_id }}"
dest: "{{ release_root }}/current"
state: link
- name: Read the real candidate homepage
ansible.builtin.uri:
url: "http://{{ hostvars[inventory_hostname].ansible_host }}:{{ backend_port }}/"
return_content: true
delegate_to: controller
register: homepage
- name: Require the complete candidate homepage
ansible.builtin.assert:
that: homepage.content == lookup('file', package_root ~ '/' ~ release_id ~ '/index.html', rstrip=False)
- name: Read the real candidate download
ansible.builtin.uri:
url: "http://{{ hostvars[inventory_hostname].ansible_host }}:{{ backend_port }}/schedule.csv"
return_content: true
delegate_to: controller
register: download
- name: Require the complete approved program
ansible.builtin.assert:
that: download.content == lookup('file', package_root ~ '/' ~ approved_release ~ '/schedule.csv', rstrip=False)
- name: Rejoin only after both business checks
ansible.builtin.uri:
url: "{{ pool_api }}/pool"
method: POST
body_format: json
body:
node: "{{ inventory_hostname }}"
enabled: true
delegate_to: controller
YAML
Comprueba primero el YAML y la estructura de tareas sin desplegar. --syntax-check valida la sintaxis, pero no demuestra el resultado funcional:
ansible-playbook rollout.yml --syntax-check
Si aparecen errores de escritura o sangría, copia de nuevo el archivo completo y repite la comprobación. Después ejecuta el despliegue real:
ansible-playbook rollout.yml
Las tareas de web1 deben terminar antes de las de web2. Ambos hosts deben finalizar con failed=0 y unreachable=0. Las solicitudes operativas de retirada o incorporación pueden mostrar ok; su éxito HTTP y efecto real importan más que el contador changed del resumen. Si un error de edición interrumpe la ejecución, corrige el archivo completo y repítela con el mismo paquete aprobado. Repetir el flujo vuelve a retirar, comprobar y reincorporar; no es un despliegue sin operaciones.
Inspecciona el estado con tu herramienta original:
ansible-playbook inspect.yml
Los dos nodos deben indicar courtyard-weekend y estar activos en el grupo. Cambia a la pestaña Website y recarga. El título debe ser A little room for a good afternoon. Pulsa The program, comprueba las tres sesiones, descarga otra vez el CSV y abre el archivo nuevo para confirmar las tres filas completas. Si ya había una descarga, el navegador puede añadir un número al nombre. Plan a visit debe seguir llevando a la información de acceso sin escalones por la entrada del jardín.
El programa actualizado contiene las tres sesiones aprobadas; la descarga real del CSV está junto a la lista.

Esto demuestra una actualización funcional de dos nodos en el entorno preparado de solicitudes breves. No establece una garantía de publicación sin interrupciones para cualquier tráfico o aplicación de producción.
Resumen
Has creado una herramienta de inspección de solo lectura y utilizado un despliegue secuencial de Ansible para entregar un sitio real y la descarga completa de su programa. Los cambios delegados del grupo y las comprobaciones reales vinculan cada decisión de publicación con el servidor gestionado correspondiente.



