{"id":29897,"date":"2023-11-12T22:44:57","date_gmt":"2023-11-12T21:44:57","guid":{"rendered":"https:\/\/pi3g.com\/?p=29897"},"modified":"2023-11-13T09:24:21","modified_gmt":"2023-11-13T08:24:21","slug":"debugging-mqtt-over-websockets-on-envoy-1-28-0","status":"publish","type":"post","link":"https:\/\/pi3g.com\/de\/debugging-mqtt-over-websockets-on-envoy-1-28-0\/","title":{"rendered":"Debuggen von MQTT \u00fcber Websockets auf Envoy 1.28.0"},"content":{"rendered":"<p>Ich habe unsere Envoy-Installation von Envoy 1.11.1 auf 1.28.0 migriert und verwende nun auch SNI zur Auswahl des richtigen Zertifikats. <\/p>\n\n\n\n<p>Ein gro\u00dfer Teil dieser Migration ist die Aktualisierung der Syntax der Konfiguration f\u00fcr Envoy von der API v2 auf die API v3. <\/p>\n\n\n\n<p>Das Upgrade verlief gut, au\u00dfer dass unser Websocket-basierter MQTT-Dienst (basierend auf VerneMQ) nicht wie erwartet funktionierte.<\/p>\n\n\n\n<p>Zuerst nahm ich an, dass das Problem in envoy lag. Nachdem ich viele Timeout-Optionen ausprobiert und mir die envoy-Dokumentation angesehen habe, habe ich beschlossen, mit einer neuen Route und einem anderen Broker (Mosquitto) zu experimentieren. <\/p>\n\n\n\n<p><strong>Die folgende Konfiguration funktioniert mit Mosquitto als Broker, f\u00fcr den Fall, dass jemand anderes \u00fcber das gleiche Problem stolpert.<\/strong><\/p>\n\n\n\n<p>Hier ein Auszug aus meiner envoy.yaml (die vollst\u00e4ndige Konfiguration besteht aus \u00fcber 87000 Zeilen, die von einem Template-Skript generiert werden, wegen der SNI und der Notwendigkeit, individuelle Listener pro Domain zu haben, wie ich oben erw\u00e4hnt habe): <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>statische_Ressourcen:\n  H\u00f6rer:\n  - Adresse:\n      socket_address:\n        Adresse: 0.0.0.0\n        port_value: 443\n    per_connection_buffer_limit_bytes: 32768 # 32 KiB\n    Listener_Filter:\n    - name: tls_inspector\n      typed_config:\n        \"@type\": type.googleapis.com\/envoy.extensions.filters.listener.tls_inspector.v3.TlsInspector\n    filter_chains:\n    - filter_chain_match:\n        server_names: [\"picockpit.com\", \"www.picockpit.com\", \"picockpit.com<strong>:443<\/strong>\", \"www.picockpit.com<strong>:443<\/strong>\"]\n      transport_socket:\n        Name: envoy.transport_sockets.tls\n        typed_config:\n          \"@type\": type.googleapis.com\/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext\n          common_tls_context:\n            tls_certificates:\n            - certificate_chain: { filename: \"\/certs\/letsencrypt\/live\/picockpit.com\/fullchain.pem\" }\n              private_key: { dateiname: \"\/certs\/letsencrypt\/live\/picockpit.com\/privkey.pem\" }\n            alpn_protocols: [ \"h2,http\/1.1\" ]\n      filter:\n      - name: envoy.filters.network.http_connection_manager\n        typed_config:\n          '@type': type.googleapis.com\/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager\n          stat_pr\u00e4fix: ingress_http\n          codec_type: AUTO\n\n          http_filters:\n          - Name: envoy.filters.http.compressor\n            typed_config:\n              '@type': type.googleapis.com\/envoy.extensions.filters.http.compressor.v3.Compressor\n              compressor_library:\n                name: text_optimiert\n                typed_config:\n                  '@type': type.googleapis.com\/envoy.extensions.compression.gzip.compressor.v3.Gzip\n                  komprimierungsstufe: BEST_SPEED\n                  komprimierung_strategie: DEFAULT_STRATEGY\n                  speicher_level: 9\n                  fenster_bits: 15\n                  chunk_size: 16384\n          - Name: envoy.filters.http.router\n            typed_config:\n             \"@type\": type.googleapis.com\/envoy.extensions.filters.http.router.v3.Router\n          common_http_protocol_options:\n            idle_timeout: 3600s # 1 Stunde\n\n          use_remote_address: true\n          xff_num_trusted_hops: 0\n          route_config:\n            virtual_hosts:\n            - name: backend\n              Domains: [\"picockpit.com\", \"www.picockpit.com\", \"picockpit.com<strong>:443<\/strong>\", \"www.picockpit.com<strong>:443<\/strong>\"]\n              Routen:\n\n              - match: { path: \"\/pidoctor\"}\n                redirect:\n                  path_redirect: \"\/raspberry-pi\/pidoctor-raspberry-pi-system-health-monitor\/\"\n              - match: { prefix: \"\/pidoctor\/\"}\n                redirect:\n                  path_redirect: \"\/raspberry-pi\/pidoctor-raspberry-pi-system-health-monitor\/\"\n\n\n              - match: { prefix: \"\/mqtt\/test\" }\n                route:\n                  prefix_rewrite: \"\/mqtt\"\n                  cluster: ziel_test\n<strong>                  Timeout: 0s<\/strong>\n                  idle_timeout: 0s\n<strong>                  upgrade_configs:\n                    - upgrade_type: \"Websocket\"\n                      aktiviert: true<\/strong>\n                      \n              - \u00fcbereinstimmen: { prefix: \"\/\" }\n                route:\n                  cluster: target_main\n                  Timeout: 0s\n  cluster:\n\n    - name: ziel_test\n      connect_timeout: 5s\n      per_connection_buffer_limit_bytes: 32768 # 32 KiB\n      Typ: STRICT_DNS\n      lb_policy: ROUND_ROBIN\n      load_assignment:\n        cluster_name: ziel_test\n        Endpunkte:\n        - lb_endpoints:\n          - endpoint:\n              Adresse:\n                socket_address:\n                  Adresse: mosquitto-test.test-network\n                  port_wert: 8025\n<\/code><\/pre>\n\n\n\n<p>Beachten Sie, dass ich einen gro\u00dfen Teil der Konfiguration anderer Dienste und Routen ausgelassen habe und Ihnen die target_main-Cluster-Informationen nicht gegeben habe (weil sie f\u00fcr die MQTT-\u00fcber-Websockets-Situation irrelevant sind). <\/p>\n\n\n\n<p>Beachten Sie den Wert timeout: 0s, was wichtig ist, damit MQTT-Verbindungen fortgesetzt werden k\u00f6nnen und nicht wie standardm\u00e4\u00dfig vorgesehen nach 15 Sekunden abgebrochen werden. <\/p>\n\n\n\n<p>Ich habe auch andere Teile hervorgehoben, die meiner Meinung nach relevant sind, damit Verbindungen zu Websockets aufger\u00fcstet werden k\u00f6nnen (damit MQTT \u00fcber sie \u00fcbertragen werden kann). Beachten Sie auch die <strong>Port-Nummern <\/strong>die als zus\u00e4tzliche Dom\u00e4nen\u00fcbereinstimmungen eingegeben werden. <\/p>\n\n\n\n<p><strong>Mosquitto docker-compose.yml:<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Version: '3.6'\n\nDienstleistungen:\n  mosquitto:\n    image: eclipse-mosquitto\n    container_name: mosquitto-test\n    Rechnername: mosquitto-test\n    Netzwerke:\n\n      - test_net\n    Neustart: \"nein\"\n    Benutzer: \"root:root\"\n    Datentr\u00e4ger:\n      - Typ: bind\n        Quelle: .\/mosquitto.conf\n        Ziel: \/mosquitto\/config\/mosquitto.conf\n\n\nNetzwerke:\n\n  test_net:\n    extern:\n      name: test-netze\n\n\n<\/code><\/pre>\n\n\n\n<p><strong>mosquitto.conf:<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>H\u00f6rer 8025\nProtokoll Websockets\n\nallow_anonymous wahr\nlog_type all<\/code><\/pre>\n\n\n\n<p><strong>Tool zur \u00dcberpr\u00fcfung der Verbindung:<\/strong><\/p>\n\n\n\n<p><a href=\"https:\/\/www.hivemq.com\/demos\/websocket-client\/\">HiveMQ Websocket-Client<\/a><\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"697\" src=\"https:\/\/pi3g.com\/wp-content\/uploads\/2023\/11\/image-1-1024x697.png\" alt=\"\" class=\"wp-image-29898\" srcset=\"https:\/\/pi3g.com\/wp-content\/uploads\/2023\/11\/image-1-1024x697.png 1024w, https:\/\/pi3g.com\/wp-content\/uploads\/2023\/11\/image-1-300x204.png 300w, https:\/\/pi3g.com\/wp-content\/uploads\/2023\/11\/image-1-768x523.png 768w, https:\/\/pi3g.com\/wp-content\/uploads\/2023\/11\/image-1-18x12.png 18w, https:\/\/pi3g.com\/wp-content\/uploads\/2023\/11\/image-1.png 1526w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Aktualisierung 13.11.2023<\/h2>\n\n\n\n<p>MQTT ist wieder online, auch mit VerneMQ:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"120\" src=\"https:\/\/pi3g.com\/wp-content\/uploads\/2023\/11\/image-2-1024x120.png\" alt=\"\" class=\"wp-image-29901\" srcset=\"https:\/\/pi3g.com\/wp-content\/uploads\/2023\/11\/image-2-1024x120.png 1024w, https:\/\/pi3g.com\/wp-content\/uploads\/2023\/11\/image-2-300x35.png 300w, https:\/\/pi3g.com\/wp-content\/uploads\/2023\/11\/image-2-768x90.png 768w, https:\/\/pi3g.com\/wp-content\/uploads\/2023\/11\/image-2-1536x181.png 1536w, https:\/\/pi3g.com\/wp-content\/uploads\/2023\/11\/image-2-18x2.png 18w, https:\/\/pi3g.com\/wp-content\/uploads\/2023\/11\/image-2.png 1879w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Ich hatte VerneMQ zwar mehrmals neu gestartet, aber offenbar nicht lange genug gewartet, bis es sich stabilisiert hatte. Ein Kollege hat es heute neu gestartet, und jetzt funktioniert es. Es scheint, dass es 10 - 15 Minuten braucht (in unserem Setup), um voll ansprechbar zu werden und angemessen zu arbeiten.<\/p>\n\n\n\n<p>Daher kann ich best\u00e4tigen, dass die obige Konfiguration f\u00fcr envoy auch mit VerneMQ funktioniert.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Gelernte Lektion<\/h2>\n\n\n\n<p>Wenn etwas nicht funktioniert, <strong>versuchen, das Problem im Zusammenspiel mit einem anderen Werkzeug zu reproduzieren <\/strong>- Wenn es dort funktioniert, dann liegt das Problem m\u00f6glicherweise nicht bei dem ersten Werkzeug, das Sie ge\u00e4ndert haben, sondern bei dem zweiten Werkzeug, mit dem es zusammenarbeiten muss. <\/p>\n\n\n\n<p>und einige zus\u00e4tzliche Leckereien:<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">Online-Dokumentation<\/h1>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/www.envoyproxy.io\/docs\">https:\/\/www.envoyproxy.io\/docs<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/www.envoyproxy.io\/docs\/envoy\/v1.28.0\/\">https:\/\/www.envoyproxy.io\/docs\/envoy\/v1.28.0\/<\/a> (speziell f\u00fcr die aktuelle envoy-Version)<\/li>\n\n\n\n<li><a href=\"https:\/\/github.com\/envoyproxy\/envoy\/blob\/main\/configs\/envoyproxy_io_proxy_http3_downstream.yaml\">https:\/\/github.com\/envoyproxy\/envoy\/blob\/main\/configs\/envoyproxy_io_proxy_http3_downstream.yaml<\/a> - Beispiel einer HTTP3-Konfiguration<\/li>\n\n\n\n<li><a href=\"https:\/\/codilime.com\/blog\/envoy-configuration\/\">https:\/\/codilime.com\/blog\/envoy-configuration\/<\/a> - Verst\u00e4ndnis f\u00fcr den Gesandten<\/li>\n\n\n\n<li><a href=\"https:\/\/pi3g.com\/de\/envoy-docker-and-websockets-debugging-and-configuration\/\">https:\/\/pi3g.com\/envoy-docker-and-websockets-debugging-and-configuration\/ <\/a>- \u00fcber Websockets und envoy (Websockets werden in PiCockpit verwendet, um MQTT zu transportieren) - dieser vorherige Artikel basiert auf v1.11.1 von envoy<\/li>\n<\/ul>\n\n\n\n<h1 class=\"wp-block-heading\">N\u00fctzliche Tools<\/h1>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/http3check.net\/\">https:\/\/http3check.net\/<\/a> - erm\u00f6glicht die Pr\u00fcfung auf HTTP\/3-Unterst\u00fctzung<\/li>\n\n\n\n<li><a href=\"https:\/\/www.hivemq.com\/demos\/websocket-client\/\">HiveMQ Websocket-Client<\/a><\/li>\n<\/ul>","protected":false},"excerpt":{"rendered":"<p>Ich habe unsere Envoy-Installation von Envoy 1.11.1 auf 1.28.0 migriert und verwende nun auch SNI zur Auswahl des richtigen Zertifikats. Ein gro\u00dfer Teil dieser Migration ist die Aktualisierung der Syntax der Konfiguration f\u00fcr Envoy von der v2 API auf die v3 API. Das Upgrade verlief gut, mit Ausnahme unseres Websocket-basierten MQTT-Dienstes...<\/p>","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":"","_links_to":"","_links_to_target":""},"categories":[402,467,608],"tags":[481,1056,725,602],"class_list":["post-29897","post","type-post","status-publish","format-standard","hentry","category-development","category-docker","category-vernemq","tag-envoy","tag-mqtt-over-websockets-with-envoy","tag-routing","tag-websockets"],"_links":{"self":[{"href":"https:\/\/pi3g.com\/de\/wp-json\/wp\/v2\/posts\/29897","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/pi3g.com\/de\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/pi3g.com\/de\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/pi3g.com\/de\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/pi3g.com\/de\/wp-json\/wp\/v2\/comments?post=29897"}],"version-history":[{"count":3,"href":"https:\/\/pi3g.com\/de\/wp-json\/wp\/v2\/posts\/29897\/revisions"}],"predecessor-version":[{"id":29903,"href":"https:\/\/pi3g.com\/de\/wp-json\/wp\/v2\/posts\/29897\/revisions\/29903"}],"wp:attachment":[{"href":"https:\/\/pi3g.com\/de\/wp-json\/wp\/v2\/media?parent=29897"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/pi3g.com\/de\/wp-json\/wp\/v2\/categories?post=29897"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/pi3g.com\/de\/wp-json\/wp\/v2\/tags?post=29897"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}