你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

使用 MQTT 客户端测试与 MQTT 代理的连接

重要

Azure Arc 启用的 Azure IoT 操作预览版目前处于预览状态。 不应在生产环境中使用此预览版软件。

在正式版推出后,需要部署新的 Azure IoT 操作安装。 无法升级预览版安装。

有关 beta 版、预览版或尚未正式发布的 Azure 功能所适用的法律条款,请参阅 Microsoft Azure 预览版的补充使用条款

本文介绍了在非生产环境中使用 MQTT 客户端测试与 MQTT 代理的连接的不同方法。

默认情况下,MQTT 代理:

  • 在端口 18883 上部署了已启用 TLS 的侦听器,服务类型为 ClusterIpClusterIp 表示只能通过 Kubernetes 群集内部访问中转站。 若要从群集外部访问中转站,则必须配置 LoadBalancerNodePort 类型的服务。

  • 仅接受 用于身份验证的 Kubernetes 服务帐户,用于从群集内部进行连接。 若要从群集外部进行连接,则必须配置不同的身份验证方法。

注意

对于生产方案,应使用 TLS 和服务帐户身份验证来保护 IoT 解决方案。 有关详细信息,请参阅:

在开始之前,请安装或配置 IoT 操作。 使用以下选项在非生产环境中通过 MQTT 客户端测试与 MQTT 代理的连接。

连接到群集内的默认侦听器

第一个选项是从群集内部进行连接。 此选项使用默认配置,无需额外的更新。 以下示例演示了如何使用普通 Alpine Linux 和常用的 MQTT 客户端(使用服务帐户和默认根 CA 证书)从群集内部进行连接。

首先,使用以下配置创建名为 client.yaml 的文件:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: mqtt-client
  namespace: azure-iot-operations
---
apiVersion: v1
kind: Pod
metadata:
  name: mqtt-client
  # Namespace must match MQTT broker BrokerListener's namespace
  # Otherwise use the long hostname: aio-broker.azure-iot-operations.svc.cluster.local
  namespace: azure-iot-operations
spec:
  # Use the "mqtt-client" service account created from above
  # Otherwise create it with `kubectl create serviceaccount mqtt-client -n azure-iot-operations`
  serviceAccountName: mqtt-client
  containers:
    # Mosquitto and mqttui on Alpine
  - image: alpine
    name: mqtt-client
    command: ["sh", "-c"]
    args: ["apk add mosquitto-clients mqttui && sleep infinity"]
    volumeMounts:
    - name: broker-sat
      mountPath: /var/run/secrets/tokens
    - name: trust-bundle
      mountPath: /var/run/certs
  volumes:
  - name: broker-sat
    projected:
      sources:
      - serviceAccountToken:
          path: broker-sat
          audience: aio-internal # Must match audience in BrokerAuthentication
          expirationSeconds: 86400
  - name: trust-bundle
    configMap:
      name: azure-iot-operations-aio-ca-trust-bundle # Default root CA cert

然后,使用 kubectl 部署该配置。 应只需几秒钟即可启动。

kubectl apply -f client.yaml

运行 Pod 后,使用 kubectl exec 在 Pod 中运行命令。

例如,若要将消息发布到中转站,请在 Pod 中打开 shell:

kubectl exec --stdin --tty mqtt-client --namespace azure-iot-operations -- sh

在 Pod 的 shell 中运行以下命令,以将消息发布到中转站:

mosquitto_pub --host aio-broker --port 18883 --message "hello" --topic "world" --debug --cafile /var/run/certs/ca.crt -D CONNECT authentication-method 'K8S-SAT' -D CONNECT authentication-data $(cat /var/run/secrets/tokens/broker-sat)

输出应如下所示:

Client (null) sending CONNECT
Client (null) received CONNACK (0)
Client (null) sending PUBLISH (d0, q0, r0, m1, 'world', ... (5 bytes))
Client (null) sending DISCONNECT

