チュートリアル: OPC UA 資産を Azure IoT Operations クラスターに追加する
このチュートリアルでは、OPC UA 資産を Azure IoT Operations クラスターに手動で追加します。 これらの資産は、Azure IoT Operations クラスターの MQTT ブローカーにメッセージを発行します。 通常、OT ユーザーは次の手順を実行します。
資産とは、物理デバイス、または、デバイス、マシン、システム、またはプロセスを表す論理エンティティです。 たとえば、物理資産には、ポンプ、モーター、タンク、生産ラインなどがあります。 定義する論理資産には、プロパティがあったり、テレメトリをストリーミングしたり、イベントを生成したりする可能性があります。
OPC UA サーバーは、資産と通信するソフトウェア アプリケーションです。 OPC UA タグは、OPC UA サーバーが公開するデータ ポイントです。 OPC UA タグは、資産のステータス、パフォーマンス、品質、状態に関する、リアルタイムまたは履歴データを提供できます。
このチュートリアルでは、Operations Experience Web UI を使用して資産を作成します。 Azure CLI を使って、これらのタスクの一部を完了することもできます。
前提条件
Kubernetes クラスターにデプロイされた Azure IoT Operations のインスタンス。 インスタンスを作成するには、次のいずれかを使用して Azure IoT Operations をデプロイします。
- 「クイックスタート: K3s を使用して GitHub Codespaces で Azure IoT Operations を実行する」では、チュートリアルで使用できる Azure IoT Operations インスタンスをデプロイする簡単な手順が説明されています。
- 「デプロイの概要」では、Azure Kubernetes Service Edge Essentials を使用した Windows または K3s を使用した Ubuntu に Azure IoT Operations インスタンスをデプロイする詳細な手順について説明します。
Operations Experience Web UI にサインインするには、Kubernetes - Azure Arc インスタンスを含むリソース グループに対する共同作成者以上のアクセス許可を持つ Microsoft Entra ID アカウントが必要です。 詳細については、「Operations Experience Web UI」を参照してください。
特に明記されていない限り、このチュートリアルのコンソール コマンドは Bash または PowerShell 環境で実行できます。
どのような問題が解決されますか?
OPC UA サーバーが公開するデータは複雑な構造になっている可能性があり、理解が困難な場合があります。 Azure IoT Operations では、OPC UA 資産をタグ、イベント、プロパティとしてモデル化する方法が提供されます。 このモデル化により、データを理解することと、それを MQTT ブローカーやデータフローなどのダウンストリーム プロセスで使用することがより簡単になります。
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
注意
この構成はセキュリティで保護されていません。 運用環境では、この構成を使わないでください。
Operations Experience にサインインする
資産エンドポイント、資産を作成し、OPC UA タグとイベントをサブスクライブするには、Operations Experience を使用します。
ブラウザーで Operations Experience を参照し、Microsoft Entra ID 資格情報を使用してサインインします。
サイトを選択する
サイトは、Azure IoT Operations インスタンスのコレクションです。 通常、サイトは物理的な場所でインスタンスをグループ化し、OT ユーザーが資産を見つけて管理するのを容易にします。 IT 管理者は、サイトを作成し、それに Azure IoT Operations インスタンスを割り当てます。 新しい展開を使用しているため、サイトはまだありません。 前に作成したクラスターは、[未割り当てインスタンスの表示] を選択することで確認できます。 操作エクスペリエンスで、インスタンスは Azure IoT Operations をデプロイしたクラスターを表します。
インスタンスを選択する
前のチュートリアルで Azure IoT Operations をデプロイしたクラスターを選びます。
ヒント
インスタンスが表示されない場合は、適切な Microsoft Entra ID テナントにいない可能性があります。 操作エクスペリエンスの右上のメニューからテナントを変更できます。
資産エンドポイントを追加する
前の記事で Azure IoT Operations をデプロイしたときに、組み込みの OPC PLC シミュレーターを含めました。 この手順では、OPC PLC シミュレーターに接続できるようにする資産エンドポイントを追加します。
資産エンドポイントを追加するには、次のようにします。
[資産エンドポイント] を選択し、続いて [資産エンドポイントの作成] を選択します。
次のエンドポイント情報を入力します。
フィールド 値 資産エンドポイント名 opc-ua-connector-0
OPC UA サーバー URL opc.tcp://opcplc-000000:50000
ユーザー認証モード Anonymous
定義を保存するには、[作成] を選択します。
この構成では、
opc-ua-connector-0
という新しい資産エンドポイントをクラスターにデプロイします。kubectl
を使って資産エンドポイントを表示できます。kubectl get assetendpointprofile -n azure-iot-operations
資産を管理する
Operations Experience でインスタンスを選択すると、[資産] ページに使用可能な資産の一覧が表示されます。 資産がまだない場合、この一覧は空です。
資産の作成
資産を作成するには、[資産の作成] を選択します。 その後、次の資産情報を入力します。
フィールド | 値 |
---|---|
資産エンドポイント | opc-ua-connector-0 |
資産名 | thermostat |
説明 | A simulated thermostat asset |
既定の MQTT トピック | azure-iot-operations/data/thermostat |
既存のカスタム プロパティを削除し、次のカスタム プロパティを追加します。 後のチュートリアルの Power BI テンプレートでそのクエリを実行するので、正確なプロパティ名を使うよう注意してください。
プロパティ名 | プロパティの詳細 |
---|---|
batch | 102 |
顧客 | コントソ |
備品 | Boiler |
isSpare | true |
location | シアトル |
[次へ] を選択して、[タグの追加] ページに移動します。
OPC UA タグを作成する
[タグの追加] ページで 2 つの OPC UA タグを追加します。 それぞれのタグを追加するには、[タグまたは CSV の追加] を選択し、続いて [タグの追加] を選択します。 次の表に示すタグの詳細を入力します。
ノード ID | タグ名 | 可観測性モード |
---|---|---|
ns=3;s=FastUInt10 | 温度 | なし |
ns=3;s=FastUInt100 | タグ 10 | なし |
監視モードは値 None
、Gauge
、Counter
、Histogram
、Log
のいずれかになります。
[既定の設定の管理] を選択して、各タグの既定のサンプリング間隔とキュー サイズを変更できます。
[次へ] を選択して [イベントの追加] ページに移動し、[次へ] を選択して [確認] ページに移動します。
確認
資産とタグの詳細を確認し、必要な調整を行ったら、[作成] を選択します。
この構成では、thermostat
という名前の新しい資産をクラスターにデプロイします。 以下のように kubectl
を使用することで、資産を表示できます。
kubectl get assets -n azure-iot-operations
データが流れていることを確認する
mosquitto_sub ツールを使用して、データが MQTT ブローカーに流れていることを確認します。 この例では、Kubernetes クラスターで mosquitto_sub ツールを実行します。
次のコマンドを実行して、クラスターの MQTT ブローカーを操作するのに役立つ mosquitto_pub と mosquitto_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 # Create a service account apiVersion: v1 kind: ServiceAccount metadata: name: mqtt-client namespace: azure-iot-operations --- # 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
注意
この構成はセキュリティで保護されていません。 運用環境では、この構成を使わないでください。
mqtt-client ポッドが実行されているときに、次のコマンドを実行して、作成したポッド内にシェル環境を作成します。
kubectl exec --stdin --tty mqtt-client -n azure-iot-operations -- sh
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/thermostat', ... (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/thermostat', ... (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/thermostat', ... (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/thermostat', ... (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/thermostat', ... (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
ポッドを再起動します。
次のコマンドを実行して、
aio-opc-opc.tcp-1
ポッドの名前を確認します。kubectl get pods -n azure-iot-operations
ポッドの名前は
aio-opc-opc.tcp-1-849dd78866-vhmz6
のようになります。次の例のようなコマンドを実行して、
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-08-02T13:52:15.1969959Z",
"Value": 2696
},
"Tag 10": {
"SourceTimestamp": "2024-08-02T13:52:15.1970198Z",
"Value": 2696
}
}
問題をどのように解決したか。
このチュートリアルでは、資産エンドポイントを追加して、資産とタグを定義しました。 資産とタグは、OPC UA server からのデータをモデル化して、MQTT ブローカーやその他のダウンストリーム プロセスでデータを容易に使用できるようにします。 次のチュートリアルでは、定義したサーモスタット資産を使用します。
リソースをクリーンアップする
次のチュートリアルに進む場合は、すべてのリソースを保持してください。
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 を削除します。