Introducción
Que un paquete esté instalado, que exista un archivo de configuración y que un servicio responda son resultados distintos. Administrarás cada uno explícitamente: instalarás y eliminarás una utilidad, configurarás nginx, declararás su estado de ejecución y recargarás la configuración modificada mediante un handler. Las respuestas HTTP reales de ambos nodos administrados demostrarán que el servicio funciona.
Declarar estados de paquetes instalados y ausentes
En este paso, instalarás una pequeña utilidad, la inspeccionarás y la eliminarás mediante una declaración reutilizable de paquetes.
El módulo apt administra paquetes de Ubuntu en el host administrado. Su state: present solicita la instalación y state: absent solicita la eliminación. Este entorno incluye listas de paquetes preparadas y descargas en caché, así que mantén update_cache: false; actualizar las listas o solicitar las versiones más recientes añadiría dependencias de red innecesarias. Las políticas de actualización de producción pueden ser distintas.
Entra en el proyecto del controlador:
cd /home/labex/project
Crea un playbook cuya variable seleccione el estado deseado del paquete tree. Las operaciones de paquetes requieren become en los destinos. install_recommends: false evita los paquetes recomendados opcionales.
cat > packages.yml <<'YAML'
- name: Declare a utility package state
hosts: all
gather_facts: false
become: true
vars:
utility_state: present
tasks:
- name: Converge the tree package
ansible.builtin.apt:
name: tree
state: "{{ utility_state }}"
update_cache: false
install_recommends: false
YAML
Instala la utilidad:
ansible-playbook packages.yml
El comando tree muestra árboles de directorios; aquí su opción de versión demuestra que el ejecutable está realmente instalado en cada nodo administrado:
ansible all -m ansible.builtin.command -a 'tree --version'
Cada destino debería devolver una versión de tree. Repite el playbook; los paquetes presentes no deberían necesitar otra instalación:
ansible-playbook packages.yml
Ahora solicita la ausencia con una variable extra en lugar de editar la tarea reutilizable:
ansible-playbook packages.yml -e utility_state=absent
Repite el mismo estado deseado de ausencia. Ambas filas del resumen deberían mostrar ahora changed=0, failed=0 y unreachable=0:
ansible-playbook packages.yml -e utility_state=absent
El estado del paquete es una declaración sobre la instalación, no una prueba de que un servicio esté en ejecución o respondiendo. Deja tree ausente mientras el siguiente paso despliega nginx.
Configurar e iniciar un servicio web real
En este paso, instalarás nginx, desplegarás una configuración completa validada y mantendrás explícitamente su servicio en ejecución.
Los dos nodos administrados son contenedores con destinos SSH y sistemas de archivos separados. No ejecutan systemd. El módulo service usa su gestor de servicios disponible; no ejecutes systemctl en estos destinos. Administraremos el estado actual de ejecución en lugar de prometer una política de arranque de systemd.
Crea una página estática en el controlador. Termina con un salto de línea para que sus bytes administrados exactos sean predecibles:
printf 'Ansible service ready\n' > page.txt
Escribe una configuración completa de nginx. events y http son contextos de nivel superior de nginx, server define un sitio web, listen elige el puerto 8080, root selecciona su directorio de documentos e index selecciona la página para las solicitudes /. Son ajustes de nginx, no YAML de Ansible.
cat > nginx-course.conf <<'NGINX'
events {}
http {
server {
listen 8080;
root /var/www/ansible-site;
index index.html;
}
}
NGINX
Crea el playbook de despliegue. La tarea apt usa policy_rc_d: 101 para impedir que el instalador de paquetes inicie nginx implícitamente; la tarea service posterior declara explícitamente el estado en ejecución. El validate de la tarea copy ejecuta la prueba de configuración de nginx sobre un candidato temporal (%s) antes de sustituir el destino.
Un handler es una acción con nombre que figura bajo handlers. Una tarea de configuración con cambios notifica a Reload nginx, que se ejecuta una vez al final del play. Si no hay cambio de configuración, no hay notificación. La tarea service normal usa started, que mantiene en ejecución un servicio ya iniciado sin un reinicio incondicional.
cat > web.yml <<'YAML'
- name: Deploy a working web service
hosts: all
gather_facts: false
become: true
tasks:
- name: Install nginx without refreshing the prepared package lists
ansible.builtin.apt:
name: nginx
state: present
update_cache: false
install_recommends: false
policy_rc_d: 101
- name: Prepare the site directory
ansible.builtin.file:
path: /var/www/ansible-site
state: directory
owner: root
group: root
mode: "0755"
- name: Deploy the static page
ansible.builtin.copy:
src: /home/labex/project/page.txt
dest: /var/www/ansible-site/index.html
owner: root
group: root
mode: "0644"
- name: Validate and deploy nginx configuration
ansible.builtin.copy:
src: /home/labex/project/nginx-course.conf
dest: /etc/nginx/nginx.conf
owner: root
group: root
mode: "0644"
validate: /usr/sbin/nginx -t -c %s
notify: Reload nginx
- name: Keep nginx running
ansible.builtin.service:
name: nginx
state: started
handlers:
- name: Reload nginx
ansible.builtin.service:
name: nginx
state: reloaded
YAML
Comprueba la sintaxis y después aplica el despliegue:
ansible-playbook web.yml --syntax-check
ansible-playbook web.yml
Ambos nodos deberían instalar nginx, recibir los archivos e iniciarse correctamente. Un primer cambio de configuración también programa el handler de recarga. Comprobar únicamente la versión de un paquete no demostraría nada de ese comportamiento del servicio.
curl es un cliente HTTP. Su opción --fail trata un estado HTTP no satisfactorio como un fallo del comando; --silent elimina la salida de progreso y --show-error conserva los detalles del fallo. Ejecútalo en cada host administrado contra la propia interfaz de bucle local de ese host:
ansible all -m ansible.builtin.command -a 'curl --fail --silent --show-error http://127.0.0.1:8080/'
Cada resultado debería contener Ansible service ready. El controlador y cada destino tienen interfaces de bucle local separadas; este comando comprueba ambos servicios de destino en lugar del controlador.
Aplicar un cambio de configuración mediante un handler
En este paso, cambiarás un ajuste activo de nginx, observarás el handler y confirmarás el ajuste mediante una respuesta HTTP.
La directiva server_tokens de nginx controla si las cabeceras de respuesta muestran la versión de nginx. Añade server_tokens off dentro de http sustituyendo la configuración del controlador por esta versión completa:
cat > nginx-course.conf <<'NGINX'
events {}
http {
server_tokens off;
server {
listen 8080;
root /var/www/ansible-site;
index index.html;
}
}
NGINX
Aplica el mismo playbook:
ansible-playbook web.yml
La copia de configuración debería informar changed y notificar a Reload nginx en ambos hosts. El handler recarga el servicio en ejecución después de que la nueva configuración supere la validación. Su ejecución hace efectiva la configuración; limitarse a copiar un archivo no demuestra qué ha cargado el proceso.
-I de curl solicita cabeceras HTTP. Inspecciona la respuesta real del servicio en ambos hosts:
ansible all -m ansible.builtin.command -a 'curl --fail --silent --show-error -I http://127.0.0.1:8080/'
Ambas respuestas deberían tener un estado HTTP satisfactorio y una cabecera Server con nginx sin un sufijo de versión. Otros campos de las cabeceras, como las fechas, varían.
Repite el playbook completo:
ansible-playbook web.yml
Ambos hosts deberían informar changed=0 sin tareas fallidas ni inaccesibles, y no debería programarse ningún handler de recarga. La página estática sigue disponible, tree sigue ausente y nginx sigue instalado y en ejecución.
Resumen
Has declarado la presencia y ausencia de paquetes, separado la instalación del estado de ejecución del servicio y desplegado una configuración completa de nginx con validación del candidato. Una configuración modificada notificó a un handler de recarga, las respuestas HTTP reales demostraron el comportamiento activo y una repetición sin cambios evitó cambios o recargas adicionales.



