MQTT debuggen via websockets op Envoy 1.28.0

Ik heb onze Envoy-installatie gemigreerd van Envoy 1.11.1 naar 1.28.0 en gebruik nu ook SNI voor het selecteren van het juiste certificaat.

Een groot deel van die migratie is het upgraden van de syntax van de configuratie voor Envoy van de v2 API naar de v3 API.

De upgrade ging goed, behalve dat onze websocket-gebaseerde MQTT service (gebaseerd op VerneMQ) niet werkte zoals verwacht.

In eerste instantie nam ik aan dat het probleem in envoy zat. Na veel time-out opties geprobeerd te hebben, en de envoy documentatie bekeken te hebben, heb ik besloten om te experimenteren met een nieuwe route, en een andere broker (Mosquitto) erachter.

De volgende configuratie werkt met Mosquitto als broker, voor het geval iemand anders tegen hetzelfde probleem aanloopt.

Hier is een uittreksel van mijn envoy.yaml (de volledige configuratie is meer dan 87000 regels, gegenereerd door een sjabloon script, vanwege de SNI en het hebben van individuele luisteraars per domein zoals ik hierboven vermeldde):

statische_bronnen:
  luisteraars:
  - adres:
      socket_adres:
        address: 0.0.0.0
        poort_waarde: 443
    per_verbinding_buffer_limiet_bytes: 32768 # 32 KiB
    listener_filters:
    - naam: tls_inspector
      getypt_config:
        "@type": type.googleapis.com/envoy.extensions.filters.listener.tls_inspector.v3.TlsInspector
    filter_ketens:
    - filter_chain_match:
        server_namen: ["picockpit.com","www.picockpit.com","picockpit.com:443","www.picockpit.com:443"]
      transport_socket:
        naam: envoy.transport_sockets.tls
        getypt_config:
          "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext
          gemeenschappelijke_tls_context:
            tls_certificaten:
            - certificate_chain: { bestandsnaam: "/certs/letsencrypt/live/picockpit.com/fullchain.pem" }
              private_key: { bestandsnaam: "/certs/letsencrypt/live/picockpit.com/privkey.pem" }
            alpn_protocollen: [ "h2,http/1.1" ]
      filters:
      - naam: envoy.filters.network.http_connection_manager
        getypt_config:
          '@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
          stat_prefix: ingress_http
          codec_type: AUTO

          http_filters:
          - naam: envoy.filters.http.compressor
            getypt_config:
              '@type': type.googleapis.com/envoy.extensions.filters.http.compressor.v3.Compressor
              compressor_bibliotheek:
                naam: tekst_geoptimaliseerd
                getypt_config:
                  '@type': type.googleapis.com/envoy.extensions.compression.gzip.compressor.v3.Gzip
                  compressie_niveau: BEST_SPEED
                  compressie_strategie: STANDAARD_STRATEGIE
                  geheugenniveau: 9
                  window_bits: 15
                  brok_grootte: 16384
          - naam: envoy.filters.http.router
            getypt_config:
             "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
          gemeenschappelijke_http_protocol_opties:
            idle_timeout: 3600s # 1 uur

          gebruik_remote_adres: waar
          xff_num_trusted_hops: 0
          route_config:
            virtual_hosts:
            - naam: backend
              domeinen: ["picockpit.com", "www.picockpit.com", "picockpit.com:443", "www.picockpit.com:443"]
              routes:

              - match: {pad: "/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: doel_test
                  timeout: 0s
                  idle_timeout: 0s
                  upgrade_configuraties:
                    - upgrade_type: "websocket".
                      ingeschakeld: waar
                      
              - match: { prefix: "/" }
                route:
                  cluster: doel_hoofd
                  time-out: 0s
  clusters:

    - naam: doel_test
      verbindingstijd: 5s
      per_verbinding_buffer_limiet_bytes: 32768 # 32 KiB
      type: STRICT_DNS
      lb_beleid: ROUND_ROBIN
      load_assignment:
        cluster_naam: doel_test
        eindpunten:
        - lb_endpoints:
          - eindpunt:
              adres:
                socket_adres:
                  adres: mosquitto-test.test-netwerk
                  poort_waarde: 8025

Merk op dat ik een groot deel van de configuratie van andere diensten, routes, heb weggelaten en dat ik de target_main clusterinformatie niet heb gegeven (omdat deze irrelevant is voor de MQTT over websockets situatie).

Let op de timeout: 0s waarde, die belangrijk is voor MQTT verbindingen om door te gaan in plaats van te worden getimed na 15sec zoals standaard het geval is.

Ik heb ook andere delen gemarkeerd die naar mijn mening relevant zijn om verbindingen te upgraden naar websockets (zodat MQTT er doorheen kan). Let ook op de poortnummers worden doorgegeven als extra domeinovereenkomsten.

Mosquitto docker-compose.yml:

versie: "3.6

diensten:
  mosquitto:
    image: eclipse-mosquitto
    containernaam: mosquitto-test
    hostnaam: mosquitto-test
    netwerken:

      - test_net
    herstarten: "nee
    gebruiker: "root:root"
    volumes:
      - type: binden
        bron: ./mosquitto.conf
        doel: /mosquitto/config/mosquitto.conf


netwerken:

  test_net:
    extern:
      naam: test-netwerk


mosquitto.conf:

luisteraar 8025
protocol websockets

allow_anonymous true
log_type alle

Tool om de verbinding te controleren:

HiveMQ websocket-client

Update 13.11.2023

MQTT is weer online, ook met VerneMQ:

Hoewel ik VerneMQ verschillende keren opnieuw had opgestart, had ik blijkbaar niet lang genoeg gewacht om het te stabiliseren. Een collega herstartte het vandaag en nu werkt het. Het lijkt erop dat het 10 - 15 minuten duurt (in onze setup) om volledig responsief te worden en goed te werken.

Daarom kan ik bevestigen dat de bovenstaande configuratie voor envoy ook werkt met VerneMQ.

Geleerde les

Als iets niet werkt, probeer het probleem te reproduceren in de wisselwerking met een ander hulpmiddel - Als het daar werkt, dan zit het probleem mogelijk niet in het eerste gereedschap dat u hebt gewijzigd, maar in het tweede gereedschap waarmee het moet werken.

en nog wat extra lekkers:

Online Documentatie

Handige hulpmiddelen