mosquitto 客户端使用装载在 /var/run/secrets/tokens/broker-sat 的服务帐户令牌向中转站进行身份验证。 令牌的有效期为 24 小时。 客户端还使用安装在 /var/run/certs/ca.crt 的默认根 CA 证书来验证中转站的 TLS 证书链。

提示

你可以使用 kubectl 下载默认根 CA 证书,以与其他客户端一起使用。 例如,若要将默认根 CA 证书下载到名为 ca.crt 的文件,请使用以下代码:

kubectl get configmap azure-iot-operations-aio-ca-trust-bundle -n azure-iot-operations -o jsonpath='{.data.ca\.crt}' > ca.crt

若要订阅主题,请运行以下命令:

mosquitto_sub --host aio-broker --port 18883 --topic "world" --debug --cafile /var/run/certs/ca.crt -D CONNECT authentication-method 'K8S-SAT' -D CONNECT authentication-data $(cat /var/run/secrets/tokens/broker-sat)

输出应如下所示:

Client (null) sending CONNECT
Client (null) received CONNACK (0)
Client (null) sending SUBSCRIBE (Mid: 1, Topic: world, QoS: 0, Options: 0x00)
Client (null) received SUBACK
Subscribed (mid: 1): 0

mosquitto 客户端使用相同的服务帐户令牌和根 CA 证书向中转站进行身份验证并订阅主题。

若要删除 Pod,请运行 kubectl delete pod mqtt-client -n azure-iot-operations

从群集外部连接客户端

由于默认代理侦听器已设置为 ClusterIp 服务类型,因此你无法直接从群集外部连接到代理。 为了防止内部 Azure IoT 操作组件之间的通信意外中断,我们建议将默认侦听器保持不变并专用于 AIO 内部通信。 虽然可以创建单独的 Kubernetes LoadBalancer 服务来公开群集 IP 服务,但最好创建具有不同设置(例如更常见的 MQTT 端口 1883 和 8883)的单独侦听器,以避免混淆和潜在的安全风险。

节点端口

测试连接的最简单方法是在侦听器中使用 NodePort 服务类型。 因此可以使用 <nodeExternalIP>:<NodePort> 进行连接,正如 kubernetes 文档 中所述。

例如,要创建一个新的代理侦听器,其节点端口服务类型侦听端口 1883:

  1. 在 Azure 门户中,转到 IoT 操作实例。

  2. 在 Azure IoT 操作资源下,选择 MQTT 代理

  3. 选择“NodePort 的 MQTT 代理监听器”>“创建”。 每个服务类型只能创建一个侦听器。 如果已有相同服务类型的侦听器,则可以向现有侦听器添加更多端口。

    注意

    将身份验证设置为“无”并且不配置 TLS 将关闭身份验证和 TLS(仅用于测试目的)

    输入以下设置:

    设置
    名称 nodeport
    服务名称 aio-broker-nodeport
    端口 1883
    身份验证 选择“默认”或“无”
    授权 选择“默认”
    协议 选择“MQTT”
    节点端口 31883
  4. 通过在端口上选择“TLS”,将 TLS 设置添加到侦听器

    设置 说明
    TLS 选择“添加”按钮。
    TLS 模式 选择“手动”或“自动”
    颁发者名称 cert-manager 证书颁发者的名称。 必需。
    证书颁发者类型 cert-manager 证书颁发者的类型。 必需。
    证书颁发者组 cert-manager 证书颁发者组。 必需。
    私钥算法 私钥的算法。
    私钥轮换策略 用于轮换私钥的策略。
    DNS 名称 证书的 DNS 使用者备用名称。
    IP 地址 证书使用者备用名称的 IP 地址。
    密钥名称 包含 X.509 客户端证书的 Kubernetes 机密。
    持续时间 TLS 服务器证书的总生存期默认为 90 天。
    续订时间早于 开始续订证书的时间。
  5. 选择“应用”以保存 TLS 设置

  6. 选择“创建”以创建侦听器。

获取节点的外部 IP 地址:

kubectl get nodes -o yaml | grep ExternalIP -C 1

输出应如下所示:

    - address: 104.197.41.11
      type: ExternalIP
    allocatable:
