次の方法で共有


クイック スタート: クラスターを構成する

重要

Azure Arc によって実現されている Azure IoT Operations プレビューは、現在プレビュー段階です。 運用環境ではこのプレビュー ソフトウェアを使わないでください。

Azure IoT Operations の一般公開リリースが提供されたときには、新規インストールをデプロイすることが必要になります。 プレビュー インストールからのアップグレードはできません。

ベータ版、プレビュー版、または一般提供としてまだリリースされていない Azure の機能に適用される法律条項については、「Microsoft Azure プレビューの追加使用条件」を参照してください。

このクイック スタートでは、Azure IoT Operations プレビュー クラスターで次のリソースを構成します。

  • パン屋のオーブンをシミュレートするシミュレートされた OPC PLC サーバーへの接続を定義する "資産エンドポイント"。
  • オーブンを表し、オーブンで公開されるするデータ ポイントを定義する "資産"。
  • シミュレートされたオーブンからのメッセージを操作する "データフロー"。

資産とは、物理デバイス、または、デバイス、マシン、システム、またはプロセスを表す論理エンティティです。 たとえば、物理資産には、ポンプ、モーター、タンク、生産ラインなどがあります。 定義する論理資産には、プロパティがあったり、テレメトリをストリーミングしたり、イベントを生成したりする可能性があります。

OPC UA サーバーは、資産と通信するソフトウェア アプリケーションです。 OPC UA タグは、OPC UA サーバーが公開するデータ ポイントです。 OPC UA タグは、資産のステータス、パフォーマンス、品質、状態に関する、リアルタイムまたは履歴データを提供できます。

このクイック スタートでは、Bicep ファイルを使用して Azure IoT Operations インスタンスを構成します。

前提条件

Azure IoT Operations Preview のインスタンスを Kubernetes クラスターにデプロイします。 「クイックスタート: K3s を使用して GitHub Codespaces で Azure IoT Operations Preview を実行する」では、クイックスタートで使用できる Azure IoT Operations インスタンスをデプロイするシンプルな手順を説明しています。

特に明記されていない限り、このクイックスタートのコンソール コマンドは Bash または PowerShell 環境で実行できます。

どのような問題が解決されますか?

OPC UA サーバーが公開するデータは複雑な構造になっている可能性があり、理解が困難な場合があります。 Azure IoT Operations では、OPC UA 資産をタグ、イベント、プロパティとしてモデル化する方法が提供されます。 このモデル化により、データを理解することと、それを MQTT ブローカーやデータフローなどのダウンストリーム プロセスで使用することがより簡単になります。 データフローを使用すると、データを操作して Azure Event Hubs などのクラウド サービスにルーティングできます。 このクイック スタートでは、データフローでペイロード内の一部のフィールドの名前が変更され、メッセージに資産 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 環境を使用している場合は、必要な環境変数は既に設定されているため、この手順をスキップできます。 それ以外の場合、シェルで次の環境変数を設定します。

# 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 Operations インスタンスを構成する Bicep ファイルをダウンロードして実行します。 Bicep ファイル:

  • OPC PLC シミュレーターに接続する資産エンドポイントを追加します。
  • オーブンを表し、オーブンで公開されるデータ ポイントを定義する資産を追加します。
  • シミュレートされたオーブンからのメッセージを操作するデータフローを追加します。
  • データを受信する Azure Event Hubs インスタンスを作成します。
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 シミュレーターに接続する資産エンドポイント。
  • オーブンを表し、オーブンで公開されるデータ ポイントを定義する資産。
  • シミュレートされたオーブンからのメッセージを処理する 2 つのデータフロー。
  • データフローの宛先ハブを含む Azure Event Hubs 名前空間。

資産エンドポイント、資産、およびデータフローを表示するには、ブラウザーで操作エクスペリエンス UI に移動し、Microsoft Entra ID 資格情報でサインインします。 新しい展開を使用しているため、サイトはまだありません。 前のクイックスタートで作成したクラスターは、[未割り当てインスタンス] を選択することで確認できます。 操作エクスペリエンスで、インスタンスは Azure IoT Operations をデプロイしたクラスターを表します。

割り当てられていないインスタンスを示す操作エクスペリエンスのスクリーンショット。

