Depurando MQTT sobre websockets en Envoy 1.28.0
He migrado nuestra instalación de Envoy de Envoy 1.11.1 a 1.28.0, y ahora también utilizo SNI para seleccionar el certificado correcto.
Gran parte de esa migración consiste en actualizar la sintaxis de la configuración de Envoy de la API v2 a la API v3.
La actualización fue bien, excepto porque nuestro servicio MQTT basado en websocket (basado en VerneMQ) no funcionaba como esperábamos.
Al principio supuse que el problema estaba en envoy. Después de probar muchas opciones de tiempo de espera, y mirando a la documentación envoy, He decidido experimentar con una nueva ruta, y un corredor diferente (Mosquitto) detrás de él.
La siguiente configuración funciona con Mosquitto como broker, por si alguien más tropieza con el mismo problema.
Aquí hay un extracto de mi envoy.yaml (la configuración completa tiene más de 87000 líneas, generadas por un script de plantilla, debido al SNI y a tener que tener escuchas individuales por dominio como mencioné anteriormente):
recursos_estáticos:
oyentes:
- address:
socket_address:
address: 0.0.0.0
valor_puerto: 443
per_connection_buffer_limit_bytes: 32768 # 32 KiB
listener_filters:
- name: tls_inspector
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.listener.tls_inspector.v3.TlsInspector
cadenas_de_filtro:
- filter_chain_match:
server_names: ["picockpit.com", "www.picockpit.com", "picockpit.com:443", "www.picockpit.com:443"]
transport_socket:
nombre: envoy.transport_sockets.tls
typed_config:
"@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext
common_tls_context:
tls_certificates:
- cadena_certificados: { nombre_archivo: "/certs/letsencrypt/live/picockpit.com/fullchain.pem" }
clave_privada: { nombre_archivo: "/certs/letsencrypt/live/picockpit.com/privkey.pem" }
alpn_protocols: [ "h2,http/1.1" ]
filters:
- nombre: envoy.filters.network.http_connection_manager
typed_config:
'@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
stat_prefix: ingress_http
codec_type: AUTO
http_filters
- nombre: envoy.filters.http.compressor
typed_config:
'@type': type.googleapis.com/envoy.extensions.filters.http.compressor.v3.Compressor
compressor_library:
name: text_optimized
typed_config:
'@type': type.googleapis.com/envoy.extensions.compression.gzip.compressor.v3.Gzip
nivel_compresión: BEST_SPEED
estrategia_compresión: DEFAULT_STRATEGY
nivel_memoria: 9
bits_ventana: 15
chunk_size: 16384
- nombre: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
common_http_protocol_options:
idle_timeout: 3600s # 1 hora
use_remote_address: true
xff_num_trusted_hops: 0
route_config:
virtual_hosts:
- name: backend
dominios: ["picockpit.com", "www.picockpit.com", "picockpit.com:443", "www.picockpit.com:443"]
rutas:
- coinciden: { ruta: "/pidoctor"}
redirect:
path_redirect: "/raspberry-pi/pidoctor-raspberry-pi-system-health-monitor/"
- coincidencia: { prefix: "/pidoctor/"}
redirigir:
path_redirect: "/raspberry-pi/pidoctor-raspberry-pi-system-health-monitor/"
- match: { prefix: "/mqtt/test" }
route:
prefix_rewrite: "/mqtt"
clúster: target_test
tiempo de espera: 0s
idle_timeout: 0s
upgrade_configs:
- upgrade_type: "websocket"
enabled: true
- coincidencia: { prefijo: "/" }
ruta:
cluster: target_main
tiempo de espera: 0s
clusters:
- nombre: target_test
connect_timeout: 5s
per_connection_buffer_limit_bytes: 32768 # 32 KiB
type: STRICT_DNS
lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: target_test
puntos_finales:
- lb_endpoints:
- endpoint:
address
socket_address:
dirección: mosquitto-test.test-network
valor_puerto: 8025
Ten en cuenta que he omitido gran parte de la configuración de otros servicios, rutas, y no te he dado la información del cluster target_main (porque es irrelevante para la situación de MQTT sobre websockets).
Observe el valor timeout: 0s valor, que es importante para las conexiones MQTT para continuar en lugar de ser el tiempo de espera después de 15seg como es el valor predeterminado.
También he resaltado otras partes que son, en mi opinión, relevantes para permitir que las conexiones se actualicen a websockets (para que MQTT pueda ser transportado a través de ellas). Tenga en cuenta también la números de puerto como coincidencias de dominio adicionales.
Mosquitto docker-compose.yml:
versión: '3.6
servicios:
mosquitto:
imagen: eclipse-mosquitto
nombre_contenedor: mosquitto-test
nombre_host: mosquitto-test
redes:
- test_net
reiniciar: "no"
usuario: "root:root"
volúmenes:
- tipo: bind
fuente: ./mosquitto.conf
target: /mosquitto/config/mosquitto.conf
redes:
test_net:
externa:
nombre: red_prueba
mosquitto.conf:
receptor 8025
protocolo websockets
allow_anonymous true
log_type todos
Herramienta utilizada para verificar la conexión:
Actualización 13.11.2023
MQTT está en línea de nuevo, con VerneMQ también:
Aunque había reiniciado VerneMQ varias veces, aparentemente no esperé lo suficiente para que se estabilizara. Un colega lo reinició hoy, y ahora funciona. Parece que tarda entre 10 y 15 minutos (en nuestra configuración) en responder y funcionar correctamente.
Por lo tanto, puedo confirmar que la configuración anterior para envoy también funciona con VerneMQ.
Lección aprendida
Si algo no funciona, intentar reproducir el problema en la interacción con otra herramienta - si ahí funciona, posiblemente el problema no esté en la primera herramienta que has cambiado, sino en la segunda con la que tiene que funcionar.
y algunas golosinas adicionales:
Documentación en línea
- https://www.envoyproxy.io/docs
- https://www.envoyproxy.io/docs/envoy/v1.28.0/ (específicamente para la versión actual de envoy)
- https://github.com/envoyproxy/envoy/blob/main/configs/envoyproxy_io_proxy_http3_downstream.yaml - ejemplo de configuración HTTP3
- https://codilime.com/blog/envoy-configuration/ - comprensión Enviado
- https://pi3g.com/envoy-docker-and-websockets-debugging-and-configuration/ - sobre websockets y envoy (websockets se utilizan en PiCockpit para transportar MQTT) - este artículo anterior se basa en v1.11.1 de envoy
Herramientas útiles
- https://http3check.net/ - permite comprobar la compatibilidad con HTTP/3
- Cliente de websocket HiveMQ