--
    - address: 23.251.152.56
      type: ExternalIP
    allocatable:
...

请使用外部 IP 地址和节点端口连接到代理。 例如,若要将消息发布到代理,请使用以下代码:

mosquitto_pub --host <EXTERNAL_IP> --port 31883 --message "hello" --topic "world" --debug # Add authentication and TLS options matching listener settings

如果输出中没有外部 IP,则可能使用的是默认情况下不会公开节点的外部 IP 地址的 Kubernetes 设置,例如 k3s、k3d 或 minikube 的许多设置。 在这种情况下,可以使用内部 IP 以及节点端口从同一网络上的计算机访问代理。 例如,若要获取节点的内部 IP 地址,请使用以下代码:

kubectl get nodes -o yaml | grep InternalIP -C 1

输出应如下所示:

    - address: 172.19.0.2
      type: InternalIP
    allocatable:

然后,使用内部 IP 地址和节点端口从同一群集中的计算机连接到代理。 如果 Kubernetes 在本地计算机上运行(例如使用单节点 k3s 时),则通常可以使用 localhost,而不是内部 IP 地址。 如果 Kubernetes 在 Docker 容器中运行(例如使用 k3d 时),则内部 IP 地址对应于容器的 IP 地址,并且应该可从主机访问。

负载均衡器

向 Internet 公开代理的另一种方法是使用 LoadBalancer 服务类型。 此方法更为复杂,可能需要进行额外的配置,例如设置端口转发。

例如,要创建一个新的代理侦听器,其负载均衡器服务类型侦听端口 1883:

  1. 在 Azure 门户中,转到 IoT 操作实例。

  2. 在 Azure IoT 操作资源下,选择 MQTT 代理

  3. 选择“NodePort 的 MQTT 代理监听器”>“创建”。 每个服务类型只能创建一个侦听器。 如果已有相同服务类型的侦听器,则可以向现有侦听器添加更多端口。

    注意

    将身份验证设置为“无”并且不配置 TLS 将关闭身份验证和 TLS(仅用于测试目的)

    输入以下设置:

    设置
    名称 loadbalancer
    服务名称 aio-broker-loadbalancer
    端口 1883
    身份验证 选择“默认”
    授权 选择“默认”或“无”
    协议 选择“MQTT”
  4. 可以通过在端口上选择“TLS”,将 TLS 设置添加到侦听器

    设置 说明
    TLS 选择“添加”按钮。
    TLS 模式 选择“手动”或“自动”
    颁发者名称 cert-manager 证书颁发者的名称。 必需。
    证书颁发者类型 cert-manager 证书颁发者的类型。 必需。
    证书颁发者组 cert-manager 证书颁发者组。 必需。
    私钥算法 私钥的算法。
    私钥轮换策略 用于轮换私钥的策略。
    DNS 名称 证书的 DNS 使用者备用名称。
    IP 地址 证书使用者备用名称的 IP 地址。
    密钥名称 包含 X.509 客户端证书的 Kubernetes 机密。
    持续时间 TLS 服务器证书的总生存期默认为 90 天。
    续订时间早于 开始续订证书的时间。
  5. 选择“应用”以保存 TLS 设置

  6. 选择“创建”以创建侦听器。

获取代理服务的外部 IP 地址:

kubectl get service aio-broker-loadbalancer --namespace azure-iot-operations

如果输出与下面类似:

NAME                      TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
aio-broker-loadbalancer   LoadBalancer   10.x.x.x        x.x.x.x       1883:30382/TCP   83s

这意味着已将外部 IP 分配到负载均衡器服务,你可以使用外部 IP 地址和端口连接到代理。 例如,若要将消息发布到代理,请使用以下代码:

mosquitto_pub --host <EXTERNAL_IP> --port 1883 --message "hello" --topic "world" --debug # Add authentication and TLS options matching listener settings

如果未分配外部 IP,则可能需要使用端口转发功能或虚拟交换机来访问代理。

使用端口转发

