Debug di MQTT su websocket su Envoy 1.28.0
Ho migrato la nostra installazione di Envoy da Envoy 1.11.1 a 1.28.0 e ora sto usando anche SNI per selezionare il certificato corretto.
Una parte importante di questa migrazione è l'aggiornamento della sintassi della configurazione di Envoy dall'API v2 all'API v3.
L'aggiornamento è andato bene, tranne che per il nostro servizio MQTT basato su websocket (basato su VerneMQ) che non funziona come previsto.
All'inizio ho pensato che il problema fosse in envoy. Dopo aver provato molte opzioni di timeout e aver consultato la documentazione di envoy, ho deciso di sperimentare una nuova rotta e un diverso broker (Mosquitto) dietro di essa.
La seguente configurazione funziona con Mosquitto come broker, nel caso in cui qualcun altro si imbatta nello stesso problema.
Ecco un estratto del mio envoy.yaml (la configurazione completa è di oltre 87000 righe, generate da uno script template, a causa dell'SNI e della necessità di avere singoli ascoltatori per dominio, come ho detto sopra):
risorse_statiche:
ascoltatori:
- indirizzo:
socket_address:
indirizzo: 0.0.0.0
valore_porta: 443
limite_buffer_per_connessione_byte: 32768 # 32 KiB
filtri_ascoltatore:
- nome: tls_inspector
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.listener.tls_inspector.v3.TlsInspector
catene_di_filtro:
- filter_chain_match:
nomi_server: ["picockpit.com", "www.picockpit.com", "picockpit.com:443", "www.picockpit.com:443"]
transport_socket:
nome: 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:
- nome: envoy.filters.network.http_connection_manager
typed_config:
'@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
prefisso_statale: ingress_http
codec_type: AUTO
http_filters:
- nome: envoy.filters.http.compressor
typed_config:
'@type': type.googleapis.com/envoy.extensions.filters.http.compressor.v3.Compressor
compressore_library:
nome: text_optimized
typed_config:
'@type': type.googleapis.com/envoy.extensions.compression.gzip.compressor.v3.Gzip
livello_di_compressione: BEST_SPEED
strategia di compressione: DEFAULT_STRATEGY
livello_memoria: 9
bit_finestra: 15
chunk_size: 16384
- nome: 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 ora
use_remote_address: true
xff_num_trusted_hops: 0
route_config:
virtual_hosts:
- nome: backend
domini: ["picockpit.com", "www.picockpit.com", "picockpit.com:443", "www.picockpit.com:443"]
percorsi:
- match: { percorso: "/pidoctor"}
redirect:
path_redirect: "/raspberry-pi/pidoctor-raspberry-pi-system-health-monitor/"
- match: { prefisso: "/pidoctor/"}
redirect:
path_redirect: "/raspberry-pi/pidoctor-raspberry-pi-system-health-monitor/"
- match: { prefisso: "/mqtt/test" }
route:
prefisso_rewrite: "/mqtt"
cluster: target_test
timeout: 0s
idle_timeout: 0s
upgrade_configs:
- upgrade_type: "websocket"
abilitato: vero
- match: { prefisso: "/" }
route:
cluster: target_main
timeout: 0s
cluster:
- nome: target_test
timeout di connessione: 5s
limite_buffer_per_connessione_bytes: 32768 # 32 KiB
tipo: STRICT_DNS
lb_policy: ROUND_ROBIN
assegnazione del carico:
nome_cluster: target_test
endpoint:
- lb_endpoints:
- endpoint:
indirizzo:
socket_address:
indirizzo: mosquitto-test.test-network
valore_porta: 8025
Si noti che ho omesso gran parte della configurazione di altri servizi, delle rotte e non ho fornito le informazioni sul cluster target_main (perché è irrilevante per la situazione MQTT su websocket).
Si noti il valore timeout: 0s, importante perché le connessioni MQTT continuino invece di essere interrotte dopo 15 secondi, come avviene di default.
Ho anche evidenziato altre parti che, a mio parere, sono rilevanti per consentire l'aggiornamento delle connessioni a websocket (in modo che MQTT possa essere trasportato attraverso di esse). Si noti anche l'opzione numeri di porta che vengono passati come corrispondenze di dominio aggiuntive.
Mosquitto docker-compose.yml:
versione: '3.6'
servizi:
mosquitto:
immagine: eclipse-mosquitto
nome_contenitore: mosquitto-test
nome host: mosquitto-test
reti:
- test_net
riavvio: "no"
utente: "root:root"
volumi:
- tipo: bind
sorgente: ./mosquitto.conf
destinazione: /mosquitto/config/mosquitto.conf
reti:
test_net:
esterno:
nome: rete-test
mosquitto.conf:
ascoltatore 8025
protocollo websockets
allow_anonymous true
log_type all
Strumento utilizzato per verificare la connessione:
Aggiornamento 13.11.2023
MQTT è di nuovo online, con anche VerneMQ:
Ho riavviato VerneMQ diverse volte, ma a quanto pare non ho aspettato abbastanza perché si stabilizzasse. Un collega lo ha riavviato oggi e ora funziona. Sembra che ci vogliano 10-15 minuti (nella nostra configurazione) per diventare completamente reattivo e funzionare in modo appropriato.
Posso quindi confermare che la configurazione di cui sopra per envoy funziona anche con VerneMQ.
Lezione imparata
Se qualcosa non funziona, provare a replicare il problema nell'interazione con un altro strumento - se funziona lì, forse il problema non è nel primo strumento che avete cambiato, ma nel secondo strumento con cui deve funzionare.
e alcune chicche aggiuntive:
Documentazione online
- https://www.envoyproxy.io/docs
- https://www.envoyproxy.io/docs/envoy/v1.28.0/ (in particolare per la versione attuale di envoy)
- https://github.com/envoyproxy/envoy/blob/main/configs/envoyproxy_io_proxy_http3_downstream.yaml - esempio di configurazione HTTP3
- https://codilime.com/blog/envoy-configuration/ - comprensione dell'inviato
- https://pi3g.com/envoy-docker-and-websockets-debugging-and-configuration/ - su websocket ed envoy (i websocket sono usati in PiCockpit per trasportare MQTT) - questo articolo precedente è basato sulla v1.11.1 di envoy
Strumenti utili
- https://http3check.net/ - permette di verificare il supporto di HTTP/3
- Client websocket HiveMQ