資産エンドポイントでは、OPC PLC シミュレーターへの接続を定義します。

資産エンドポイントの一覧を示す操作エクスペリエンスのスクリーンショット。

オーブン資産では、オーブンで公開されるデータポイントを定義します。

資産の一覧を示す操作エクスペリエンスのスクリーンショット。

データフローでは、シミュレートされたオーブンからのメッセージを処理し、クラウド内の Event Hubs にルーティングする方法を定義します。

データフローの一覧を示す操作エクスペリエンスのスクリーンショット。

次のスクリーンショットは、温度変換データフローの構成方法を示しています。

温度変換の計算を示す操作エクスペリエンスのスクリーンショット。

データが MQTT ブローカーに送信されていることを確認する

mosquitto_sub ツールを使用して、データが MQTT ブローカーに流れていることを確認します。 この例では、Kubernetes クラスターで mosquitto_sub ツールを実行します。

  1. 次のコマンドを実行して、クラスターの MQTT ブローカーを操作するのに役立つ mosquitto_pubmosquitto_sub ツールを含むポッドをデプロイします。

    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 ポッドが実行されているときに、次のコマンドを実行して、作成したポッド内にシェル環境を作成します。

    kubectl exec --stdin --tty mqtt-client -n azure-iot-operations -- sh
    
  3. mqtt-client ポッドの Bash シェルで、次のコマンドを実行し、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)
    

    このコマンドは、Ctrl+C キーを押して停止するまで実行を続け、data/thermostat トピックにメッセージが到着するとそれを表示します。 シェル環境を終了するには、「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 ポッドを再起動します。

  1. 次のコマンドを実行して、aio-opc-opc.tcp-1 ポッドの名前を確認します。

    kubectl get pods -n azure-iot-operations
    

    ポッドの名前は aio-opc-opc.tcp-1-849dd78866-vhmz6 のようになります。

  2. 次の例のようなコマンドを実行して、aio-opc-opc.tcp-1 ポッドを再起動します。 前の手順の aio-opc-opc.tcp-1 ポッド名を使います。

    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
   }
}

データが Event Hubs に送信されていることを確認する

データがクラウドに流れていることを確認するには、Azure portal で Event Hubs インスタンスを表示できます。 データフローが開始され、メッセージがイベント ハブに送信されるまで数分待つことが必要な場合があります。

以前に適用した Bicep 構成では、データフローによって宛先として使用される Event Hubs 名前空間とハブを作成しました。 名前空間とハブを表示するには、Azure portal で、IoT Operations インスタンスを含むリソース グループに移動し、Event Hubs 名前空間を選択します。

メッセージがインスタンスに流れている場合、インスタンスの [概要] ページで受信メッセージの数を確認できます。

受信メッセージ数が表示された Event Hubs インスタンスの [概要] ページを示すスクリーンショット。

メッセージが流れている場合、[データ エクスプローラー] を使用してメッセージを表示できます。

Event Hubs インスタンスの [データ エクスプローラー] ページのスクリーンショット。

ヒント

メッセージを表示するには、Event Hubs 名前空間の Azure Event Hubs データ受信者ロールを自分に割り当てる必要があります。

問題をどのように解決したか。

このクイック スタートでは、bicep ファイルを使用し、資産エンドポイント、資産、データフローを使って Azure IoT Operations インスタンスを構成しました。 この構成では、データを処理し、シミュレートされたオーブンからルーティングします。 構成のデータフローでは、メッセージを Azure Event Hubs インスタンスにルーティングします。

リソースをクリーンアップする

次のクイックスタートに進む場合は、すべてのリソースを保持してください。

Azure IoT Operations デプロイは削除するが、クラスターは保持する場合は、az iot ops delete コマンドを使用します。

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

このクイックスタート用に作成したすべてのリソースを削除する場合は、Azure IoT Operations をデプロイした Kubernetes クラスターを削除した後、そのクラスターを含んでいた Azure リソース グループを削除します。

これらのクイックスタートで Codespaces を使った場合は、GitHub から Codespace を削除します。

次のステップ

Microsoft Fabric ダッシュボードを構築してオーブン データから分析情報を取得する方法を学習する場合は、「チュートリアル: 処理されたデータから分析情報を取得する」を参照してください。