在 Envoy 1.28.0 上调试通过 websockets 传输的 MQTT

我已将我们的 Envoy 安装从 Envoy 1.11.1 迁移到 1.28.0,现在也使用 SNI 来选择正确的证书。

迁移的一个重要部分是将 Envoy 配置的语法从 v2 API 升级到 v3 API。

升级进行得很顺利,除了我们基于 WebSocket 的 MQTT 服务(基于 VerneMQ)不能按预期运行。

起初我以为问题出在 envoy 上。在尝试了许多超时选项并查阅了 envoy 文档后,我决定使用新的路由和背后的不同代理(Mosquitto)进行实验。

以下配置适用于作为代理的 Mosquitto,以防其他人遇到同样的问题。

下面是我的 envoy.yaml 摘录(完整配置超过 87000 行,由模板脚本生成,因为 SNI 和我上面提到的每个域必须有单独的侦听器):

静态资源:
  listeners:
  - address:
      socket_address:
        address:0.0.0.0
        port_value: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
    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:自动

          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
                  压缩级别BEST_SPEED
                  compression_strategy:default_strategy
                  memory_level: 9
                  window_bits:15
                  chunk_size: 16384
          - name: 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 小时

          use_remote_address: true
          xff_num_trusted_hops:0
          route_config:
            virtual_hosts:
            - 名称: 后台
              域:["picockpit.com", "www.picockpit.com", "picockpit.com:443","www.picockpit.com:443"]
              路由:

              - match:{ path:"/pidoctor"}
                重定向:
                  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"
                  集群: target_test
                  timeout:0s
                  空闲超时:0s
                  升级配置:
                    - upgrade_type:"websocket
                      enabled: true
                      
              - match:{ prefix:"/" }
                路由:
                  cluster: target_main
                  timeout:0s
  集群:

    - 名称: target_test
      connect_timeout:5s
      per_connection_buffer_limit_bytes:32768 # 32 千字节
      类型: STRICT_DNSSTRICT_DNS
      lb_policy:ROUND_ROBIN
      load_assignment:
        集群名称: target_test
        endpoints:
        - lb_endpoints:
          - endpoint:
              address:
                socket_address:
                  address: mosquitto-test.test-network
                  port_value: 8025

请注意,我省略了其他服务和路由的大部分配置,也没有提供 target_main 集群信息(因为它与通过 websockets 的 MQTT 情况无关)。

注意超时:0s 值,这对 MQTT 连接的继续很重要,而不是像默认值那样在 15 秒后超时。

我还强调了我认为与允许连接升级为 websockets(以便通过它们传输 MQTT)相关的其他部分。还请注意 端口号 作为额外的匹配域输入。

Mosquitto docker-compose.yml:

版本:'3.6

服务
  mosquitto:
    image: eclipse-mosquitto
    container_name: mosquitto-test
    hostname: mosquitto-test
    networks:

      - test_net
    restart:"no
    user:"root:root
    卷:
      - 类型:绑定
        源: ./mosquitto.conf
        目标: /mosquitto/config/mosquitto.conf/mosquitto/config/mosquitto.conf


网络

  test_net:
    external:
      名称: test-network


mosquitto.conf:

监听器 8025
协议 websockets

allow_anonymous true
日志类型 all

用于验证连接的工具:

HiveMQ websocket 客户端

2023 年 11 月 13 日更新

MQTT 又上线了,还有 VerneMQ:

虽然我曾多次重启 VerneMQ,但显然没有等足够长的时间让它稳定下来。今天我的一位同事重新启动了 VerneMQ,它现在可以正常工作了。看来,它需要 10 - 15 分钟(在我们的设置中)才能完全响应并正常工作。

因此,我可以确认上述 envoy 配置也适用于 VerneMQ。

经验教训

如果有什么问题、 尝试用另一种工具复制交互过程中的问题 - 如果它能在那里工作,那么问题可能不在你更改的第一个工具上,而在它需要与之配合的第二个工具上。

和一些额外的好东西:

在线文档

实用工具