使用 minikubekind 和其他群集仿真系统时,可能不会自动分配外部 IP。 例如,它可能显示为挂起状态。

  1. 若要访问中转站,请转发侦听端口 18883 的中转站到主机。

    kubectl port-forward --namespace azure-iot-operations service/aio-broker 18883:mqtts-18883
    
  2. 使用 127.0.0.1 连接到端口 18883 上的中转站,其身份验证和 TLS 配置与示例相同,无需端口转发。

有关 minikube 的详细信息,请参阅使用端口转移访问群集中的应用程序

AKS 边缘软件包上的端口转移

对于 Azure Kubernetes 服务边缘软件包,需要执行一些其他步骤。 使用 AKS Edge Essentials,仅仅获取外部 IP 地址可能不足以连接到代理。 你可能需要设置端口转发并在防火墙上打开相应端口,以允许发往代理服务的流量。

  1. 首先,获取代理的负载均衡器侦听器的外部 IP 地址:

    kubectl get service broker-loadbalancer --namespace azure-iot-operations
    

    输出应如下所示:

    NAME                    TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)          AGE
    broker-loadbalancer     LoadBalancer   10.x.x.x       192.168.0.4   1883:30366/TCP   14h
    
  2. 在外部 IP 地址 192.168.0.4 和端口 1883 上设置到 broker-loadbalancer 服务的端口转移:

    netsh interface portproxy add v4tov4 listenport=1883 connectport=1883 connectaddress=192.168.0.4
    
  3. 打开防火墙上的端口,以流量发送到代理的服务:

    New-NetFirewallRule -DisplayName "AIO MQTT Broker" -Direction Inbound -Protocol TCP -LocalPort 1883 -Action Allow
    
  4. 使用主机的公共 IP 地址连接到 MQTT 代理。

有关端口转移的详细信息,请参阅向外部设备公开 Kubernetes 服务

通过 localhost 进行访问

某些 Kubernetes 分发版可以在群集配置过程中向主机系统 (localhost) 上的端口公开 MQTT 代理。 通过使用此方法,同一主机上的客户端将能够更轻松地访问 MQTT 代理。

例如,若要创建 K3d 群集,并将 MQTT 代理的默认 MQTT 端口 1883 映射到 localhost:1883,请使用以下代码:

k3d cluster create --port '1883:1883@loadbalancer'

或者,若要更新现有群集,请使用以下代码:

k3d cluster edit <CLUSTER_NAME> --port-add '1883:1883@loadbalancer'

然后,使用 localhost 和端口连接到代理。 例如,若要将消息发布到代理,请使用以下代码:

mosquitto_pub --host localhost --port 1883 --message "hello" --topic "world" --debug # Add authentication and TLS options matching listener settings

关闭 TLS 和身份验证(仅用于测试目的)

MQTT 代理默认使用 TLS 和服务帐户身份验证,目的是提供默认安全体验,最大限度地减少 IoT 解决方案无意中暴露给攻击者的风险。 不应在生产环境中关闭 TLS 和身份验证。 在不进行身份验证和 TLS 的情况下向 Internet 公开 MQTT 代理,可能会导致未经授权的访问,甚至导致 DDOS 攻击。

警告

如果你了解相关风险,并且需要在控制良好的环境中使用不安全的端口,可以通过从侦听器配置中移除 tlsauthenticationRef 设置来关闭 TLS 和身份验证,以便进行测试。

  1. 在 Azure 门户中,转到 IoT 操作实例。

  2. 在 Azure IoT 操作资源下,选择 MQTT 代理

  3. 选择“NodePort 的 MQTT 代理监听器”>“创建”。 每个服务类型只能创建一个侦听器。 如果已有相同服务类型的侦听器,则可以向现有侦听器添加更多端口。

    注意

    将身份验证设置为“无”并且不配置 TLS 将关闭身份验证和 TLS(仅用于测试目的)

    输入以下设置:

    设置
    名称 输入侦听器的名称
    服务名称 输入服务名称
    端口 1883
    身份验证 选择“无”
    授权 选择“无”
    协议 选择“MQTT”
    节点端口 31883(如果使用节点端口)
  4. 选择“创建”以创建侦听器。