{"id":2395,"date":"2026-04-24T18:37:53","date_gmt":"2026-04-24T18:37:53","guid":{"rendered":"https:\/\/dsantana.uas.edu.mx\/?p=2395"},"modified":"2026-04-24T19:17:49","modified_gmt":"2026-04-24T19:17:49","slug":"practica-integracion-de-apache2-en-el-cluster-de-alta-disponibilidad-pacemaker-corosync","status":"publish","type":"post","link":"https:\/\/dsantana.uas.edu.mx\/index.php\/2026\/04\/24\/practica-integracion-de-apache2-en-el-cluster-de-alta-disponibilidad-pacemaker-corosync\/","title":{"rendered":"Practica: Integraci\u00f3n de Apache2 en el Cl\u00faster de Alta Disponibilidad (Pacemaker + Corosync)"},"content":{"rendered":"\n<figure class=\"wp-block-image aligncenter size-full\"><img fetchpriority=\"high\" decoding=\"async\" width=\"1024\" height=\"1024\" src=\"https:\/\/dsantana.uas.edu.mx\/wp-content\/uploads\/2026\/04\/Integracion-de-Apache2-en-un-Cluster-de-Alta-Dispo.png\" alt=\"\" class=\"wp-image-2405\" srcset=\"https:\/\/dsantana.uas.edu.mx\/wp-content\/uploads\/2026\/04\/Integracion-de-Apache2-en-un-Cluster-de-Alta-Dispo.png 1024w, https:\/\/dsantana.uas.edu.mx\/wp-content\/uploads\/2026\/04\/Integracion-de-Apache2-en-un-Cluster-de-Alta-Dispo-300x300.png 300w, https:\/\/dsantana.uas.edu.mx\/wp-content\/uploads\/2026\/04\/Integracion-de-Apache2-en-un-Cluster-de-Alta-Dispo-150x150.png 150w, https:\/\/dsantana.uas.edu.mx\/wp-content\/uploads\/2026\/04\/Integracion-de-Apache2-en-un-Cluster-de-Alta-Dispo-768x768.png 768w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p><strong>Objetivo:<\/strong> Extender el cl\u00faster activo\/pasivo previamente configurado para que el servicio <strong>Apache2<\/strong> sea gestionado por Pacemaker, de modo que <strong>solo est\u00e9 activo en el nodo que tiene la IP virtual (VIP)<\/strong>, que <strong>migre autom\u00e1ticamente junto con la VIP durante un <em>failover<\/em><\/strong>, y que el usuario final no perciba la ca\u00edda.<\/p>\n\n\n\n<p>La siguiente gu\u00eda asume que ya se cuenta con un cl\u00faster Pacemaker+Corosync operativo (seg\u00fan la pr\u00e1ctica anterior) y que ya existe un recurso de direcci\u00f3n <strong>IP Virtual<\/strong> actualmente <strong>activo en nodo-a<\/strong>. Apache a\u00fan no est\u00e1 gestionado por el cl\u00faster, por lo que ser\u00e1 a\u00f1adido en esta pr\u00e1ctica. El <strong>DocumentRoot<\/strong> del servidor web es <code>\/var\/www\/html<\/code> en ambos nodos. En este entorno de laboratorio no se usa DRBD para la replicaci\u00f3n de archivos y <strong>STONITH est\u00e1 deshabilitado<\/strong>.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" width=\"1024\" height=\"259\" src=\"https:\/\/dsantana.uas.edu.mx\/wp-content\/uploads\/2026\/04\/image-5-1024x259.png\" alt=\"\" class=\"wp-image-2396\" srcset=\"https:\/\/dsantana.uas.edu.mx\/wp-content\/uploads\/2026\/04\/image-5-1024x259.png 1024w, https:\/\/dsantana.uas.edu.mx\/wp-content\/uploads\/2026\/04\/image-5-300x76.png 300w, https:\/\/dsantana.uas.edu.mx\/wp-content\/uploads\/2026\/04\/image-5-768x194.png 768w, https:\/\/dsantana.uas.edu.mx\/wp-content\/uploads\/2026\/04\/image-5-1536x388.png 1536w, https:\/\/dsantana.uas.edu.mx\/wp-content\/uploads\/2026\/04\/image-5-2048x517.png 2048w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p><strong>Contexto confirmado del laboratorio:<\/strong><\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th><strong>Elemento<\/strong><\/th><th><strong>Valor<\/strong><\/th><\/tr><tr><th><strong>Cl\u00faster<\/strong><\/th><td>Pacemaker + Corosync, ya creado y operativo<\/td><\/tr><tr><th><strong>Recurso IP Virtual<\/strong><\/th><td><code>IP-Virtual<\/code> (ocf:heartbeat:IPaddr2), ya funcional en <strong>nodo-a<\/strong><\/td><\/tr><tr><th><strong>DRBD<\/strong><\/th><td><strong>No se usa<\/strong> en esta pr\u00e1ctica<\/td><\/tr><tr><th><strong>STONITH<\/strong><\/th><td>Deshabilitado (<code>stonith-enabled=false<\/code>) \u2014 entorno de laboratorio<\/td><\/tr><tr><th><strong>DocumentRoot<\/strong><\/th><td><code>\/var\/www\/html<\/code><\/td><\/tr><tr><th><strong>Modo<\/strong><\/th><td>Activo\/pasivo (single-primary)<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" width=\"828\" height=\"1024\" src=\"https:\/\/dsantana.uas.edu.mx\/wp-content\/uploads\/2026\/04\/image-6-828x1024.png\" alt=\"\" class=\"wp-image-2397\" srcset=\"https:\/\/dsantana.uas.edu.mx\/wp-content\/uploads\/2026\/04\/image-6-828x1024.png 828w, https:\/\/dsantana.uas.edu.mx\/wp-content\/uploads\/2026\/04\/image-6-242x300.png 242w, https:\/\/dsantana.uas.edu.mx\/wp-content\/uploads\/2026\/04\/image-6-768x950.png 768w, https:\/\/dsantana.uas.edu.mx\/wp-content\/uploads\/2026\/04\/image-6-1241x1536.png 1241w, https:\/\/dsantana.uas.edu.mx\/wp-content\/uploads\/2026\/04\/image-6-1655x2048.png 1655w, https:\/\/dsantana.uas.edu.mx\/wp-content\/uploads\/2026\/04\/image-6.png 1833w\" sizes=\"(max-width: 828px) 100vw, 828px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Paso 1: Instalaci\u00f3n de Apache en ambos nodos<\/h2>\n\n\n\n<p><strong>Comando (en cada nodo):<\/strong><\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>apt install -y apache2<br><\/p>\n\n\n\n<p><strong>Qu\u00e9 se hace:<\/strong> Se instala el servidor web Apache2 en los dos nodos del cl\u00faster.<\/p>\n\n\n\n<p><strong>Por qu\u00e9 se hace:<\/strong> Apache debe estar instalado en <strong>todos los nodos del cl\u00faster<\/strong> para que Pacemaker pueda iniciarlo en cualquiera de ellos si fuera necesario. Si Apache solo estuviera en un nodo, un failover al otro ser\u00eda imposible: Pacemaker intentar\u00eda ejecutar un binario que no existe. Aunque solo un nodo lo ejecutar\u00e1 en cada momento (modelo activo\/pasivo), <strong>ambos deben tener el software disponible<\/strong>.<\/p>\n\n\n\n<p><strong>Qu\u00e9 ocurre internamente:<\/strong> La instalaci\u00f3n deposita los binarios (<code>\/usr\/sbin\/apache2<\/code>), los archivos de configuraci\u00f3n (<code>\/etc\/apache2\/<\/code>), los m\u00f3dulos disponibles y los scripts de servicio. En Debian, el archivo de configuraci\u00f3n principal es <code>\/etc\/apache2\/apache2.conf<\/code>. A\u00fan no se modifica nada en la pila de red ni en el cl\u00faster; solo se prepara la <strong>capa de aplicaci\u00f3n<\/strong> de cada servidor.<\/p>\n\n\n\n<p><strong>Verificaci\u00f3n:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>apache2 -v<\/code> \u2192 muestra la versi\u00f3n instalada.<\/li>\n\n\n\n<li><code>dpkg -l | grep apache2<\/code> \u2192 confirma que los paquetes est\u00e1n instalados.<\/li>\n\n\n\n<li>El directorio <code>\/var\/www\/html<\/code> debe existir (creado por la instalaci\u00f3n), conteniendo la p\u00e1gina predeterminada de Apache.<\/li>\n<\/ul>\n\n\n\n<p><strong>Errores comunes:<\/strong><\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Problema<\/th><th>S\u00edntoma<\/th><th>Soluci\u00f3n<\/th><\/tr><tr><td>Repositorios desactualizados<\/td><td><code>apt<\/code> no localiza el paquete <code>apache2<\/code><\/td><td>Ejecutar <code>apt update<\/code> antes de la instalaci\u00f3n<\/td><\/tr><tr><td>Permisos insuficientes<\/td><td>Error de permisos al instalar<\/td><td>Ejecutar como <code>root<\/code> o con <code>sudo<\/code><\/td><\/tr><tr><td>Versiones distintas entre nodos<\/td><td>Comportamiento inconsistente tras failover<\/td><td>Mantener el mismo nivel de paquetes en ambos nodos<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Paso 2: Desactivar Apache como servicio del sistema (CR\u00cdTICO)<\/h2>\n\n\n\n<p><strong>Comandos (en cada nodo):<\/strong><\/p>\n\n\n\n<p><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>systemctl stop apache2\nsystemctl disable apache2\n<\/code><\/pre>\n\n\n\n<p><strong>Verificar:<\/strong><\/p>\n\n\n\n<p><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>systemctl is-enabled apache2\n<\/code><\/pre>\n\n\n\n<p>Debe responder: <strong><code>disabled<\/code><\/strong>.<\/p>\n\n\n\n<p><strong>Qu\u00e9 se hace:<\/strong> Se <strong>detiene<\/strong> cualquier instancia de Apache corriendo actualmente y se <strong>deshabilita<\/strong> su inicio autom\u00e1tico al arrancar el sistema operativo.<\/p>\n\n\n\n<p><strong>Por qu\u00e9 se hace:<\/strong> En un cl\u00faster HA, <strong>solo Pacemaker debe controlar el inicio y detenci\u00f3n de los servicios clusterizados<\/strong>. Sin este paso, Apache podr\u00eda iniciarse autom\u00e1ticamente en <strong>ambos nodos<\/strong> tras un reinicio, generando una situaci\u00f3n grave:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Dos instancias concurrentes<\/strong> del servidor web, potencialmente compitiendo por el puerto 80.<\/li>\n\n\n\n<li><strong>Conflicto con Pacemaker:<\/strong> al detectar Apache ejecut\u00e1ndose fuera de su control, Pacemaker podr\u00eda marcar el recurso en estado de error o tomar medidas inesperadas.<\/li>\n\n\n\n<li>Ruptura del modelo activo\/pasivo: el servicio quedar\u00eda activo en ambos nodos simult\u00e1neamente sin coordinaci\u00f3n.<\/li>\n<\/ul>\n\n\n\n<p><strong>Qu\u00e9 ocurre internamente:<\/strong><code>stop<\/code> env\u00eda la se\u00f1al de apagado al proceso Apache si est\u00e1 corriendo. <code>disable<\/code> elimina los enlaces simb\u00f3licos del servicio en los targets de systemd (<code>multi-user.target.wants<\/code>), impidiendo que Apache se inicie autom\u00e1ticamente al arrancar el sistema. <strong>Tras este paso, Apache solo arrancar\u00e1 cuando Pacemaker ejecute la acci\u00f3n <em>start<\/em> del agente OCF.<\/strong><\/p>\n\n\n\n<p><strong>Verificaci\u00f3n completa:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>systemctl status apache2<\/code> \u2192 <strong>inactive (dead)<\/strong> en ambos nodos.<\/li>\n\n\n\n<li><code>systemctl is-enabled apache2<\/code> \u2192 <strong>disabled<\/strong> en ambos nodos.<\/li>\n\n\n\n<li><code>pgrep -f apache2<\/code> \u2192 sin resultados (no hay procesos Apache).<\/li>\n\n\n\n<li><code>ss -tlnp | grep :80<\/code> \u2192 sin resultados (el puerto 80 no est\u00e1 en uso).<\/li>\n<\/ul>\n\n\n\n<p><strong>Errores comunes:<\/strong><\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Problema<\/th><th>S\u00edntoma<\/th><th>Soluci\u00f3n<\/th><\/tr><tr><th><strong>Apache arranca tras reinicio<\/strong><\/th><td><code>systemctl status apache2<\/code> muestra <em>active<\/em> tras un reboot<\/td><td>Verificar que <code>systemctl disable apache2<\/code> se ejecut\u00f3 correctamente en ese nodo. Repetir si es necesario.<\/td><\/tr><tr><th><strong>Olvidar ejecutar en un nodo<\/strong><\/th><td>Pacemaker inicia Apache en nodo-a, pero Apache ya corre por systemd en nodo-b \u2192 puerto 80 ocupado, conflictos de estado<\/td><td>Detener y deshabilitar Apache en <strong>todos<\/strong> los nodos. Si Pacemaker ya reporta error, limpiar con <code>pcs resource cleanup Apache<\/code>.<\/td><\/tr><tr><th><strong>Proceso residual de Apache<\/strong><\/th><td><code>pgrep apache2<\/code> muestra PIDs tras <code>stop<\/code><\/td><td>Verificar con <code>systemctl status apache2<\/code> y, si persiste, usar <code>kill<\/code> para eliminar procesos hu\u00e9rfanos.<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Paso 3: Crear una p\u00e1gina de prueba en cada nodo<\/h2>\n\n\n\n<p><strong>Comando (en cada nodo):<\/strong><\/p>\n\n\n\n<p><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>echo \"Apache activo en $(hostname)\" > \/var\/www\/html\/index.html\n<\/code><\/pre>\n\n\n\n<p><strong>Qu\u00e9 se hace:<\/strong> Se crea un archivo <code>index.html<\/code> con contenido distintivo en cada nodo: en <code>nodo-a<\/code> quedar\u00e1 \u00abApache activo en nodo-a\u00bb y en <code>nodo-b<\/code> quedar\u00e1 \u00abApache activo en nodo-b\u00bb.<\/p>\n\n\n\n<p><strong>Por qu\u00e9 se hace:<\/strong> Esta p\u00e1gina permite <strong>identificar visualmente qu\u00e9 nodo est\u00e1 sirviendo las peticiones web<\/strong> en cada momento. Durante el failover, al consultar la IP virtual con <code>curl<\/code>, la respuesta cambiar\u00e1 de \u00abnodo-a\u00bb a \u00abnodo-b\u00bb, confirmando la migraci\u00f3n del servicio. Es una herramienta did\u00e1ctica fundamental para recolectar evidencias y analizar el comportamiento del cl\u00faster.<\/p>\n\n\n\n<p><strong>Qu\u00e9 ocurre internamente:<\/strong> Se escribe un archivo de texto en el <strong>sistema de archivos local<\/strong> de cada nodo. Como no se usa DRBD en esta pr\u00e1ctica, cada nodo tiene su propio almacenamiento independiente para <code>\/var\/www\/html<\/code> \u2014 los archivos <code>index.html<\/code> son diferentes a prop\u00f3sito. En un entorno de producci\u00f3n se utilizar\u00eda almacenamiento compartido o replicado (como DRBD) para que ambos nodos sirvan exactamente los mismos datos.<\/p>\n\n\n\n<p><strong>Verificaci\u00f3n:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>En <code>nodo-a<\/code>: <code>cat \/var\/www\/html\/index.html<\/code> \u2192 <code>Apache activo en nodo-a<\/code>.<\/li>\n\n\n\n<li>En <code>nodo-b<\/code>: <code>cat \/var\/www\/html\/index.html<\/code> \u2192 <code>Apache activo en nodo-b<\/code>.<\/li>\n<\/ul>\n\n\n\n<p><strong>Errores comunes:<\/strong><\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Problema<\/th><th>S\u00edntoma<\/th><th>Soluci\u00f3n<\/th><\/tr><tr><td>Permiso denegado<\/td><td>Error al escribir en <code>\/var\/www\/html\/<\/code><\/td><td>Ejecutar con <code>sudo<\/code> o como root<\/td><\/tr><tr><td>Directorio inexistente<\/td><td><em>\u00abNo such file or directory\u00bb<\/em><\/td><td>Verificar instalaci\u00f3n de Apache; crear con <code>mkdir -p \/var\/www\/html<\/code> si falta<\/td><\/tr><tr><td>Hostname incorrecto<\/td><td>La p\u00e1gina muestra <code>localhost<\/code> u otro nombre<\/td><td>Confirmar que <code>hostnamectl set-hostname<\/code> se ejecut\u00f3 correctamente en cada nodo (paso de la pr\u00e1ctica anterior)<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Paso 4: Habilitar mod_status en Apache (Requisito del agente OCF)<\/h2>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>\u26a0\ufe0f <strong>Este paso no est\u00e1 en la lista original de comandos de la actividad, pero es un requisito t\u00e9cnico indispensable para que el agente OCF <code>ocf:heartbeat:apache<\/code> funcione correctamente.<\/strong> Sin \u00e9l, el recurso Apache fallar\u00e1 al intentar monitorizar el servicio.<\/p>\n<\/blockquote>\n\n\n\n<p><strong>\u00bfPor qu\u00e9 es necesario?<\/strong> El agente de recursos <code>ocf:heartbeat:apache<\/code> utiliza por defecto la <strong>p\u00e1gina de estado del servidor<\/strong> (<code>\/server-status<\/code>) para verificar que Apache est\u00e1 operativo. Esta funcionalidad depende del m\u00f3dulo <strong>mod_status<\/strong> y del archivo de configuraci\u00f3n correspondiente (normalmente <code>\/etc\/apache2\/mod_status.conf<\/code>). Si la p\u00e1gina de estado no funciona o no est\u00e1 restringida exclusivamente a localhost (<code>127.0.0.1<\/code>), el agente reportar\u00e1 un fallo de monitorizaci\u00f3n y Pacemaker marcar\u00e1 el recurso como defectuoso.<\/p>\n\n\n\n<p>La documentaci\u00f3n oficial del agente OCF indica expl\u00edcitamente: <em>\u00abMake sure that the server status page works and that the access is allowed<\/em><em><strong>only<\/strong><\/em><em>from localhost (address 127.0.0.1)\u00bb<\/em>. Adem\u00e1s, si la <code>statusurl<\/code> responde desde direcciones distintas a localhost, <em>\u00abit may happen that the cluster complains about the resource being active on multiple nodes\u00bb<\/em>.<\/p>\n\n\n\n<p><strong>Qu\u00e9 hacer (en ambos nodos):<\/strong><\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Habilitar el m\u00f3dulo mod_status:<\/strong> sudo a2enmod status<br><\/li>\n\n\n\n<li><strong>Crear o editar la configuraci\u00f3n de server-status.<\/strong> La gu\u00eda de Server World muestra una configuraci\u00f3n funcional para cl\u00fasteres Pacemaker:  sudo nano \/etc\/apache2\/conf-available\/server-status.conf<br>Contenido: Apache Config&lt;Location \/server-status><br>SetHandler server-status<br>Require local<br>&lt;\/Location><br><\/li>\n\n\n\n<li><strong>Activar la configuraci\u00f3n:<\/strong> sudo a2enconf server-status<br><\/li>\n<\/ol>\n\n\n\n<p><strong>Verificaci\u00f3n (verificaci\u00f3n temporal \u2014 requiere iniciar Apache brevemente):<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Iniciar Apache manualmente para probar: <code>sudo systemctl start apache2<\/code><\/li>\n\n\n\n<li>Ejecutar: <code>curl -s -o \/dev\/null -w \"%{http_code}\" http:\/\/127.0.0.1\/server-status<\/code> \u2192 debe devolver <strong>200<\/strong>.<\/li>\n\n\n\n<li>Ejecutar desde otro equipo: <code>curl http:\/\/&lt;IP_del_nodo>\/server-status<\/code> \u2192 <strong>debe ser rechazado<\/strong> (403 Forbidden) o no responder, confirmando que el acceso est\u00e1 restringido a localhost.<\/li>\n\n\n\n<li><strong>Detener Apache tras la prueba:<\/strong> <code>sudo systemctl stop apache2<\/code> (Pacemaker ser\u00e1 quien lo inicie despu\u00e9s).<\/li>\n<\/ul>\n\n\n\n<p><strong>Consecuencias de omitir este paso:<\/strong> El agente OCF intentar\u00e1 acceder a <code>http:\/\/127.0.0.1\/server-status<\/code> durante la operaci\u00f3n <em>start<\/em> y cada 30 segundos durante <em>monitor<\/em>. Si la p\u00e1gina no responde con c\u00f3digo 200, el agente reportar\u00e1 fallo. Pacemaker marcar\u00e1 el recurso como <strong>Failed<\/strong> e intentar\u00e1 recuperarlo (potencialmente provocando un failover innecesario o dejando Apache permanentemente detenido).<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Paso 5: Crear el recurso Apache en Pacemaker<\/h2>\n\n\n\n<p><strong>Comando (desde <code>nodo-a<\/code>):<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>pcs resource create Apache \\\nocf:heartbeat:apache \\\nconfigfile=\/etc\/apache2\/apache2.conf \\\nstatusurl=\"http:\/\/127.0.0.1\/server-status\" \\\nop monitor interval=30s<\/code><\/pre>\n\n\n\n<p><br><strong>Qu\u00e9 se hace:<\/strong> Se registra Apache como un <strong>recurso del cl\u00faster<\/strong> en el CIB (Cluster Information Base) de Pacemaker, utilizando el agente de recursos OCF <code>ocf:heartbeat:apache<\/code>. Tras la creaci\u00f3n, Pacemaker evaluar\u00e1 en qu\u00e9 nodo iniciarlo e inmediatamente ejecutar\u00e1 la secuencia de arranque.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">An\u00e1lisis de cada par\u00e1metro<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong><code>Apache<\/code><\/strong> \u2014 Nombre l\u00f3gico del recurso en el cl\u00faster. Se usar\u00e1 en todos los comandos posteriores (<code>pcs resource status Apache<\/code>, restricciones, etc.).<\/li>\n\n\n\n<li><strong><code>ocf:heartbeat:apache<\/code><\/strong> \u2014 <strong>Agente de recursos OCF<\/strong> dedicado a gestionar servidores web Apache. Este agente opera tanto con Apache versi\u00f3n 1.x como 2.x. Implementa las acciones est\u00e1ndar: <code>start<\/code>, <code>stop<\/code>, <code>status<\/code>, <code>monitor<\/code>, <code>meta-data<\/code> y <code>validate-all<\/code>. Pacemaker invoca estas acciones para controlar el ciclo de vida completo de Apache dentro del cl\u00faster. <strong>\u00bfPor qu\u00e9 OCF y no systemd?<\/strong> Pacemaker tambi\u00e9n puede gestionar servicios v\u00eda <code>systemd:apache2<\/code>, pero el agente OCF ofrece una ventaja clave: <strong>monitorizaci\u00f3n inteligente<\/strong> a trav\u00e9s de la p\u00e1gina de estado HTTP. El agente <code>systemd<\/code> solo verifica si el proceso existe; el agente OCF verifica que Apache realmente responde a peticiones HTTP, detectando fallos funcionales (no solo ca\u00eddas del proceso).<\/li>\n\n\n\n<li><strong><code>configfile=\/etc\/apache2\/apache2.conf<\/code><\/strong> \u2014 Ruta al archivo de configuraci\u00f3n principal de Apache. El agente lo analiza para derivar valores predeterminados de otros par\u00e1metros del recurso (ruta del binario, puerto, archivo PID). <strong>Especificar este par\u00e1metro es obligatorio en Debian<\/strong>, ya que el valor predeterminado del agente es <code>\/etc\/httpd\/conf\/httpd.conf<\/code> (ruta t\u00edpica de Red Hat\/CentOS). De forma similar, el binario predeterminado del agente es <code>\/usr\/sbin\/httpd<\/code>, mientras que en Debian es <code>\/usr\/sbin\/apache2<\/code>. Al apuntar <code>configfile<\/code> a la ruta correcta de Debian, el agente puede derivar las rutas apropiadas para el sistema.<\/li>\n\n\n\n<li><strong><code>statusurl=\"http:\/\/127.0.0.1\/server-status\"<\/code><\/strong> \u2014 URL que el agente utilizar\u00e1 para verificar la salud de Apache. Si no se especifica, el agente intenta deducirla del archivo de configuraci\u00f3n. Se recomienda fijarla expl\u00edcitamente. <strong>El acceso a esta URL debe estar restringido exclusivamente a <code>127.0.0.1<\/code><\/strong>; de lo contrario, el cl\u00faster podr\u00eda interpretar err\u00f3neamente que Apache est\u00e1 activo en m\u00faltiples nodos simult\u00e1neamente. Esto se configur\u00f3 en el Paso 4.<\/li>\n\n\n\n<li><strong><code>op monitor interval=30s<\/code><\/strong> \u2014 Cada <strong>30 segundos<\/strong>, Pacemaker ejecutar\u00e1 la acci\u00f3n <em>monitor<\/em> del agente, que accede a la <code>statusurl<\/code> para confirmar que Apache sigue operativo. Si la comprobaci\u00f3n falla, Pacemaker marcar\u00e1 el recurso como defectuoso y aplicar\u00e1 la pol\u00edtica de recuperaci\u00f3n configurada (reiniciar localmente o hacer failover al otro nodo).<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Qu\u00e9 ocurre internamente al crear e iniciar el recurso<\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Actualizaci\u00f3n del CIB:<\/strong> Pacemaker registra el nuevo <em>primitive<\/em> <code>Apache<\/code> con sus par\u00e1metros y operaciones.<\/li>\n\n\n\n<li><strong>Selecci\u00f3n de nodo:<\/strong> Pacemaker eval\u00faa en qu\u00e9 nodo iniciar el recurso. Sin restricciones a\u00fan definidas, generalmente seleccionar\u00e1 <code>nodo-a<\/code> (donde ya reside la IP-Virtual).<\/li>\n\n\n\n<li><strong>Ejecuci\u00f3n de <em>start<\/em>:<\/strong> El agente OCF arranca Apache utilizando la configuraci\u00f3n indicada.<\/li>\n\n\n\n<li><strong>Bucle de verificaci\u00f3n:<\/strong> La operaci\u00f3n <em>start<\/em> <strong>no finaliza inmediatamente<\/strong> tras lanzar el proceso. En su lugar, entra en un <strong>bucle interno<\/strong> donde invoca repetidamente la acci\u00f3n <em>monitor<\/em> para confirmar que el servidor arranc\u00f3 y est\u00e1 operativo. Si <em>monitor<\/em> no tiene \u00e9xito dentro del timeout de <em>start<\/em>, el recurso Apache terminar\u00e1 con un estado de error. Esto garantiza que Pacemaker no declare Apache como \u00abStarted\u00bb hasta que realmente est\u00e9 sirviendo peticiones.<\/li>\n\n\n\n<li><strong>Monitorizaci\u00f3n continua:<\/strong> Una vez confirmado el arranque, Pacemaker ejecutar\u00e1 <em>monitor<\/em> cada 30 segundos para detectar cualquier degradaci\u00f3n.<\/li>\n<\/ol>\n\n\n\n<p>La gu\u00eda de Server World muestra un ejemplo similar de creaci\u00f3n de recurso Apache en Pacemaker: <code>pcs resource create website ocf:heartbeat:apache configfile=\/etc\/apache2\/apache2.conf statusurl=http:\/\/127.0.0.1\/server-status<\/code>.<\/p>\n\n\n\n<p><strong>Verificaci\u00f3n:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>pcs status<\/code> \u2192 debe mostrar el recurso Apache como <strong>Started<\/strong> en nodo-a: <code>Full list of resources: IP-Virtual (ocf::heartbeat:IPaddr2): Started nodo-a Apache (ocf::heartbeat:apache): Started nodo-a<\/code><\/li>\n\n\n\n<li>En <code>nodo-a<\/code>: <code>pgrep -f apache2<\/code> \u2192 debe devolver PIDs de los procesos Apache (master y workers).<\/li>\n\n\n\n<li>En <code>nodo-a<\/code>: <code>ss -tlnp | grep :80<\/code> \u2192 debe mostrar <code>apache2<\/code> escuchando en el puerto 80.<\/li>\n\n\n\n<li>En <code>nodo-b<\/code>: <code>pgrep -f apache2<\/code> \u2192 sin resultados (Apache no corre all\u00ed).<\/li>\n<\/ul>\n\n\n\n<p><strong>Errores comunes:<\/strong><\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Problema<\/th><th>S\u00edntoma<\/th><th>Soluci\u00f3n<\/th><\/tr><tr><th><strong>mod_status no habilitado<\/strong><\/th><td>Recurso en estado <em>Failed<\/em>. En logs: error al acceder a la p\u00e1gina de estado. La operaci\u00f3n <em>monitor<\/em> depende de mod_status y el archivo de configuraci\u00f3n correspondiente.<\/td><td>Completar el Paso 4: <code>a2enmod status<\/code>, crear configuraci\u00f3n de <code>server-status<\/code> con <code>Require local<\/code>. Limpiar el error con <code>pcs resource cleanup Apache<\/code>.<\/td><\/tr><tr><th><strong>Ruta de <code>configfile<\/code> incorrecta<\/strong><\/th><td>Apache no inicia. El valor predeterminado del agente es <code>\/etc\/httpd\/conf\/httpd.conf<\/code>, que no existe en Debian.<\/td><td>Verificar que <code>configfile<\/code> apunte expl\u00edcitamente a <code>\/etc\/apache2\/apache2.conf<\/code>.<\/td><\/tr><tr><th><strong>Apache ya corriendo por systemd<\/strong><\/th><td>Conflicto: <em>\u00abAddress already in use\u00bb<\/em> en el puerto 80.<\/td><td>Verificar el Paso 2: <code>systemctl stop apache2 &amp;&amp; systemctl disable apache2<\/code> en ambos nodos. Luego <code>pcs resource cleanup Apache<\/code>.<\/td><\/tr><tr><th><strong>Timeout de arranque excedido<\/strong><\/th><td>El agente no logra confirmar el arranque dentro del tiempo l\u00edmite. El recurso termina con error.<\/td><td>Incrementar el timeout de start: <code>pcs resource update Apache op start timeout=60s<\/code>. Verificar que <code>server-status<\/code> responde correctamente.<\/td><\/tr><tr><th><strong>statusurl accesible desde IPs externas<\/strong><\/th><td>El cl\u00faster puede reportar que Apache est\u00e1 activo en m\u00faltiples nodos.<\/td><td>Restringir <code>\/server-status<\/code> a <code>Require local<\/code> en la configuraci\u00f3n de Apache (Paso 4).<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Paso 6: Relacionar Apache con la IP Virtual (Restricciones de Orden y Colocaci\u00f3n)<\/h2>\n\n\n\n<p><strong>Comandos (desde <code>nodo-a<\/code>):<\/strong><\/p>\n\n\n\n<p><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>pcs constraint order IP-Virtual then Apache\npcs constraint colocation add Apache with IP-Virtual INFINITY\n<\/code><\/pre>\n\n\n\n<p><\/p>\n\n\n\n<p><strong>Qu\u00e9 se hace:<\/strong> Se crean dos <strong>restricciones<\/strong> en Pacemaker para vincular el recurso <code>Apache<\/code> con el recurso <code>IP-Virtual<\/code> existente, garantizando que siempre se ejecuten juntos y en el orden correcto.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Restricci\u00f3n de orden: <code>IP-Virtual then Apache<\/code><\/h3>\n\n\n\n<p>Esta restricci\u00f3n establece que <strong>primero debe activarse la IP Virtual y despu\u00e9s Apache<\/strong>. Al detener recursos, el orden se invierte: Apache se detiene <strong>antes<\/strong> de liberar la IP. De este modo se evita que Apache intente servir p\u00e1ginas en una IP que a\u00fan no est\u00e1 asignada al nodo, o que siga sirviendo tras haberse movido la IP a otro nodo.<\/p>\n\n\n\n<p><strong>Consecuencia pr\u00e1ctica:<\/strong> Si por alguna raz\u00f3n la IP Virtual no puede iniciarse (p. ej., por un conflicto de red), Apache <strong>no arrancar\u00e1<\/strong>. Esto es deseable: no tiene sentido tener Apache corriendo sin la direcci\u00f3n IP por la que los clientes acceden al servicio.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Restricci\u00f3n de colocaci\u00f3n: <code>Apache with IP-Virtual INFINITY<\/code><\/h3>\n\n\n\n<p>Obliga a que <strong>Apache y la IP Virtual se ejecuten siempre en el mismo nodo<\/strong>. El score <strong>INFINITY<\/strong> convierte esta regla en <strong>obligatoria<\/strong> (no es una preferencia, es un requisito estricto). Si no puede cumplirse, Pacemaker preferir\u00e1 dejar Apache detenido antes que violarlo.<\/p>\n\n\n\n<p><strong>Consecuencia pr\u00e1ctica:<\/strong> Si la IP Virtual migra de un nodo a otro (por failover o intervenci\u00f3n manual), Pacemaker autom\u00e1ticamente detendr\u00e1 Apache en el nodo original y lo reiniciar\u00e1 en el nodo destino, respetando adem\u00e1s la restricci\u00f3n de orden (primero asigna la IP, luego arranca Apache).<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Efecto combinado de ambas restricciones<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Escenario<\/th><th>Comportamiento<\/th><\/tr><tr><td>Arranque normal<\/td><td>Pacemaker asigna la VIP a un nodo \u2192 luego inicia Apache en ese mismo nodo<\/td><\/tr><tr><td>Failover (nodo activo cae)<\/td><td>Pacemaker asigna la VIP al nodo sobreviviente \u2192 luego inicia Apache all\u00ed<\/td><\/tr><tr><td>VIP no disponible<\/td><td>Apache permanece <strong>detenido<\/strong> en todo el cl\u00faster<\/td><\/tr><tr><td>Detenci\u00f3n ordenada<\/td><td>Pacemaker detiene Apache \u2192 luego remueve la VIP<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p><strong>Nota did\u00e1ctica:<\/strong> Una alternativa a las restricciones expl\u00edcitas es agrupar los recursos en un <strong>grupo de recursos<\/strong> (<em>resource group<\/em>). En un grupo, los recursos se inician en el orden en que se a\u00f1aden y se detienen en orden inverso, y siempre se ejecutan en el mismo nodo. En esta pr\u00e1ctica se usan restricciones individuales para que el estudiante comprenda expl\u00edcitamente cada regla y su efecto.<\/p>\n<\/blockquote>\n\n\n\n<p><strong>Verificaci\u00f3n:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>pcs constraint show<\/code> \u2192 debe listar:\n<ul class=\"wp-block-list\">\n<li>Orden: <code>start IP-Virtual then start Apache (kind:Mandatory)<\/code><\/li>\n\n\n\n<li>Colocaci\u00f3n: <code>Apache with IP-Virtual (score:INFINITY)<\/code><\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><code>pcs status<\/code> \u2192 ambos recursos en el <strong>mismo nodo<\/strong> (nodo-a).<\/li>\n<\/ul>\n\n\n\n<p><strong>Errores comunes:<\/strong><\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Problema<\/th><th>S\u00edntoma<\/th><th>Soluci\u00f3n<\/th><\/tr><tr><th><strong>Nombres de recurso incorrectos<\/strong><\/th><td>Error <em>\u00abresource not found\u00bb<\/em> al crear la restricci\u00f3n<\/td><td>Usar exactamente los nombres definidos: <code>IP-Virtual<\/code> y <code>Apache<\/code> (respetar may\u00fasculas, min\u00fasculas y guiones). Verificar con <code>pcs resource status<\/code>.<\/td><\/tr><tr><th><strong>Falta restricci\u00f3n de colocaci\u00f3n<\/strong><\/th><td>Apache arranca en un nodo distinto al de la IP \u2192 servicio inaccesible por la VIP<\/td><td>Agregar la restricci\u00f3n de colocaci\u00f3n con score INFINITY.<\/td><\/tr><tr><th><strong>Falta restricci\u00f3n de orden<\/strong><\/th><td>Apache intenta arrancar antes de que la IP est\u00e9 disponible \u2192 posible fallo de arranque o servicio inaccesible temporalmente<\/td><td>Crear la restricci\u00f3n de orden: <code>pcs constraint order IP-Virtual then Apache<\/code>.<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Paso 7: Verificar el estado del cl\u00faster con Apache integrado<\/h2>\n\n\n\n<p><strong>Comando:<\/strong><\/p>\n\n\n\n<p><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>pcs status\n<\/code><\/pre>\n\n\n\n<p><strong>Salida esperada:<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Cluster name: laboratorio-ha\n...\nOnline: &#91; nodo-a nodo-b ]\n...\nFull list of resources:\n  IP-Virtual  (ocf::heartbeat:IPaddr2):   Started nodo-a\n  Apache      (ocf::heartbeat:apache):    Started nodo-a\n<\/code><\/pre>\n\n\n\n<p>Esto confirma que la IP Virtual y Apache se ejecutan en <strong>nodo-a<\/strong>, mientras <strong>nodo-b<\/strong> est\u00e1 Online pero sin recursos asignados (en espera).<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Prueba funcional del servicio web<\/h3>\n\n\n\n<p>Desde un equipo cliente, desde nodo-b, o desde el propio nodo-a:<\/p>\n\n\n\n<p><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>curl http:\/\/192.168.1.100\n<\/code><\/pre>\n\n\n\n<p><strong>Respuesta esperada:<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Apache activo en nodo-a\n<\/code><\/pre>\n\n\n\n<p>Esto confirma que:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>La IP virtual <code>192.168.1.100<\/code> est\u00e1 asignada a <code>nodo-a<\/code>.<\/li>\n\n\n\n<li>Apache est\u00e1 operativo bajo el control de Pacemaker y sirviendo la p\u00e1gina de prueba.<\/li>\n\n\n\n<li>Los clientes acceden al servicio web mediante la <strong>IP del cl\u00faster<\/strong>, independientemente de las IPs f\u00edsicas de los nodos.<\/li>\n<\/ul>\n\n\n\n<p><strong>Verificaciones adicionales:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>En <code>nodo-a<\/code>: <code>ip addr | grep 192.168.1.100<\/code> \u2192 debe mostrar la VIP en una interfaz de red.<\/li>\n\n\n\n<li>En <code>nodo-a<\/code>: <code>ss -tlnp | grep :80<\/code> \u2192 confirma que Apache escucha en el puerto 80.<\/li>\n\n\n\n<li>En <code>nodo-b<\/code>: <code>pgrep apache2<\/code> \u2192 sin resultados (Apache no corre all\u00ed).<\/li>\n\n\n\n<li>En <code>nodo-b<\/code>: <code>ip addr | grep 192.168.1.100<\/code> \u2192 sin resultados (la VIP no est\u00e1 all\u00ed).<\/li>\n\n\n\n<li>Inicia un <strong>ping continuo<\/strong> (<code>ping 192.168.1.100<\/code>) desde un tercer equipo para medir la interrupci\u00f3n exacta durante el failover del siguiente paso.<\/li>\n<\/ul>\n\n\n\n<p><strong>Errores comunes:<\/strong><\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Problema<\/th><th>S\u00edntoma<\/th><th>Soluci\u00f3n<\/th><\/tr><tr><th><strong>Apache en estado <em>Stopped<\/em><\/strong><\/th><td><code>pcs status<\/code> muestra Apache detenido<\/td><td>Verificar que <code>IP-Virtual<\/code> est\u00e9 <em>Started<\/em>. Con colocaci\u00f3n INFINITY, si la IP no est\u00e1 activa, Apache permanecer\u00e1 detenido. Iniciar la IP: <code>pcs resource start IP-Virtual<\/code>. Revisar logs de Pacemaker: <code>journalctl -eu pacemaker<\/code>.<\/td><\/tr><tr><th><strong>Apache en estado <em>Failed<\/em><\/strong><\/th><td>Recurso marcado como fallido con <em>fail-count<\/em><\/td><td>Investigar la causa (<code>pcs resource failcount show Apache<\/code>). Causas frecuentes: mod_status no habilitado, configfile incorrecto, puerto ocupado. Corregir y limpiar: <code>pcs resource cleanup Apache<\/code>.<\/td><\/tr><tr><th><strong>curl no responde<\/strong><\/th><td>Timeout al acceder a la VIP<\/td><td>Verificar que la IP virtual est\u00e9 asignada (<code>ip addr<\/code> en nodo-a). Verificar que Apache est\u00e9 corriendo. Comprobar firewalls: permitir tr\u00e1fico al puerto 80 e ICMP en los nodos.<\/td><\/tr><tr><th><strong>Respuesta inesperada<\/strong><\/th><td><code>curl<\/code> devuelve la p\u00e1gina predeterminada de Apache en vez de la personalizada<\/td><td>Verificar que <code>\/var\/www\/html\/index.html<\/code> contiene el texto correcto. Confirmar el DocumentRoot en <code>\/etc\/apache2\/sites-enabled\/000-default.conf<\/code>.<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Paso 8: Prueba de <em>failover<\/em> con Apache<\/h2>\n\n\n\n<p>La prueba cr\u00edtica: verificar que ante la ca\u00edda del nodo principal, el cl\u00faster migra autom\u00e1ticamente <strong>tanto la IP virtual como Apache<\/strong> al nodo sobreviviente.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Procedimiento<\/h3>\n\n\n\n<p>En <strong>nodo-a<\/strong> (actualmente activo):<\/p>\n\n\n\n<p><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>shutdown -h now\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Qu\u00e9 ocurre internamente durante el failover<\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Detecci\u00f3n del fallo (Corosync):<\/strong> Corosync en <code>nodo-b<\/code> detecta la ausencia de <em>heartbeats<\/em> de <code>nodo-a<\/code>. Tras agotarse el <em>token timeout<\/em>, declara a <code>nodo-a<\/code> como <strong>offline<\/strong>.<\/li>\n\n\n\n<li><strong>Notificaci\u00f3n a Pacemaker:<\/strong> Corosync comunica el evento de fallo a Pacemaker en <code>nodo-b<\/code>. Con la configuraci\u00f3n <code>two_node: 1<\/code> (habitual en cl\u00fasteres de 2 nodos), <code>nodo-b<\/code> mantiene el qu\u00f3rum y puede operar de forma aut\u00f3noma.<\/li>\n\n\n\n<li><strong>Coordinaci\u00f3n (DC):<\/strong> Si <code>nodo-a<\/code> era el <em>Designated Coordinator<\/em>, <code>nodo-b<\/code> asume ese rol autom\u00e1ticamente.<\/li>\n\n\n\n<li><strong>Migraci\u00f3n secuencial (restricci\u00f3n de orden):<\/strong> Pacemaker identifica que <code>IP-Virtual<\/code> y <code>Apache<\/code> estaban activos en el nodo ca\u00eddo y deben recuperarse. Respetando la restricci\u00f3n de orden:\n<ul class=\"wp-block-list\">\n<li><strong>Primero:<\/strong> Asigna la <strong>IP Virtual<\/strong> a <code>nodo-b<\/code>. El agente <code>IPaddr2<\/code> configura la IP <code>192.168.1.100<\/code> en la interfaz de red de <code>nodo-b<\/code> y emite un paquete <strong>ARP gratuito<\/strong> para actualizar las tablas ARP de switches\/routers.<\/li>\n\n\n\n<li><strong>Despu\u00e9s:<\/strong> Inicia <strong>Apache<\/strong> en <code>nodo-b<\/code>. El agente <code>ocf:heartbeat:apache<\/code> arranca el servicio y verifica mediante el bucle de monitorizaci\u00f3n en <code>http:\/\/127.0.0.1\/server-status<\/code> que Apache responde correctamente.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Servicio restaurado:<\/strong> En pocos segundos, <code>nodo-b<\/code> es el nodo activo con la VIP y Apache ejecut\u00e1ndose. Los clientes perciben, a lo sumo, uno o dos pings perdidos durante la transici\u00f3n.<\/li>\n<\/ol>\n\n\n\n<h3 class=\"wp-block-heading\">Verificaci\u00f3n en nodo-b (nuevo activo)<\/h3>\n\n\n\n<p><strong>Estado del cl\u00faster:<\/strong><\/p>\n\n\n\n<p><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>pcs status\n<\/code><\/pre>\n\n\n\n<p>Debe mostrar:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Online: &#91; nodo-b ]\nOFFLINE: &#91; nodo-a ]\n...\nIP-Virtual (ocf::heartbeat:IPaddr2): Started nodo-b\nApache     (ocf::heartbeat:apache):  Started nodo-b\n<\/code><\/pre>\n\n\n\n<p><strong>Verificar la IP:<\/strong><\/p>\n\n\n\n<p><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ip addr | grep 192.168.1.100\n<\/code><\/pre>\n\n\n\n<p>\u2192 Debe mostrar la VIP asignada en la interfaz de <code>nodo-b<\/code>.<\/p>\n\n\n\n<p><strong>Verificar el servicio web:<\/strong><\/p>\n\n\n\n<p><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>curl http:\/\/192.168.1.100\n<\/code><\/pre>\n\n\n\n<p>\u2192 Respuesta: <strong>\u00abApache activo en nodo-b\u00bb<\/strong>. La p\u00e1gina ahora proviene del segundo nodo, confirmando que tanto la IP como Apache migraron exitosamente.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Comportamiento al retornar nodo-a<\/h3>\n\n\n\n<p>Si se enciende de nuevo <code>nodo-a<\/code>, \u00e9ste reingresar\u00e1 al cl\u00faster (estado ONLINE), pero Pacemaker <strong>no revertir\u00e1 autom\u00e1ticamente<\/strong> los recursos al nodo original. Los recursos permanecen en <code>nodo-b<\/code> para evitar oscilaciones (<em>ping-pong<\/em>) en caso de fallas intermitentes. Para migrar los recursos de vuelta a <code>nodo-a<\/code>, se requiere una orden administrativa (p. ej., <code>pcs resource move<\/code>) o configurar preferencias de ubicaci\u00f3n (<em>resource stickiness<\/em>, <em>location constraints<\/em>).<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">An\u00e1lisis del tiempo de interrupci\u00f3n<\/h3>\n\n\n\n<p>Si se mantuvo un ping continuo a la VIP durante la falla, la cantidad de paquetes perdidos indica la duraci\u00f3n aproximada del failover (cada paquete ICMP perdido \u2248 1 segundo con el intervalo predeterminado). En un cl\u00faster bien configurado en red local, los clientes perciben a lo sumo una breve pausa. El tiempo exacto depende de:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Token timeout de Corosync:<\/strong> tiempo que tarda en declarar offline al nodo ca\u00eddo.<\/li>\n\n\n\n<li><strong>Intervalo de monitorizaci\u00f3n de Pacemaker:<\/strong> frecuencia con que verifica la salud de los recursos.<\/li>\n\n\n\n<li><strong>Tiempo de arranque de Apache:<\/strong> cu\u00e1nto tarda el agente OCF en confirmar que Apache est\u00e1 respondiendo.<\/li>\n<\/ul>\n\n\n\n<p><strong>Errores comunes:<\/strong><\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Problema<\/th><th>S\u00edntoma<\/th><th>Soluci\u00f3n<\/th><\/tr><tr><th><strong>Apache no arranca en nodo-b<\/strong><\/th><td><code>pcs status<\/code> muestra Apache en <em>Stopped<\/em> o <em>Failed<\/em> en nodo-b<\/td><td>Revisar logs: <code>journalctl -eu pacemaker<\/code>. Causa m\u00e1s frecuente: <strong>mod_status no habilitado en nodo-b<\/strong>. El Paso 4 debe ejecutarse en <strong>ambos<\/strong> nodos. Corregir y limpiar: <code>pcs resource cleanup Apache<\/code>.<\/td><\/tr><tr><th><strong>Failover no ocurre<\/strong><\/th><td><code>nodo-b<\/code> no asume los recursos<\/td><td>Verificar que <code>nodo-b<\/code> estaba Online antes de apagar <code>nodo-a<\/code>. Revisar pol\u00edtica de qu\u00f3rum: ejecutar <code>pcs property set no-quorum-policy=ignore<\/code> si el cl\u00faster no tiene qu\u00f3rum habilitado para 2 nodos.<\/td><\/tr><tr><th><strong>Interrupci\u00f3n prolongada<\/strong><\/th><td>Muchos paquetes perdidos durante el failover<\/td><td>Ajustar los <em>timeouts<\/em> de Corosync y el intervalo de monitorizaci\u00f3n de Pacemaker. Un intervalo de monitor m\u00e1s corto (ej. 10s) detecta fallos m\u00e1s r\u00e1pido, pero incrementa la sobrecarga.<\/td><\/tr><tr><th><strong>Inconsistencia por STONITH deshabilitado<\/strong><\/th><td>Tras reencender nodo-a, Pacemaker detecta conflicto<\/td><td>En laboratorio es infrecuente. Sin STONITH, un nodo que no se apag\u00f3 limpiamente podr\u00eda quedar en estado indeterminado. <strong>En producci\u00f3n, siempre implementar fencing<\/strong> para evitar que un nodo <em>zombi<\/em> cause servicios duplicados.<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Tabla Resumen: Comando \u2192 Funci\u00f3n \u2192 Verificaci\u00f3n \u2192 Error Frecuente<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th><strong>Paso<\/strong><\/th><th><strong>Comando(s)<\/strong><\/th><th><strong>Qu\u00e9 hace<\/strong><\/th><th><strong>Verificaci\u00f3n<\/strong><\/th><th><strong>Error frecuente<\/strong><\/th><\/tr><tr><th><strong>1<\/strong><\/th><td><code>apt install -y apache2<\/code> (ambos nodos)<\/td><td>Instala Apache para que pueda ejecutarse en cualquier nodo<\/td><td><code>apache2 -v<\/code> muestra versi\u00f3n<\/td><td>Paquete no disponible; versiones distintas entre nodos<\/td><\/tr><tr><th><strong>2<\/strong><\/th><td><code>systemctl stop apache2<\/code>; <code>systemctl disable apache2<\/code> (ambos)<\/td><td>Detiene y deshabilita Apache en systemd; solo Pacemaker lo controlar\u00e1<\/td><td><code>systemctl is-enabled apache2<\/code> \u2192 <strong>disabled<\/strong><\/td><td>Olvidar deshabilitar en un nodo \u2192 doble instancia<\/td><\/tr><tr><th><strong>3<\/strong><\/th><td><code>echo \"Apache activo en $(hostname)\" &gt; \/var\/www\/html\/index.html<\/code> (ambos)<\/td><td>Crea p\u00e1gina de prueba con hostname para identificar nodo activo<\/td><td><code>cat \/var\/www\/html\/index.html<\/code> \u2192 hostname correcto<\/td><td>Permisos insuficientes; directorio inexistente<\/td><\/tr><tr><th><strong>4<\/strong><\/th><td><code>a2enmod status<\/code>; crear <code>server-status.conf<\/code>; <code>a2enconf server-status<\/code> (ambos)<\/td><td>Habilita mod_status restringido a localhost, requisito del agente OCF <\/td><td><code>curl http:\/\/127.0.0.1\/server-status<\/code> \u2192 c\u00f3digo 200<\/td><td>mod_status no habilitado \u2192 agente falla en monitor<\/td><\/tr><tr><th><strong>5<\/strong><\/th><td><code>pcs resource create Apache ocf:heartbeat:apache configfile=... statusurl=... op monitor interval=30s<\/code><\/td><td>Registra Apache como recurso del cl\u00faster con monitorizaci\u00f3n HTTP<\/td><td><code>pcs status<\/code> \u2192 <em>Apache: Started nodo-a<\/em><\/td><td>configfile incorrecto (default es <code>\/etc\/httpd\/conf\/httpd.conf<\/code>) <\/td><\/tr><tr><th><strong>6<\/strong><\/th><td><code>pcs constraint order IP-Virtual then Apache<\/code>; <code>pcs constraint colocation add Apache with IP-Virtual INFINITY<\/code><\/td><td>VIP se inicia antes que Apache; ambos siempre en el mismo nodo<\/td><td><code>pcs constraint show<\/code> lista orden y colocaci\u00f3n<\/td><td>Nombres de recurso mal escritos<\/td><\/tr><tr><th><strong>7<\/strong><\/th><td><code>pcs status<\/code>; <code>curl http:\/\/192.168.1.100<\/code><\/td><td>Confirma estado del cl\u00faster y funcionamiento del sitio web<\/td><td>VIP y Apache en nodo-a; <code>curl<\/code> devuelve \u00abApache activo en nodo-a\u00bb<\/td><td>Apache en <em>Failed<\/em> \u2192 verificar mod_status y logs<\/td><\/tr><tr><th><strong>8<\/strong><\/th><td><code>shutdown -h now<\/code> (en nodo-a)<\/td><td>Simula falla del nodo principal; Pacemaker migra VIP + Apache a nodo-b<\/td><td><code>pcs status<\/code> \u2192 nodo-a <em>OFFLINE<\/em>, recursos en nodo-b; <code>curl<\/code> devuelve \u00abApache activo en nodo-b\u00bb<\/td><td>Apache no arranca en nodo-b \u2192 verificar mod_status en <strong>ambos<\/strong> nodos<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"944\" src=\"https:\/\/dsantana.uas.edu.mx\/wp-content\/uploads\/2026\/04\/image-7-1024x944.png\" alt=\"\" class=\"wp-image-2398\" srcset=\"https:\/\/dsantana.uas.edu.mx\/wp-content\/uploads\/2026\/04\/image-7-1024x944.png 1024w, https:\/\/dsantana.uas.edu.mx\/wp-content\/uploads\/2026\/04\/image-7-300x277.png 300w, https:\/\/dsantana.uas.edu.mx\/wp-content\/uploads\/2026\/04\/image-7-768x708.png 768w, https:\/\/dsantana.uas.edu.mx\/wp-content\/uploads\/2026\/04\/image-7-1536x1417.png 1536w, https:\/\/dsantana.uas.edu.mx\/wp-content\/uploads\/2026\/04\/image-7-2048x1889.png 2048w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Objetivo: Extender el cl\u00faster activo\/pasivo previamente configurado para que el servicio Apache2 sea gestionado por Pacemaker, de modo que solo est\u00e9 activo en el nodo que tiene la IP virtual (VIP), que migre autom\u00e1ticamente junto con la VIP durante un failover, y que el usuario final no perciba la ca\u00edda. La siguiente gu\u00eda asume que ya se cuenta con un cl\u00faster Pacemaker+Corosync operativo (seg\u00fan la pr\u00e1ctica anterior) y que ya existe un recurso de direcci\u00f3n IP Virtual actualmente activo en nodo-a. Apache a\u00fan no est\u00e1 gestionado por el cl\u00faster, por lo que ser\u00e1 a\u00f1adido en esta pr\u00e1ctica. El DocumentRoot del servidor web es \/var\/www\/html en ambos nodos. En este entorno de laboratorio no se usa DRBD para la replicaci\u00f3n de archivos y STONITH est\u00e1 deshabilitado. Contexto confirmado del laboratorio: Elemento Valor Cl\u00faster Pacemaker + Corosync, ya creado y operativo Recurso IP Virtual IP-Virtual (ocf:heartbeat:IPaddr2), ya funcional en nodo-a DRBD No se usa en esta pr\u00e1ctica STONITH Deshabilitado (stonith-enabled=false) \u2014 entorno de laboratorio DocumentRoot \/var\/www\/html Modo Activo\/pasivo (single-primary) Paso 1: Instalaci\u00f3n de Apache en ambos nodos Comando (en cada nodo): apt install -y apache2 Qu\u00e9 se hace: Se instala el servidor web Apache2 en los dos nodos del cl\u00faster. Por qu\u00e9 se hace: Apache debe estar instalado en todos los nodos del cl\u00faster para que Pacemaker pueda iniciarlo en cualquiera de ellos si fuera necesario. Si Apache solo estuviera en un nodo, un failover al otro ser\u00eda imposible: Pacemaker intentar\u00eda ejecutar un binario que no existe. Aunque solo un nodo lo ejecutar\u00e1 en cada momento (modelo activo\/pasivo), ambos deben tener el software disponible. Qu\u00e9 ocurre internamente: La instalaci\u00f3n deposita los binarios (\/usr\/sbin\/apache2), los archivos de configuraci\u00f3n (\/etc\/apache2\/), los m\u00f3dulos disponibles y los scripts de servicio. En Debian, el archivo de configuraci\u00f3n principal es \/etc\/apache2\/apache2.conf. A\u00fan no se modifica nada en la pila de red ni en el cl\u00faster; solo se prepara la capa de aplicaci\u00f3n de cada servidor. Verificaci\u00f3n: Errores comunes: Problema S\u00edntoma Soluci\u00f3n Repositorios desactualizados apt no localiza el paquete apache2 Ejecutar apt update antes de la instalaci\u00f3n Permisos insuficientes Error de permisos al instalar Ejecutar como root o con sudo Versiones distintas entre nodos Comportamiento inconsistente tras failover Mantener el mismo nivel de paquetes en ambos nodos Paso 2: Desactivar Apache como servicio del sistema (CR\u00cdTICO) Comandos (en cada nodo): Verificar: Debe responder: disabled. Qu\u00e9 se hace: Se detiene cualquier instancia de Apache corriendo actualmente y se deshabilita su inicio autom\u00e1tico al arrancar el sistema operativo. Por qu\u00e9 se hace: En un cl\u00faster HA, solo Pacemaker debe controlar el inicio y detenci\u00f3n de los servicios clusterizados. Sin este paso, Apache podr\u00eda iniciarse autom\u00e1ticamente en ambos nodos tras un reinicio, generando una situaci\u00f3n grave: Qu\u00e9 ocurre internamente:stop env\u00eda la se\u00f1al de apagado al proceso Apache si est\u00e1 corriendo. disable elimina los enlaces simb\u00f3licos del servicio en los targets de systemd (multi-user.target.wants), impidiendo que Apache se inicie autom\u00e1ticamente al arrancar el sistema. Tras este paso, Apache solo arrancar\u00e1 cuando Pacemaker ejecute la acci\u00f3n start del agente OCF. Verificaci\u00f3n completa: Errores comunes: Problema S\u00edntoma Soluci\u00f3n Apache arranca tras reinicio systemctl status apache2 muestra active tras un reboot Verificar que systemctl disable apache2 se ejecut\u00f3 correctamente en ese nodo. Repetir si es necesario. Olvidar ejecutar en un nodo Pacemaker inicia Apache en nodo-a, pero Apache ya corre por systemd en nodo-b \u2192 puerto 80 ocupado, conflictos de estado Detener y deshabilitar Apache en todos los nodos. Si Pacemaker ya reporta error, limpiar con pcs resource cleanup Apache. Proceso residual de Apache pgrep apache2 muestra PIDs tras stop Verificar con systemctl status apache2 y, si persiste, usar kill para eliminar procesos hu\u00e9rfanos. Paso 3: Crear una p\u00e1gina de prueba en cada nodo Comando (en cada nodo): Qu\u00e9 se hace: Se crea un archivo index.html con contenido distintivo en cada nodo: en nodo-a quedar\u00e1 \u00abApache activo en nodo-a\u00bb y en nodo-b quedar\u00e1 \u00abApache activo en nodo-b\u00bb. Por qu\u00e9 se hace: Esta p\u00e1gina permite identificar visualmente qu\u00e9 nodo est\u00e1 sirviendo las peticiones web en cada momento. Durante el failover, al consultar la IP virtual con curl, la respuesta cambiar\u00e1 de \u00abnodo-a\u00bb a \u00abnodo-b\u00bb, confirmando la migraci\u00f3n del servicio. Es una herramienta did\u00e1ctica fundamental para recolectar evidencias y analizar el comportamiento del cl\u00faster. Qu\u00e9 ocurre internamente: Se escribe un archivo de texto en el sistema de archivos local de cada nodo. Como no se usa DRBD en esta pr\u00e1ctica, cada nodo tiene su propio almacenamiento independiente para \/var\/www\/html \u2014 los archivos index.html son diferentes a prop\u00f3sito. En un entorno de producci\u00f3n se utilizar\u00eda almacenamiento compartido o replicado (como DRBD) para que ambos nodos sirvan exactamente los mismos datos. Verificaci\u00f3n: Errores comunes: Problema S\u00edntoma Soluci\u00f3n Permiso denegado Error al escribir en \/var\/www\/html\/ Ejecutar con sudo o como root Directorio inexistente \u00abNo such file or directory\u00bb Verificar instalaci\u00f3n de Apache; crear con mkdir -p \/var\/www\/html si falta Hostname incorrecto La p\u00e1gina muestra localhost u otro nombre Confirmar que hostnamectl set-hostname se ejecut\u00f3 correctamente en cada nodo (paso de la pr\u00e1ctica anterior) Paso 4: Habilitar mod_status en Apache (Requisito del agente OCF) \u26a0\ufe0f Este paso no est\u00e1 en la lista original de comandos de la actividad, pero es un requisito t\u00e9cnico indispensable para que el agente OCF ocf:heartbeat:apache funcione correctamente. Sin \u00e9l, el recurso Apache fallar\u00e1 al intentar monitorizar el servicio. \u00bfPor qu\u00e9 es necesario? El agente de recursos ocf:heartbeat:apache utiliza por defecto la p\u00e1gina de estado del servidor (\/server-status) para verificar que Apache est\u00e1 operativo. Esta funcionalidad depende del m\u00f3dulo mod_status y del archivo de configuraci\u00f3n correspondiente (normalmente \/etc\/apache2\/mod_status.conf). Si la p\u00e1gina de estado no funciona o no est\u00e1 restringida exclusivamente a localhost (127.0.0.1), el agente reportar\u00e1 un fallo de monitorizaci\u00f3n y Pacemaker marcar\u00e1 el recurso como defectuoso. La documentaci\u00f3n oficial del agente OCF indica expl\u00edcitamente: \u00abMake sure that the server status page works and that the access is allowedonlyfrom localhost (address 127.0.0.1)\u00bb. Adem\u00e1s, si la statusurl responde desde direcciones distintas a localhost, \u00abit may happen that the cluster complains about the resource being active on multiple nodes\u00bb. Qu\u00e9 hacer (en ambos nodos): Verificaci\u00f3n (verificaci\u00f3n temporal \u2014 requiere<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-2395","post","type-post","status-publish","format-standard","hentry","category-sin-categoria"],"_links":{"self":[{"href":"https:\/\/dsantana.uas.edu.mx\/index.php\/wp-json\/wp\/v2\/posts\/2395","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/dsantana.uas.edu.mx\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dsantana.uas.edu.mx\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dsantana.uas.edu.mx\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/dsantana.uas.edu.mx\/index.php\/wp-json\/wp\/v2\/comments?post=2395"}],"version-history":[{"count":4,"href":"https:\/\/dsantana.uas.edu.mx\/index.php\/wp-json\/wp\/v2\/posts\/2395\/revisions"}],"predecessor-version":[{"id":2407,"href":"https:\/\/dsantana.uas.edu.mx\/index.php\/wp-json\/wp\/v2\/posts\/2395\/revisions\/2407"}],"wp:attachment":[{"href":"https:\/\/dsantana.uas.edu.mx\/index.php\/wp-json\/wp\/v2\/media?parent=2395"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dsantana.uas.edu.mx\/index.php\/wp-json\/wp\/v2\/categories?post=2395"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dsantana.uas.edu.mx\/index.php\/wp-json\/wp\/v2\/tags?post=2395"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}