Débogage de MQTT sur websockets sur Envoy 1.28.0
J'ai migré notre installation Envoy de la version 1.11.1 à la version 1.28.0, et j'utilise maintenant aussi SNI pour sélectionner le bon certificat.
Une grande partie de cette migration consiste à mettre à jour la syntaxe de la configuration d'Envoy de l'API v2 à l'API v3.
La mise à jour s'est bien déroulée, à l'exception de notre service MQTT basé sur websocket (basé sur VerneMQ) qui ne fonctionnait pas comme prévu.
J'ai d'abord supposé que le problème venait d'envoy. Après avoir essayé plusieurs options de timeout, et consulté la documentation d'envoy, j'ai décidé d'expérimenter une nouvelle route, et un broker différent (Mosquitto) derrière elle.
La configuration suivante fonctionne avec Mosquitto en tant que courtier, au cas où quelqu'un d'autre rencontrerait le même problème.
Voici un extrait de mon envoy.yaml (la configuration complète fait plus de 87000 lignes, générées par un script template, à cause du SNI et de la nécessité d'avoir des listeners individuels par domaine comme je l'ai mentionné plus haut) :
static_resources :
auditeurs :
- adresse :
adresse_socket :
adresse : 0.0.0.0
valeur_du_port : 443
limite_de_tampon_par_connexion_bytes : 32768 # 32 KiB
listener_filters :
- name : tls_inspector
typed_config :
"@type" : type.googleapis.com/envoy.extensions.filters.listener.tls_inspector.v3.TlsInspector
filter_chains :
- filter_chain_match :
server_names : ["picockpit.com", "www.picockpit.com", "picockpit.com:443", "www.picockpit.com:443"]
transport_socket :
name : envoy.transport_sockets.tls
typed_config :
"@type" : type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext
common_tls_context :
tls_certificates :
- certificate_chain : { filename : "/certs/letsencrypt/live/picockpit.com/fullchain.pem" }
private_key : { filename : "/certs/letsencrypt/live/picockpit.com/privkey.pem" }
alpn_protocols : [ "h2,http/1.1" ]
filters :
- name : 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 :
- name : 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
niveau_de_compression : BEST_SPEED
compression_strategy : DEFAULT_STRATEGY
niveau_mémoire : 9
window_bits : 15
taille_du_chunk : 16384
- nom : 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 heure
use_remote_address : true
xff_num_trusted_hops : 0
route_config :
virtual_hosts :
- name : backend
domains : ["picockpit.com", "www.picockpit.com", "picockpit.com:443", "www.picockpit.com:443"]
routes :
- match : { path : "/pidoctor"}
redirect :
path_redirect : "/raspberry-pi/pidoctor-raspberry-pi-system-health-monitor/"
- match : { prefix : "/pidoctor/"}
redirect :
path_redirect : "/raspberry-pi/pidoctor-raspberry-pi-system-health-monitor/"
- match : { prefix : "/mqtt/test" }
route :
prefix_rewrite : "/mqtt"
cluster : target_test
timeout : 0s
idle_timeout : 0s
upgrade_configs :
- upgrade_type : "websocket"
enabled : true
- match : { prefix : "/" }
route :
cluster : target_main
timeout : 0s
clusters :
- name : target_test
connect_timeout : 5s
per_connection_buffer_limit_bytes : 32768 # 32 KiB
type : STRICT_DNS
lb_policy : ROUND_ROBIN
load_assignment :
nom_du_cluster : target_test
endpoints :
- lb_endpoints :
- endpoint :
adresse :
adresse_socket :
adresse : mosquitto-test.test-network
valeur_du_port : 8025
Notez que j'ai omis une grande partie de la configuration des autres services, des routes, et que je ne vous ai pas donné les informations sur le cluster target_main (parce qu'elles ne sont pas pertinentes pour la situation MQTT over websockets).
Remarquez la valeur de timeout : 0s, ce qui est important pour que les connexions MQTT continuent au lieu d'être interrompues au bout de 15 secondes comme c'est le cas par défaut.
J'ai également mis en évidence d'autres parties qui sont, à mon avis, pertinentes pour permettre aux connexions d'être mises à niveau vers des websockets (de sorte que MQTT puisse être transporté à travers eux). Notez également le numéros de port sont transmises en tant que correspondances de domaines supplémentaires.
Mosquitto docker-compose.yml :
version : '3.6'
services :
mosquitto :
image : eclipse-mosquitto
nom_du_conteneur : mosquitto-test
nom d'hôte : mosquitto-test
réseaux :
- test_net
restart : "no
user : "root:root"
volumes :
- type : bind
source : ./mosquitto.conf
target : /mosquitto/config/mosquitto.conf
réseaux :
test_net :
externe :
name : test-network
mosquitto.conf :
auditeur 8025
protocole websockets
allow_anonymous true
log_type all
Outil utilisé pour vérifier la connexion :
Mise à jour 13.11.2023
MQTT est de nouveau en ligne, avec VerneMQ également :
Alors que j'avais redémarré VerneMQ plusieurs fois, je n'ai apparemment pas attendu assez longtemps pour qu'il se stabilise. Un collègue l'a redémarré aujourd'hui et il fonctionne désormais. Il semble qu'il faille 10 à 15 minutes (dans notre configuration) pour que VerneMQ devienne totalement réactif et fonctionne correctement.
Je peux donc confirmer que la configuration ci-dessus pour envoy fonctionne également avec VerneMQ.
Leçon apprise
Si quelque chose ne fonctionne pas, essayer de reproduire le problème dans l'interaction avec un autre outil - si cela fonctionne, il est possible que le problème ne vienne pas du premier outil que vous avez modifié, mais du second avec lequel il doit fonctionner.
et quelques autres produits :
Documentation en ligne
- https://www.envoyproxy.io/docs
- https://www.envoyproxy.io/docs/envoy/v1.28.0/ (spécifiquement pour la version actuelle d'envoy)
- https://github.com/envoyproxy/envoy/blob/main/configs/envoyproxy_io_proxy_http3_downstream.yaml - exemple de configuration HTTP3
- https://codilime.com/blog/envoy-configuration/ - Envoyé compréhensif
- https://pi3g.com/envoy-docker-and-websockets-debugging-and-configuration/ - sur les websockets et envoy (les websockets sont utilisés dans PiCockpit pour transporter MQTT) - cet article précédent est basé sur la v1.11.1 d'envoy
Outils utiles
- https://http3check.net/ - permet de vérifier la prise en charge de HTTP/3
- Client websocket HiveMQ