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

快速入门:配置群集

重要

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

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

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

本快速入门将在 Azure IoT 操作预览版群集中配置以下资源:

  • 资产终结点 - 定义与模拟面包店烤箱的模拟 OPC PLC 服务器的连接。
  • 资产 - 表示烤箱并定义烤箱公开的数据点。
  • 数据流 - 用于处理模拟烤箱的消息。

资产是表示设备、计算机、系统或流程的物理设备或逻辑实体。 例如,物理资产可以是泵、电机、储罐或生产线。 定义的逻辑资产可以具有属性、流遥测或生成事件。

OPC UA 服务器是与资产通信的软件应用程序。 OPC UA 标记是 OPC UA 服务器公开的数据点。 OPC UA 标记可以提供有关资产状态、性能、质量或条件的实时或历史数据。

本快速入门将使用 Bicep 文件来配置 Azure IoT 操作实例。

先决条件

在 Kubernetes 群集中部署 Azure IoT 操作预览版实例。 快速入门:使用 K3s 在 GitHub Codespaces 中运行 Azure IoT 操作预览版提供了简单的说明来部署可用于快速入门的 Azure IoT 操作实例。

可以在 Bash 或 PowerShell 环境中运行本快速入门中的控制台命令,除非另有说明。

我们将解决什么问题?

OPC UA 服务器公开的数据可能具有复杂的结构,并且难以理解。 Azure IoT 操作提供了一种将 OPC UA 资产建模为标记、事件和属性的方法。 通过此建模,可以更轻松地了解数据并在下游流程(例如,MQTT 代理和数据流)中使用它。 数据流可操作数据并将其路由到云服务,例如 Azure 事件中心。 在本快速入门中,数据流将更改有效负载中某些字段的名称,并将资产 ID 添加到消息中。

部署 OPC PLC 模拟器

本快速入门使用 OPC PLC 模拟器生成示例数据。 若要部署 OPC PLC 模拟器,请运行以下命令:

kubectl apply -f https://raw.githubusercontent.com/Azure-Samples/explore-iot-operations/main/samples/quickstarts/opc-plc-deployment.yaml

以下代码片段显示了已应用的 YAML 文件:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: opc-plc-000000
  namespace: azure-iot-operations
  labels:
    app.kubernetes.io/component: opcplc-000000
spec:
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/component: opcplc-000000
  template:
    metadata:
      labels:
        app.kubernetes.io/component: opcplc-000000
    spec:
      containers:
      - name: opc-plc
        image: mcr.microsoft.com/iotedge/opc-plc:latest
        args:
          - "--ph=opcplc-000000"
          - "--cdn=opcplc-000000"
          - "--ut"
          - "--sn=25"
          - "--sr=10"
          - "--fn=2000"
          - "--veryfastrate=1000"
          - "--gn=5"
          - "--pn=50000"
          - "--maxsessioncount=100"
          - "--maxsubscriptioncount=100"
          - "--maxqueuedrequestcount=2000"
          - "--ses"
          - "--alm"
          - "--at=FlatDirectory"
          - "--drurs"
          - "--ll-debug"
          - "--nodesfile"
          - "/app/config/nodesfile.json"
        ports:
        - containerPort: 50000
        volumeMounts:
          - name: opc-plc-default-application-cert
            mountPath: /app/pki/own
          - name: opc-plc-trust-list
            mountPath: /app/pki/trusted
          - name: config-volume
            mountPath: /app/config
      volumes:
        - name: opc-plc-default-application-cert
          secret:
            secretName: opc-plc-default-application-cert
        - name: opc-plc-trust-list
          secret:
            secretName: opc-plc-trust-list
        - name: config-volume
          configMap:
            name: opc-plc-config
      serviceAccountName: opcplc-000000-service-account
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: opc-plc-config
  namespace: azure-iot-operations
  labels:
    app.kubernetes.io/component: opcplc-000000
data:
  nodesfile.json: |
    {
      "Folder": "MyTelemetry",
      "NodeList": [
        {
          "NodeId": "ns=3;s=FastUInt100",
          "Name": "Fryer Temperature",
          "DataType": "Double",
          "ValueRank": -1,
          "AccessLevel": "CurrentReadOrWrite",
          "Description": "Fryer Temperature with spikes",
          "Anomaly": "Spike",
          "MinValue": 150.0,
          "MaxValue": 200.0          
        }
      ]
    }
---
apiVersion: v1
kind: Service
metadata:
  name: opcplc-000000
  namespace: azure-iot-operations
  labels:
    app.kubernetes.io/component: opcplc-000000
spec:
  type: ClusterIP
  selector:
    app.kubernetes.io/component: opcplc-000000
  ports:
    - port: 50000
      protocol: TCP
      targetPort: 50000
