Saltar a contenido

Despliegue

Topología

Tres contenedores en un stack de Docker Swarm sobre un mismo nodo.

graph LR
    subgraph internet [Internet]
        OP[Operador]
    end
    subgraph cf [Cloudflare]
        ACC[Access]
    end
    subgraph swarm [Docker Swarm · red overlay]
        TUN[cloudflared]
        SIM[simulador<br/>replicas 1]
        CTL[controlador<br/>otro equipo]
    end

    OP --> ACC --> TUN
    TUN -- HTTP/WS --> SIM
    TUN -- HTTP/WS --> CTL
    CTL -- Modbus TCP 502 --> SIM
    SIM -- UDP 5100 --> CTL
Servicio Papel Réplicas
simulador Núcleo, servidor Modbus, emisor UDP, interfaz web 1, siempre
controlador Software bajo prueba, de otro equipo 1
cloudflared Túnel saliente hacia Cloudflare 1

Comunicación interna

Simulador y controlador se resuelven por nombre de servicio sobre la red overlay. El controlador abre la conexión Modbus contra simulador:502; el simulador emite UDP contra controlador:5100.

Ningún puerto de protocolo industrial se publica

Ni el 502 ni el 5100 se publican al host ni a internet (D-03). Un endpoint Modbus accesible desde fuera sería un servicio sin autenticación de ningún tipo, y no aporta nada: el único maestro vive en la misma red overlay.

Como el emisor UDP resuelve el destino por nombre, un reinicio del contenedor del controlador cambia su IP sin que haya que reconfigurar nada. El emisor debe re-resolver el nombre periódicamente, no cachear la IP de por vida: es un fallo silencioso clásico, porque UDP no avisa de que nadie escucha.

Acceso desde fuera

Solo las interfaces web salen, y salen por el túnel. cloudflared abre una conexión saliente hacia Cloudflare; no hay puertos de entrada abiertos en el nodo. Cloudflare Access se encarga de la autenticación antes de que ningún tráfico llegue al stack.

Cloudflare no ejecuta nada del emulador

Cloudflare aporta túnel y autenticación, no runtime (D-05). El núcleo no puede correr en Workers porque Workers no admite listener TCP ni emisión UDP, y ambos son interfaces nucleares de este sistema.

Consecuencias operativas

Sin alta disponibilidad. El simulador es replicas: 1 por diseño (D-02). Si el contenedor cae, la sesión en curso se pierde. Aceptable en un banco de pruebas.

La demo comparte estado. No hay aislamiento entre visitantes: todos operan el mismo radar. La interfaz debe mostrar el número de operadores conectados y atribuir cada forzado a su actor en el registro, para que un comportamiento inesperado no se atribuya al controlador cuando lo causó otra persona.

Reinicio limpio. Al arrancar, el simulador carga la configuración, abre una sesión nueva y empieza a emitir. No recupera el estado de la sesión anterior: el registro de eventos persiste en disco pero el estado de señales no. Esto es deliberado, una prueba debe empezar desde un estado conocido.

Volúmenes

Ruta Contenido Persistencia
/data/config Ficheros JSON de configuración necesaria
/data/events Base SQLite del registro de eventos necesaria
/data/scenarios Escenarios y aserciones necesaria

Reloj

Ningún timestamp del sistema sale de la hora de pared

Un ajuste NTP en el nodo Swarm haría saltar los timestamps hacia atrás en mitad de una prueba y corrompería la traza. Todo lo que se registre o se emita usa el reloj monótono del proceso. La hora de pared se guarda una sola vez, en el evento de arranque de sesión, para poder situar la sesión en el calendario.

Pendiente

El fichero stack.yml no está escrito. Lo que fija esta página son las restricciones que debe cumplir; redactarlo es tarea de la fase 1 y no tiene decisiones abiertas.