---
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
  name: opc-plc-self-signed-issuer
  namespace: azure-iot-operations
  labels:
    app.kubernetes.io/component: opcplc-000000
spec:
  selfSigned: {}
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: opc-plc-default-application-cert
  namespace: azure-iot-operations
  labels:
    app.kubernetes.io/component: opcplc-000000
spec:
  secretName: opc-plc-default-application-cert
  duration: 2160h # 90d
  renewBefore: 360h # 15d
  issuerRef:
    name: opc-plc-self-signed-issuer
    kind: Issuer
  commonName: OpcPlc
  dnsNames:
    - opcplc-000000
    - opcplc-000000.azure-iot-operations.svc.cluster.local
    - opcplc-000000.azure-iot-operations
  uris:
    - urn:OpcPlc:opcplc-000000
  usages:
    - digital signature
    - key encipherment
    - data encipherment
    - server auth
    - client auth
  privateKey:
    algorithm: RSA
    size: 2048
  encodeUsagesInRequest: true
  isCA: false
---
apiVersion: v1
kind: Secret
metadata:
  name: opc-plc-trust-list
  namespace: azure-iot-operations
  labels:
    app.kubernetes.io/component: opcplc-000000
data: {}
---
apiVersion: batch/v1
kind: Job
metadata:
  name: opcplc-000000-execute-mutual-trust
  namespace: azure-iot-operations
  labels:
    app.kubernetes.io/component: opcplc-000000
spec:
  backoffLimit: 1
  template:
    spec:
      containers:
      - name: kubectl
        image: mcr.microsoft.com/oss/kubernetes/kubectl:v1.27.1
        imagePullPolicy: Always
        command: ["/bin/sh"]
        args: ["/scripts/execute-commands.sh"]
        volumeMounts:
        - name: scripts
          mountPath: /scripts
          readOnly: true
      restartPolicy: Never
      serviceAccountName: opcplc-000000-service-account
      volumes:
      - name: scripts
        configMap:
          name: opcplc-000000-execute-commands-script
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: opcplc-000000-execute-commands-script
  namespace: azure-iot-operations
  labels:
    app.kubernetes.io/component: opcplc-000000
data:
  execute-commands.sh: |
    #!/bin/sh

    # wait 20 seconds for the resources to be created
    sleep 20

    # Extract the OPC UA connector application instance certificate and add it to the OPC PLC trust list
    cert=$(kubectl -n azure-iot-operations get secret aio-opc-opcuabroker-default-application-cert -o jsonpath='{.data.tls\.crt}' | base64 -d)
    data=$(kubectl create secret generic temp --from-literal=opcuabroker.crt="$cert" --dry-run=client -o jsonpath='{.data}')
    kubectl patch secret opc-plc-trust-list -n azure-iot-operations -p "{\"data\": $data}"

    # Extract the OPC PLC application instance certificate and add it to the OPC UA connector trust list
    cert=$(kubectl -n azure-iot-operations get secret opc-plc-default-application-cert -o jsonpath='{.data.tls\.crt}' | base64 -d)
    data=$(kubectl create secret generic temp --from-literal=opcplc-000000.crt="$cert" --dry-run=client -o jsonpath='{.data}')
    kubectl patch secret aio-opc-ua-broker-trust-list -n azure-iot-operations -p "{\"data\": $data}"
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: opcplc-000000-service-account
  namespace: azure-iot-operations
  labels:
    app.kubernetes.io/component: opcplc-000000
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: opc-plc-000000-secret-access-role
  namespace: azure-iot-operations
rules:
- apiGroups: [""]
  resources: ["secrets"]
  verbs: ["get", "patch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: opc-plc-000000-secret-access-rolebinding
  namespace: azure-iot-operations
subjects:
- kind: ServiceAccount
  name: opcplc-000000-service-account
  namespace: azure-iot-operations
roleRef:
  kind: Role
  name: opc-plc-000000-secret-access-role
  apiGroup: rbac.authorization.k8s.io

注意

此配置使用自签名应用程序实例证书。 请勿在生产环境中使用此配置。 要了解详细信息,请参阅为 OPC UA 连接器配置 OPC UA 证书基础结构


设置环境变量

如果使用的是 Codespaces 环境,则已设置所需的环境变量,可以跳过此步骤。 否则,请在 shell 中设置以下环境变量:

# Your subscription ID
SUBSCRIPTION_ID=<subscription-id>

# The name of the resource group where your Kubernetes cluster is deployed
RESOURCE_GROUP=<resource-group-name>

# The name of your Kubernetes cluster
CLUSTER_NAME=<kubernetes-cluster-name>

配置群集

运行以下命令以下载并运行配置 Azure IoT 操作实例的 Bicep 文件。 Bicep 文件:

  • 添加连接到 OPC PLC 模拟器的资产终结点。
  • 添加表示烤箱并定义烤箱公开的数据点的资产。
  • 添加用于处理模拟烤箱的消息的数据流。
  • 创建用于接收数据的 Azure 事件中心实例。
wget https://raw.githubusercontent.com/Azure-Samples/explore-iot-operations/main/samples/quickstarts/quickstart.bicep -O quickstart.bicep

AIO_EXTENSION_NAME=$(az k8s-extension list -g $RESOURCE_GROUP --cluster-name $CLUSTER_NAME --cluster-type connectedClusters --query "[?extensionType == 'microsoft.iotoperations'].id" -o tsv | awk -F'/' '{print $NF}')
AIO_INSTANCE_NAME=$(az iot ops list -g $RESOURCE_GROUP --query "[0].name" -o tsv)
CUSTOM_LOCATION_NAME=$(az iot ops list -g $RESOURCE_GROUP --query "[0].extendedLocation.name" -o tsv | awk -F'/' '{print $NF}')

az deployment group create --subscription $SUBSCRIPTION_ID --resource-group $RESOURCE_GROUP --template-file quickstart.bicep --parameters clusterName=$CLUSTER_NAME customLocationName=$CUSTOM_LOCATION_NAME aioExtensionName=$AIO_EXTENSION_NAME aioInstanceName=$AIO_INSTANCE_NAME

查看配置

配置了以下资源的 Bicep 文件:

  • 连接到 OPC PLC 模拟器的资产终结点。
  • 表示烤箱并定义烤箱公开的数据点的资产。
  • 用于处理模拟烤箱的消息的两个数据流。
  • 包含数据流目标中心的 Azure 事件中心命名空间。

要查看资产终结点、资产和数据流,请导航到浏览器中的操作体验 UI,并使用 Microsoft Entra ID 凭据登录。 由于你正在使用新部署,因此还没有站点。 可以通过选择“未分配的实例”来查找在上一个快速入门中创建的群集。 在操作体验中,实例表示在其中部署了 Azure IoT 操作的群集。

显示操作体验中未分配实例节点的屏幕截图。

资产终结点定义与 OPC PLC 模拟器的连接:

显示操作体验中资产终结点列表的屏幕截图。

烤箱资产定义烤箱公开的数据点:

显示操作体验中资产列表的屏幕截图。

数据流定义如何处理来自模拟烤箱的消息并将其路由到云中的事件中心:

显示操作体验中数据流列表的屏幕截图。

以下屏幕截图显示了如何配置温度转换数据流:

显示操作体验中温度转换计算的屏幕截图。

验证数据是否流向 MQTT 代理

使用 mosquitto_sub 工具验证数据是否流向 MQTT 代理。 在此示例中,你将在 Kubernetes 群集中运行 mosquitto_sub 工具

  1. 运行以下命令来部署包含 mosquitto_pub 和 mosquitto_sub 工具的 Pod,这些工具可用于与群集中的 MQTT 代理交互

    kubectl apply -f https://raw.githubusercontent.com/Azure-Samples/explore-iot-operations/main/samples/quickstarts/mqtt-client.yaml
    

    以下代码片段显示了已应用的 YAML 文件:

    # Important: do not use in production environments
    # Creates a pod with mosquitto-clients and mqttui utilities in your cluster
    apiVersion: v1
    kind: Pod
    metadata:
      name: mqtt-client
      # The namespace must match the IoT MQ 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 which comes with default deployment
      # Otherwise create it with `kubectl create serviceaccount mqtt-client -n azure-iot-operations`
      serviceAccountName: mqtt-client
      containers:
        # Install mosquitto and mqttui utilities on Alpine linux
      - image: alpine
        name: mqtt-client
        command: ["sh", "-c"]
        args: ["apk add mosquitto-clients mqttui && sleep infinity"]
        resources:
          limits:
            cpu: 500m
            memory: 200Mi
          requests:
            cpu: 100m
            memory: 100Mi
        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
    

    注意

    此配置是不安全的。 请勿在生产环境中使用此配置。

  2. 运行 mqtt-client pod 时,请运行以下命令以在所创建的 Pod 中创建 shell 环境

    kubectl exec --stdin --tty mqtt-client -n azure-iot-operations -- sh
    
  3. 在 mqtt-client pod 中的 Bash shell 中,运行以下命令,使用订阅 data/thermostat 主题的 mosquitto_sub 工具连接到 MQTT 代理:

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

    此命令在到达 data/thermostat 主题时会继续运行并显示消息,直到按 Ctrl+C 停止它。 要退出 shell 环境,请键入 exit

要验证添加的烤箱资产是否正在发布数据,请查看 azure-iot-operations/data 主题中的遥测数据:

Client $server-generated/05a22b94-c5a2-4666-9c62-837431ca6f7e received PUBLISH (d0, q0, r0, m0, 'azure-iot-operations/data/oven', ... (152 bytes))
{"temperature":{"SourceTimestamp":"2024-07-29T15:02:17.1858435Z","Value":4558},"Tag 10":{"SourceTimestamp":"2024-07-29T15:02:17.1858869Z","Value":4558}}
Client $server-generated/05a22b94-c5a2-4666-9c62-837431ca6f7e received PUBLISH (d0, q0, r0, m0, 'azure-iot-operations/data/oven', ... (152 bytes))
{"temperature":{"SourceTimestamp":"2024-07-29T15:02:18.1838125Z","Value":4559},"Tag 10":{"SourceTimestamp":"2024-07-29T15:02:18.1838523Z","Value":4559}}
Client $server-generated/05a22b94-c5a2-4666-9c62-837431ca6f7e received PUBLISH (d0, q0, r0, m0, 'azure-iot-operations/data/oven', ... (152 bytes))
{"temperature":{"SourceTimestamp":"2024-07-29T15:02:19.1834363Z","Value":4560},"Tag 10":{"SourceTimestamp":"2024-07-29T15:02:19.1834879Z","Value":4560}}
Client $server-generated/05a22b94-c5a2-4666-9c62-837431ca6f7e received PUBLISH (d0, q0, r0, m0, 'azure-iot-operations/data/oven', ... (152 bytes))
{"temperature":{"SourceTimestamp":"2024-07-29T15:02:20.1861251Z","Value":4561},"Tag 10":{"SourceTimestamp":"2024-07-29T15:02:20.1861709Z","Value":4561}}
Client $server-generated/05a22b94-c5a2-4666-9c62-837431ca6f7e received PUBLISH (d0, q0, r0, m0, 'azure-iot-operations/data/oven', ... (152 bytes))
{"temperature":{"SourceTimestamp":"2024-07-29T15:02:21.1856798Z","Value":4562},"Tag 10":{"SourceTimestamp":"2024-07-29T15:02:21.1857211Z","Value":4562}}

如果没有数据流,请重启 aio-opc-opc.tcp-1 Pod:

  1. 使用以下命令查找 aio-opc-opc.tcp-1 Pod 的名称:

    kubectl get pods -n azure-iot-operations
    

    Pod 的名称类似于 aio-opc-opc.tcp-1-849dd78866-vhmz6

  2. 使用类似于以下示例的命令重启 aio-opc-opc.tcp-1 Pod。 使用上一步中的 aio-opc-opc.tcp-1 Pod 名称:

    kubectl delete pod aio-opc-opc.tcp-1-849dd78866-vhmz6 -n azure-iot-operations
    

本快速入门前面添加的示例资产可生成类似于以下示例的消息:

{
   "Temperature":{
      "SourceTimestamp":"2024-11-04T21:30:31.9454188Z",
      "Value":357
   },
   "FillWeight":{
      "SourceTimestamp":"2024-11-04T21:30:31.9455619Z",
      "Value":357
   },
   "EnergyUse":{
      "SourceTimestamp":"2024-11-04T21:30:31.9455641Z",
      "Value":357
   }
}

验证数据是否流向事件中心

要验证数据是否流向云,可以在 Azure 门户中查看事件中心实例。 可能需要等待几分钟才能启动数据流并让消息流向事件中心。

之前应用的 Bicep 配置创建了一个事件中心命名空间和被数据流用作目标的中心。 要查看该命名空间和中心,请导航到包含 IoT 操作实例的 Azure 门户中的资源组,然后选择事件中心命名空间。

如果消息流向实例,可以在实例“概述”页上看到传入消息的计数:

屏幕截图显示了包含传入消息的事件中心实例概述页。

如果消息正在流动,则可以使用“数据资源管理器”查看消息:

事件中心实例**数据资源管理器**页的屏幕截图。

提示

要查看消息,可能需要为自己分配事件中心命名空间的 Azure 事件中心数据接收方角色。

我们如何解决问题?

本快速入门使用 Bicep 文件配置了 Azure IoT 操作实例以及资产终结点、资产和数据流。 该配置处理并路由来自模拟烤箱的数据。 配置中的数据流将消息路由到 Azure 事件中心实例。

清理资源

如果继续学习下一个快速入门,请保留所有资源。

如果要移除 Azure IoT 操作部署但保留群集,请使用 az iot ops delete 命令:

az iot ops delete --cluster $CLUSTER_NAME --resource-group $RESOURCE_GROUP

如果要删除为此快速入门创建的所有资源,请删除部署 Azure IoT 操作的 Kubernetes 群集,然后移除包含该群集的 Azure 资源组。

如果使用了 Codespaces 来完成这些快速入门,请从 GitHub 中删除你的 Codespace。

下一步

若要了解如何生成 Microsoft Fabric 仪表板,以便从烤箱数据获取见解,请参阅教程:从已处理的数据中获取见解