次の方法で共有


チュートリアル: カスタム IoT Edge モジュールを作成してデプロイする

適用対象:はいアイコン IoT Edge 1.1

重要

IoT Edge 1.1 サポート終了日は 2022 年 12 月 13 日でした。 本製品、サービス、テクノロジ、または API のサポート内容については、Microsoft 製品のライフサイクルに関するページをご確認ください。 最新バージョンの IoT Edge への更新の詳細については、「IoT Edgeの更新」を参照してください。

この記事では、ダウンストリーム IoT デバイスからメッセージを受信し、機械学習モデルを介してデータを実行し、分析情報を IoT Hub に転送する 3 つの IoT Edge モジュールを作成します。

IoT Edge ハブを使用することで、モジュール間の通信が容易になっています。 IoT Edge ハブをメッセージ ブローカーとして使用すると、モジュールは互いに独立して保持されます。 モジュールは、メッセージを受信する入力と、メッセージを書き出す出力を指定するだけです。

IoT Edge デバイスでは、次の 4 つのことを実現したいと考えています。

  • ダウンストリーム デバイスからデータを受信します。
  • データを送信したデバイスの残存耐用年数 (RUL) を予測します。
  • デバイスの RUL を含むメッセージを IoT Hub に送信します。 RUL が指定したレベルを下回った場合にのみ、この関数を変更してデータを送信できます。
  • ダウンストリーム デバイス データを IoT Edge デバイス上のローカル ファイルに保存します。 このデータ ファイルは、機械学習モデルのトレーニングを調整するために、IoT Hub に定期的にアップロードされます。 一定のメッセージ ストリーミングの代わりにファイルアップロードを使用すると、コスト効率が高くなります。

これらのタスクを実行するには、次の 3 つのカスタム モジュールを使用します。

  • RUL 分類子:Azure Machine Learning モデルのトレーニングとデプロイで作成した turboFanRulClassifier モジュールは、"amlInput" という入力と "amlOutput" という出力を公開する標準的な機械学習モジュールです。 "amlInput" は、入力が ACI ベースの Web サービスに送信した入力とまったく同じように見えると想定しています。 同様に、"amlOutput" は Web サービスと同じデータを返します。

  • Avro ライター: このモジュールは、"avroModuleInput" 入力のメッセージを受信し、後で IoT Hub にアップロードするために Avro 形式のメッセージをディスクに保持します。

  • ルーター モジュール: ルーター モジュールはダウンストリーム デバイスからメッセージを受信し、そのメッセージを書式設定して分類子に送信します。 その後、モジュールは分類子からメッセージを受信し、Avro ライター モジュールにメッセージを転送します。 最後に、モジュールは RUL 予測のみを IoT Hub に送信します。

    • [入力]:

      • deviceInput: ダウンストリーム デバイスからメッセージを受信します
      • rulInput: "amlOutput" からメッセージを受信します
    • 出力:

      • classify: メッセージを "amlInput" に送信する
      • writeAvro: "avroModuleInput" にメッセージを送信する
      • toIotHub: $upstreamにメッセージを送信し、接続された IoT Hub にメッセージを渡します

次の図は、完全なソリューションのモジュール、入力、出力、および IoT Edge Hub ルートを示しています。

IoT Edge の 3 つのモジュールアーキテクチャ図

この記事の手順は、通常、クラウド開発者が実行します。

チュートリアルのこのセクションでは、次の方法について説明します。

  • カスタム コードから IoT Edge モジュールを作成します。
  • カスタム モジュールから Docker イメージを生成します。
  • カスタム モジュールをサポートするように IoT Hub ルーティングを再構成します。
  • カスタム モジュールをビルド、発行、デプロイします。

前提条件

この記事は、Azure Machine Learning on IoT Edge の使用に関するチュートリアルのシリーズの一部です。 シリーズの各記事は、前の記事の作業に基づいています。 この記事に直接アクセスした場合は、シリーズの 最初の記事 を参照してください。

新しい IoT Edge ソリューションを作成する

2 つの Azure Notebook の 2 つ目の実行中に、RUL モデルを含むコンテナー イメージを作成して発行しました。 Azure Machine Learning は、イメージ作成プロセスの一環として、イメージを Azure IoT Edge モジュールとしてデプロイできるように、そのモデルをパッケージ化しました。

この手順では、"Azure Machine Learning" モジュールを使用して Azure IoT Edge ソリューションを作成し、Azure Notebooks を使用して発行したイメージをモジュールにポイントします。

  1. 開発用 VM へのリモート デスクトップ セッションを開きます。

  2. Visual Studio Code でフォルダー C:\source\IoTEdgeAndMlSample を開きます。

  3. エクスプローラー パネル (空白の領域) を右クリックし、[ 新しい IoT Edge ソリューション] を選択します。

    新しい IoT Edge ソリューションを作成する

  4. 既定のソリューション名 EdgeSolution をそのまま使用します。

  5. モジュール テンプレートとして Azure Machine Learning を選択します。

  6. モジュールに turbofanRulClassifier という名前を付けます

  7. 機械学習ワークスペースを選択します。 このワークスペースは、「チュートリアル: Azure Machine Learning モデルのトレーニングとデプロイ」で作成した turboFanDemo ワークスペースです。

  8. Azure Notebook の実行中に作成したイメージを選択します。

  9. ソリューションを確認し、作成されたファイルに注目します。

    • deployment.template.json: このファイルには、ソリューション内の各モジュールの定義が含まれています。 このファイルには、注意が必要な 3 つのセクションがあります。

      • レジストリ資格情報: ソリューションで使用するカスタム コンテナー レジストリのセットを定義します。 現時点では、Azure Machine Learning イメージが格納された機械学習ワークスペースのレジストリが含まれている必要があります。 コンテナー レジストリはいくつでも使用できますが、わかりやすくするために、すべてのモジュールにこの 1 つのレジストリを使用します。

        "registryCredentials": {
          "<your registry>": {
            "username": "$CONTAINER_REGISTRY_USERNAME_<your registry>",
            "password": "$CONTAINER_REGISTRY_PASSWORD_<your registry>",
            "address": "<your registry>.azurecr.io"
          }
        }
        
      • モジュール: このセクションには、このソリューションに付属するユーザー定義モジュールのセットが含まれています。 turbofanRulClassifier モジュール定義は、コンテナー レジストリ内のイメージを指します。 ソリューションにモジュールを追加すると、このセクションに表示されます。

        "modules": {
           "turbofanRulClassifier": {
             "version": "1.0",
             "type": "docker",
             "status": "running",
             "restartPolicy": "always",
             "settings": {
               "image": "turbofandemo2cd74296.azurecr.io/edgemlsample:1",
               "createOptions": {}
             }
           }
        }
        
      • ルート: このチュートリアルでは、ルートをかなり操作します。 ルートは、モジュールが相互に通信する方法を定義します。 テンプレートで定義されている既存のルートが、必要なルーティングと一致しません。 turbofanRulClassifierToIoTHub ルートを削除します。

        "$edgeHub": {
           "properties.desired": {
             "schemaVersion": "1.0",
             "routes": {
               "turbofanRulClassifierToIoTHub": "FROM /messages/modules/turbofanRulClassifier/outputs/* INTO $upstream"
             },
             "storeAndForwardConfiguration": {
               "timeToLiveSecs": 7200
             }
           }
        }
        
    • deployment.debug.template.json: このファイルは、deployment.template.jsonのデバッグ バージョンです。 通常、このファイルは deployment.template.json ファイルの内容と同期する必要がありますが、このチュートリアルでは必要ありません。

    • .env: このファイルは、レジストリにアクセスするためのユーザー名とパスワードを指定する必要がある場所です。

      CONTAINER_REGISTRY_USERNAME_<your registry name>=<ACR username>
      CONTAINER_REGISTRY_PASSWORD_<your registry name>=<ACR password>
      

      このチュートリアルでは、開発とテストのシナリオに便利な、Azure Container Registry の管理者ログイン資格情報を使用します。 運用環境のシナリオに向けて準備ができたら、サービス プリンシパルのような最小限の特権で認証できるオプションを使用することをお勧めします。 詳細については、[コンテナー レジストリへのアクセスを管理する] を参照してください。

  10. Visual Studio Code エクスプローラーで deployment.template.json ファイルを右クリックし、[ IoT Edge ソリューションのビルド] を選択します。

  11. このコマンドは、deployment.amd64.json ファイルを含む config フォルダーを作成します。 このファイルは、ソリューションの具体的なデプロイ テンプレートです。

ルーター モジュールの追加

次に、ルーター モジュールをソリューションに追加します。 Router モジュールは、ソリューションに対していくつかの責任を処理します。

  • ダウンストリーム デバイスからメッセージを受信する: ダウンストリーム デバイス から IoT Edge デバイスにメッセージが到着すると、Router モジュールはメッセージを受信し、メッセージのルーティングの調整を開始します。
  • RUL 分類子モジュールにメッセージを送信する: ダウンストリーム デバイスから新しいメッセージを受信すると、Router モジュールはメッセージを RUL 分類子が想定する形式に変換します。 ルーターは RUL 予測のために RUL 分類子にメッセージを送信します。 分類子が予測を行うと、メッセージが Router モジュールに送信されます。
  • RUL メッセージを IoT Hub に送信する: ルーターは、分類子からメッセージを受信すると、重要な情報、デバイス ID、RUL のみを含むメッセージを変換し、省略されたメッセージを IoT ハブに送信します。 ここで行っていないさらに絞り込みでは、RUL 予測がしきい値を下回った場合 (たとえば、RUL が 100 サイクル未満の場合) にのみ、IoT Hub にメッセージを送信します。 この方法でフィルター処理を行うと、メッセージの量が減り、IoT ハブのコストが削減されます。
  • Avro ライター モジュールにメッセージを送信する: ダウンストリーム デバイスによって送信されたすべてのデータを保持するために、Router モジュールは分類子から受信したメッセージ全体を Avro ライター モジュールに送信します。このモジュールは、IoT Hub ファイルのアップロードを使用してデータを永続化してアップロードします。

Router モジュールは、メッセージが正しい順序で処理されることを保証するソリューションの重要な部分です。

モジュールを作成してファイルをコピーする

  1. Visual Studio Code で modules フォルダーを右クリックし、[ IoT Edge モジュールの追加] を選択します。

  2. モジュール テンプレートの C# モジュール を選択します。

  3. モジュールに turbofanRouter という名前を付けます

  4. Docker イメージ リポジトリの入力を求められたら、機械学習ワークスペースのレジストリを使用します (レジストリは 、deployment.template.json ファイルの registryCredentials ノードにあります)。 この値は、レジストリの完全修飾アドレスです (レジストリ<>.azurecr.io/turbofanrouter など)。

    この記事では、Azure Machine Learning ワークスペースによって作成された Azure Container Registry を使用します。 これは単純に便宜上です。 新しいコンテナー レジストリを作成し、そこでモジュールを公開できました。

  5. コマンド プロンプト シェルを使用してターミナルで、サンプル モジュールからソリューションにファイルをコピーします。

    copy c:\source\IoTEdgeAndMlSample\EdgeModules\modules\turbofanRouter\*.cs c:\source\IoTEdgeAndMlSample\EdgeSolution\modules\turbofanRouter\
    
  6. プロンプトを受け入れて、program.cs ファイルを上書きします。

ルーター モジュールをビルドする

  1. Visual Studio Code で、[ ターミナル>既定のビルド タスクの構成] を選択します。

  2. [テンプレートからファイル tasks.json 作成] を選択します。

  3. .NET Core を選択します。

  4. tasks.json の内容を次のコードに置き換えます。

    {
      "version": "2.0.0",
      "tasks": [
        {
          "label": "build",
          "command": "dotnet",
          "type": "shell",
          "group": {
            "kind": "build",
            "isDefault": true
          },
          "args": [
            "build",
            "${workspaceFolder}/modules/turbofanRouter"
          ],
          "presentation": {
            "reveal": "always"
          },
          "problemMatcher": "$msCompile"
        }
      ]
    }
    
  5. tasks.jsonを保存して閉じます。

  6. Ctrl + Shift + Bまたはターミナルを使用してビルド>実行ビルド タスクを実行します。

モジュール ルートを設定する

前述のように、IoT Edge ランタイムは 、deployment.template.json ファイルで構成されたルートを使用して、疎結合モジュール間の通信を管理します。 このセクションでは、turbofanRouter モジュールのルートを設定する方法について詳しく説明します。 最初に入力ルートについて説明し、次に出力を移動します。

入力

  1. Program.csの Init() メソッドでは、モジュールの 2 つのコールバックを登録します。

    await ioTHubModuleClient.SetInputMessageHandlerAsync(EndpointNames.FromLeafDevice, LeafDeviceInputMessageHandler, ioTHubModuleClient);
    await ioTHubModuleClient.SetInputMessageHandlerAsync(EndpointNames.FromClassifier, ClassifierCallbackMessageHandler, ioTHubModuleClient);
    
  2. 最初のコールバックは、 deviceInput シンクに送信されたメッセージをリッスンします。 上の図から、ダウンストリーム デバイスからこの入力にメッセージをルーティングする必要があることがわかります。 deployment.template.json ファイルで、IoT Edge モジュールによって送信されなかった IoT Edge デバイスによって受信されたメッセージを turbofanRouter モジュールの "deviceInput" という入力にルーティングするようにエッジ ハブに指示するルートを追加します。

    "leafMessagesToRouter": "FROM /messages/* WHERE NOT IS_DEFINED($connectionModuleId) INTO BrokeredEndpoint(\"/modules/turbofanRouter/inputs/deviceInput\")"
    
  3. 次に、rulClassifier モジュールからのメッセージのルートを turbofanRouter モジュールに追加します。

    "classifierToRouter": "FROM /messages/modules/turbofanRulClassifier/outputs/amloutput INTO BrokeredEndpoint(\"/modules/turbofanRouter/inputs/rulInput\")"
    

出力

router モジュールからの出力を処理するために、$edgeHub ルート パラメーターに 4 つのルートを追加します。

  1. Program.csでは、SendMessageToClassifier() メソッドを定義します。このメソッドは、モジュール クライアントを使用して、ルートを使用して RUL 分類子にメッセージを送信します。

    "routerToClassifier": "FROM /messages/modules/turbofanRouter/outputs/classOutput INTO BrokeredEndpoint(\"/modules/turbofanRulClassifier/inputs/amlInput\")"
    
  2. SendRulMessageToIotHub() は、モジュール クライアントを使用して、デバイスの RUL データのみをルート経由で IoT Hub に送信します。

    "routerToIoTHub": "FROM /messages/modules/turboFanRouter/outputs/hubOutput INTO $upstream"
    
  3. SendMessageToAvroWriter() は、モジュール クライアントを使用して、avroFileWriter モジュールに追加された RUL データを含むメッセージを送信します。

    "routerToAvro": "FROM /messages/modules/turbofanRouter/outputs/avroOutput INTO BrokeredEndpoint(\"/modules/avroFileWriter/inputs/avroModuleInput\")"
    
  4. HandleBadMessage() は、失敗したメッセージを後でルーティングできる IoT Hub のアップストリームに送信します。

    "deadLetter": "FROM /messages/modules/turboFanRouter/outputs/deadMessages INTO $upstream"
    

すべてのルートをまとめれば、"$edgeHub" ノードは次の JSON のようになります。

"$edgeHub": {
  "properties.desired": {
    "schemaVersion": "1.0",
    "routes": {
      "leafMessagesToRouter": "FROM /messages/* WHERE NOT IS_DEFINED($connectionModuleId) INTO BrokeredEndpoint(\"/modules/turbofanRouter/inputs/deviceInput\")",
      "classifierToRouter": "FROM /messages/modules/turbofanRulClassifier/outputs/amlOutput INTO BrokeredEndpoint(\"/modules/turbofanRouter/inputs/rulInput\")",
      "routerToClassifier": "FROM /messages/modules/turbofanRouter/outputs/classOutput INTO BrokeredEndpoint(\"/modules/turbofanRulClassifier/inputs/amlInput\")",
      "routerToIoTHub": "FROM /messages/modules/turboFanRouter/outputs/hubOutput INTO $upstream",
      "routerToAvro": "FROM /messages/modules/turbofanRouter/outputs/avroOutput INTO BrokeredEndpoint(\"/modules/avroFileWriter/inputs/avroModuleInput\")",
      "deadLetter": "FROM /messages/modules/turboFanRouter/outputs/deadMessages INTO $upstream"
    },
    "storeAndForwardConfiguration": {
      "timeToLiveSecs": 7200
    }
  }
}

turbofanRouter モジュールを追加すると、次の追加ルートが作成されました: turbofanRouterToIoTHub": "FROM /messages/modules/turbofanRouter/outputs/* INTO $upstream。 上記のルートのみを deployment.template.json ファイルに残して、このルートを削除します。

Avro ライター モジュールの追加

Avro ライター モジュールには、メッセージを格納してファイルをアップロードする 2 つの責任があります。

  • メッセージを格納する: Avro ライター モジュールは、メッセージを受信すると、Avro 形式でローカル ファイル システムにメッセージを書き込みます。 バインド マウントを使用します。これにより、ディレクトリ (この場合は /data/avrofiles) がモジュールのコンテナー内のパスにマウントされます。 このマウントにより、モジュールはローカル パス (/avrofiles) に書き込み、それらのファイルに IoT Edge デバイスから直接アクセスできるようになります。

  • ファイルのアップロード: Avro ライター モジュールは、Azure IoT Hub ファイルのアップロード機能を使用して、Azure ストレージ アカウントにファイルをアップロードします。 ファイルが正常にアップロードされると、モジュールはディスクからファイルを削除します。

モジュールの作成とファイルのコピー

  1. Visual Studio Code で、[ 表示>コマンド パレット] を選択し、[ Python: インタープリターの選択] を検索して選択します。

  2. インストールされている Python バージョン 3.7 以降を選択します。

  3. Visual Studio Code で modules フォルダーを右クリックし、[ IoT Edge モジュールの追加] を選択します。

  4. [Python モジュール] を選択します。

  5. モジュールに avroFileWriterという名前を付けます。

  6. Docker イメージ リポジトリの入力を求められたら、ルーター モジュールを追加するときに使用したのと同じレジストリを使用します。

  7. サンプル モジュールからソリューションにファイルをコピーします。

    copy C:\source\IoTEdgeAndMlSample\EdgeModules\modules\avroFileWriter\*.py C:\source\IoTEdgeAndMlSample\EdgeSolution\modules\avroFileWriter\
    
  8. main.py の上書きを受け入れます。

  9. filemanager.py と schema.py がソリューションに追加され、main.py が更新されていることに注意してください。

Python ファイルを開くと、pylint のインストールを求められる場合があります。 このチュートリアルを完了するためにリンターをインストールする必要はありません。

データ ファイル用のバインド マウント

前述のように、ライター モジュールは、Avro ファイルをデバイスのファイル システムに書き込むバインド マウントの存在に依存します。

デバイスにディレクトリを追加する

  1. Azure ポータルで、IoT Edge デバイス VM が実行されていない場合は起動します。 SSH を使用して接続します。 接続には、Azure portal の VM の概要ページからコピーできる DNS 名が必要です。

    ssh -l <user>@<vm name>.<region>.cloudapp.azure.com
    
  2. ログイン後、保存されたダウンストリーム デバイス メッセージを保持するディレクトリを作成します。

    sudo mkdir -p /data/avrofiles
    
  3. コンテナーによって書き込み可能になるようにディレクトリのアクセス許可を更新します。

    sudo chmod ugo+rw /data/avrofiles
    
  4. ディレクトリに、ユーザー、グループ、および所有者に対する書き込み (w) アクセス許可があることを確認します。

    ls -la /data
    

    avrofiles のディレクトリアクセス許可

モジュールにディレクトリを追加する

モジュールのコンテナーにディレクトリを追加するには、avroFileWriter モジュールに関連付けられている Dockerfile を変更します。 このモジュールには、Dockerfile.amd64、Dockerfile.amd64.debug、Dockerfile.arm32v7 の 3 つの Dockerfile が関連付けられています。 arm32 デバイスをデバッグまたはデプロイする場合は、これらのファイルを同期したままにする必要があります。 この記事では、Dockerfile.amd64 のみに注目してください。

  1. 開発用 VM で、 C:\source\IoTEdgeAndMlSample\EdgeSolution\modules\avoFileWriter\Dockerfile.amd64 ファイルを開きます。

  2. 次の例のようにファイルを変更します。

    FROM ubuntu:xenial
    
    WORKDIR /app
    
    RUN apt-get update && apt-get install -y --no-install-recommends libcurl4-openssl-dev
    python3-pip libboost-python1.58-dev libpython3-dev && rm -rf /var/lib/apt/lists/*
    
    RUN pip3 install --upgrade pip
    COPY requirements.txt ./
    RUN pip install -r requirements.txt
    
    COPY . .
    
    RUN useradd -ms /bin/bash moduleuser
    RUN mkdir /avrofiles && chown moduleuser /avrofiles
    USER moduleuser
    
    CMD [ "python3", "-u", "./main.py" ]
    

    mkdirコマンドとchown コマンドは、イメージ内に /avrofiles という最上位レベルのディレクトリを作成し、moduleuser をそのディレクトリの所有者にするように Docker ビルド プロセスに指示します。 これらのコマンドは、モジュール ユーザーが useradd コマンドを使用してイメージに追加された後、コンテキストが moduleuser (USER moduleuser) に切り替わる前に挿入することが重要です。

  3. 必要に応じて、Dockerfile.amd64.debug と Dockerfile.arm32v7 に対応する変更を行います。

avroFileWriter にバインド構成を追加する

バインドを作成する最後の手順は、バインド情報を使用して deployment.template.json (および deployment.debug.template.json) ファイルを更新することです。

  1. deployment.template.jsonを開きます。

  2. コンテナー ディレクトリ /avrofiles をエッジ デバイス上のローカル ディレクトリにポイントする Binds パラメーターを追加して、avroFileWriter のモジュール定義を変更します。 モジュール定義は、次の例と一致する必要があります。

    "avroFileWriter": {
      "version": "1.0",
      "type": "docker",
      "status": "running",
      "restartPolicy": "always",
      "settings": {
        "image": "${MODULES.avroFileWriter}",
        "createOptions": {
          "HostConfig": {
            "Binds": [
              "/data/avrofiles:/avrofiles"
            ]
          }
        }
      }
    }
    

config.yaml にアクセスするためのバインド マウント

ライター モジュールにもう 1 つのバインドを追加する必要があります。 このバインドは、IoT Edge デバイス上の /etc/iotedge/config.yaml ファイルから接続文字列を読み取るアクセス権をモジュールに与えます。 IoT Hub にファイルをアップロードするために upload_blob_async メソッドを呼び出すことができるように、IoTHubClient を作成するには接続文字列が必要です。 このバインドを追加する手順は、前のセクションの手順と似ています。

ディレクトリの権限を更新する

  1. SSH を使用して IoT Edge デバイスに接続します。

    ssh -l <user>@IoTEdge-<extension>.<region>.cloudapp.azure.com
    
  2. config.yaml ファイルに読み取りアクセス許可を追加します。

    sudo chmod +r /etc/iotedge/config.yaml
    
  3. アクセス許可が正しく設定されていることを確認します。

    ls -la /etc/iotedge/
    
  4. config.yaml のアクセス許可が -r--r--r--であることを確認します。

モジュールにディレクトリを追加する

  1. 開発用コンピューターで、 Dockerfile.amd64 ファイルを開きます。

  2. ファイルに mkdir コマンドと chown コマンドのセットを追加して、次のようにします。

    FROM ubuntu:xenial
    
    WORKDIR /app
    
    RUN apt-get update && apt-get install -y --no-install-recommends libcurl4-openssl-dev
    python3-pip libboost-python1.58-dev libpython3-dev && rm -rf /var/lib/apt/lists/\*
    
    RUN pip3 install --upgrade pip
    COPY requirements.txt ./
    RUN pip install -r requirements.txt
    
    COPY . .
    
    RUN useradd -ms /bin/bash moduleuser
    RUN mkdir /avrofiles && chown moduleuser /avrofiles
    RUN mkdir -p /app/iotconfig && chown moduleuser /app/iotconfig
    
    USER moduleuser
    
    CMD "python3", "-u", "./main.py"]
    
  3. Dockerfile.amd64.debug と Dockerfile.arm32v7 に対応する変更を行います。

モジュール構成を更新する

  1. deployment.template.json ファイルを開きます。

  2. avroFileWriter のモジュール定義を変更するには、コンテナー ディレクトリ (/app/iotconfig) をデバイス上のローカル ディレクトリ (/etc/iotedge) にポイントする 2 行目を Binds パラメーターに追加します。

    "avroFileWriter": {
      "version": "1.0",
      "type": "docker",
      "status": "running",
      "restartPolicy": "always",
      "settings": {
        "image": "${MODULES.avroFileWriter}",
        "createOptions": {
          "HostConfig": {
            "Binds": [
              "/data/avrofiles:/avrofiles",
              "/etc/iotedge:/app/iotconfig"
            ]
          }
        }
      }
    }
    
  3. deployment.debug.template.jsonに対応する変更を行います。

依存関係のインストール

ライター モジュールは、fastavro と PyYAML という 2 つの Python ライブラリに依存します。 開発マシンに依存関係をインストールし、Docker ビルド プロセスにモジュールのイメージにインストールするように指示する必要があります。

PyYAML

  1. 開発用コンピューターで、 C:\source\IoTEdgeAndMlSample\EdgeSolution\modules\avoFileWriter\requirements.txt ファイルを開き、ファイル内の新しい行に "pyyaml" を追加します。

    azure-iothub-device-client~=1.4.3
    pyyaml
    
  2. Dockerfile.amd64 ファイルを開き、pip install コマンドを追加して setuptools をアップグレードします。

    FROM ubuntu:xenial
    
    WORKDIR /app
    
    RUN apt-get update && \
        apt-get install -y --no-install-recommends libcurl4-openssl-dev python3-pip libboost-python1.58-dev libpython3-dev && \
        rm -rf /var/lib/apt/lists/\*
    
    RUN pip3 install --upgrade pip
    RUN pip install -U pip setuptools
    COPY requirements.txt ./
    RUN pip install -r requirements.txt
    
    COPY . .
    
    RUN useradd -ms /bin/bash moduleuser
    RUN mkdir /avrofiles && chown moduleuser /avrofiles
    RUN mkdir -p /app/iotconfig && chown moduleuser /app/iotconfig
    USER moduleuser
    
    CMD [ "python3", "-u", "./main.py" ]
    
  3. コマンド プロンプトで、pyyaml を開発用コンピューターにインストールします。

    pip install pyyaml
    

Fastavro

  1. requirements.txtで、pyyaml の後に fastavro を追加します。

    azure-iothub-device-client~=1.4.3
    pyyaml
    fastavro
    
  2. 開発用コンピューターに fastavro をインストールします。

    pip install fastavro
    

IoT Hub の再構成

IoT Edge デバイスとモジュールをシステムに導入することで、ハブに送信されるデータと目的に関する期待が変わりました。 新しい現実に対処するには、ハブ内のルーティングを再構成する必要があります。

モジュールをデプロイする前にハブを再構成します。これは、avroFileWriter モジュールが正しく実行されるように、一部のハブ設定 (特にファイルのアップロード) を正しく設定する必要があるためです。

IoT Hub で RUL メッセージのルートを設定する

ルーターと分類子を配置すると、デバイス ID とデバイスの RUL 予測のみを含む通常のメッセージが受信される予定です。 RUL データを独自のストレージの場所にルーティングし、デバイスの状態を監視し、レポートを作成し、必要に応じてアラートを発生させることができます。 同時に、まだ IoT Edge デバイスに接続されていないダウンストリーム デバイスから直接送信されているデバイス データを、現在のストレージの場所に引き続きルーティングする必要があります。

RUL メッセージ ルートを作成する

  1. Azure portal で、お使いの IoT Hub に移動します。

  2. 左側のウィンドウのメニューの [ ハブの設定] で、[ メッセージ ルーティング] を選択します。

  3. [ルート] タブ 、[ 追加] を選択します。

  4. ルートに RulMessageRoute という名前を付けます

  5. [エンドポイント] セレクターの右側にある [エンドポイント追加] を選択し、[ストレージ] を選択します

  6. [ ストレージ エンドポイントの追加] ページで 、エンドポイントに ruldata という名前を付けます。

  7. [コンテナーを選択します] を選択します。

  8. [ストレージ アカウント] ページで、このチュートリアル全体で使用しているストレージ アカウントを見つけます。この名前は >のようになります。

  9. ruldata コンテナーを選択し、[選択] をクリックします。

  10. [ ストレージ エンドポイントの追加 ] ページに戻り、[ 作成 ] を選択してストレージ エンドポイントを作成します。

  11. [ルートの 追加 ] ページに戻り、 ルーティング クエリtrue を次のクエリに置き換えます。

    IS_DEFINED($body.PredictedRul) AND NOT IS_DEFINED($body.OperationalSetting1)
    
  12. [ テスト ] セクションを展開し、[ メッセージ本文 ] セクションを展開します。 メッセージ本文を、想定されるメッセージの次の例に置き換えます。

    {
      "ConnectionDeviceId": "aaLeafDevice_1",
      "CorrelationId": "b27e97bb-06c5-4553-a064-e9ad59c0fdd3",
      "PredictedRul": 132.62721409309165,
      "CycleTime": 64.0
    }
    
  13. [ テスト ルート] を選択します。 テストが成功した場合は、"メッセージがクエリと一致しました" と表示されます。

  14. [保存] をクリックします。

turbofanDeviceDataToStorage ルートを更新する

新しい予測データを古いストレージの場所にルーティングしたくないので、ルートを更新してそれを防ぎます。

  1. [IoT Hub メッセージ ルーティング ] ページで、[ ルート ] タブを選択します。

  2. turbofanDeviceDataToStorage、または最初のデバイス データ ルートに指定した名前を選択します。

  3. ルーティングクエリを更新する。

    IS_DEFINED($body.OperationalSetting1)
    
  4. [ テスト ] セクションを展開し、[ メッセージ本文 ] セクションを展開します。 メッセージを、想定されるメッセージの次の例に置き換えます。

    {
      "Sensor13": 2387.96,
      "OperationalSetting1": -0.0008,
      "Sensor6": 21.61,
      "Sensor11": 47.2,
      "Sensor9": 9061.45,
      "Sensor4": 1397.86,
      "Sensor14": 8140.39,
      "Sensor18": 2388.0,
      "Sensor12": 522.87,
      "Sensor2": 642.42,
      "Sensor17": 391.0,
      "OperationalSetting3": 100.0,
      "Sensor1": 518.67,
      "OperationalSetting2": 0.0002,
      "Sensor20": 39.03,
      "DeviceId": 19.0,
      "Sensor5": 14.62,
      "PredictedRul": 212.00132402791962,
      "Sensor8": 2388.01,
      "Sensor16": 0.03,
      "CycleTime": 42.0,
      "Sensor21": 23.3188,
      "Sensor15": 8.3773,
      "Sensor3": 1580.09,
      "Sensor10": 1.3,
      "Sensor7": 554.57,
      "Sensor19": 100.0
    }
    
  5. [ テスト ルート] を選択します。 テストが成功した場合は、"メッセージがクエリと一致しました" と表示されます。

  6. [保存] を選択します。

ファイルのアップロードを構成する

IoT Hub ファイルアップロード機能を構成して、ファイル ライター モジュールがファイルをストレージにアップロードできるようにします。

  1. IoT Hub の左側のウィンドウ メニューの [ ハブの設定] で、[ ファイルのアップロード] を選択します。

  2. [Azure Storage コンテナー] を選択します

  3. 一覧からストレージ アカウントを選択します。

  4. guid が付加された azureml-blobstore で始まるコンテナーを選択し、[ 選択] をクリックします。

  5. [保存] を選択します。 保存が完了すると、ポータルから通知が表示されます。

このチュートリアルではアップロード通知を有効にしていませんが、ファイルアップロード通知の処理方法の詳細については、「 ファイルアップロード通知を受信 する」を参照してください。

モジュールのビルド、発行、デプロイ

構成の変更を行ったので、イメージをビルドして Azure コンテナー レジストリに発行する準備ができました。 ビルド プロセスでは、deployment.template.json ファイルを使用して、ビルドする必要があるモジュールを決定します。 バージョンを含む各モジュールの設定は、モジュール フォルダーの module.json ファイルにあります。 ビルド プロセスでは、最初に、module.json ファイル内にある現在の構成と一致する Dockerfile で Docker ビルドが実行され、イメージが作成されます。 次に、module.json ファイル内のバージョン タグと一致するバージョン タグを使用して、module.json ファイルからレジストリにイメージを発行します。 最後に、構成固有の配置マニフェスト (たとえば、deployment.amd64.json) が生成され、IoT Edge デバイスにデプロイされます。 IoT Edge デバイスは配置マニフェストから情報を読み取り、指示に基づいてモジュールをダウンロードし、ルートを構成し、必要なプロパティを設定します。 この展開方法には、注意する必要がある 2 つの副作用があります。

  • デプロイの遅延: IoT Edge ランタイムは、再構成を開始する前に目的のプロパティへの変更を認識する必要があるため、ランタイムがモジュールを選択して IoT Edge デバイスの更新を開始するまで、モジュールのデプロイ後にしばらく時間がかかる場合があります。

  • モジュールのバージョンは重要です。 前のモジュールと同じバージョン タグを使用してモジュールのコンテナーの新しいバージョンをコンテナー レジストリに発行した場合、ランタイムはモジュールの新しいバージョンをダウンロードしません。 ローカル イメージのバージョン タグと配置マニフェストの目的のイメージの比較が行われます。 これらのバージョンが一致する場合、ランタイムはアクションを実行しません。 そのため、新しい変更をデプロイするたびにモジュールのバージョンをインクリメントすることが重要です。 変更するモジュールの module.json ファイルのタグ プロパティの下にあるバージョン プロパティを変更して、バージョンをインクリメントします。 次に、モジュールをビルドして発行します。

    {
      "$schema-version": "0.0.1",
      "description": "",
      "image": {
        "repository": "<your registry>.azurecr.io/avrofilewriter",
        "tag": {
          "version": "0.0.1",
          "platforms": {
            "amd64": "./Dockerfile.amd64",
            "amd64.debug": "./Dockerfile.amd64.debug",
            "arm32v7": "./Dockerfile.arm32v7"
          }
        },
        "buildOptions": []
      },
      "language": "python"
    }
    

ビルドと公開

  1. 開発用 VM で、Docker が実行されていない場合は起動します。

  2. Visual Studio Code で、コマンド プロンプトで新しいターミナルを起動し、Azure コンテナー レジストリ (ACR) にログインします。

必要なユーザー名、パスワード、ログイン サーバーの値は、Azure portal で確認できます。 コンテナー レジストリ名の形式は "turbofandemo<unique id>" です。 左側のウィンドウ メニューの [設定] で、[ アクセス キー ] を選択して表示します。

docker login -u <ACR username> -p <ACR password> <ACR login server>
  1. Visual Studio Code で、deployment.template.json を右クリックし、[ IoT Edge ソリューションのビルドとプッシュ] を選択します。

レジストリ内のモジュールを表示する

ビルドが正常に完了すると、Azure portal を使用して発行されたモジュールを確認できるようになります。

  1. このチュートリアルでは、Azure Container Registry を開きます。 コンテナー レジストリ名の形式は "turbofandemo<unique id>" です。

  2. 左側のウィンドウ メニューの [ サービス] で[ リポジトリ] を選択します。

  3. 作成した両方のモジュール (avrofilewriterturbofanrouter) がリポジトリとして表示されることに注意してください。

  4. turbofanrouter を選択し、0.0.1-amd64 としてタグ付けされた 1 つのイメージを公開していることに注意してください。

    turbofanrouter の最初のタグ付きバージョンを表示する

モジュールを IoT Edge デバイスにデプロイする

ソリューションでモジュールをビルドして構成しました。次に、モジュールを IoT Edge デバイスにデプロイします。

  1. Visual Studio Code で、config フォルダー内の deployment.amd64.json ファイルを右クリックします。

  2. [ Create Deployment for Single Device]\(単一デバイスのデプロイの作成\) を選択します

  3. IoT Edge デバイス aaTurboFanEdgeDevice を選択します。

  4. Visual Studio Code エクスプローラーで Azure IoT Hub デバイス パネルを更新します。 3 つの新しいモジュールがデプロイされているが、まだ実行されていないことがわかります。

  5. 数分後にもう一度更新すると、モジュールが実行されていることがわかります。

    Visual Studio Code で実行中のモジュールを表示する

モジュールが開始され、安定した実行状態に落ち着くまでに数分かかる場合があります。 その間、IoT Edge ハブ モジュールとの接続を確立しようとするときに、モジュールの開始と停止が表示されることがあります。

エラーの診断

このセクションでは、モジュールまたはモジュールの問題を理解するためのいくつかの手法について説明します。 多くの場合、最初に Visual Studio Code のステータスで障害が検出されることがあります。

失敗したモジュールを特定する

  • Visual Studio Code: Azure IoT Hub デバイス パネルを確認します。 ほとんどのモジュールが実行中の状態で、1 つが停止している場合は、その停止したモジュールをさらに調査する必要があります。 すべてのモジュールが長時間停止状態にある場合は、障害も示している可能性があります。

  • Azure portal: ポータルで IoT ハブに移動し、デバイスの詳細ページ ([IoT Edge] でデバイスをドリルダウン) を見つけることで、モジュールがエラーを報告したか、IoT ハブに何も報告したことがないことがわかります。

デバイスからの診断

IoT Edge デバイス (ここでは Linux VM) にログインすることで、モジュールの状態に関する適切な情報にアクセスできます。 使用する主なメカニズムは、デバイス上のコンテナーとイメージを調べるために使用する Docker コマンドです。

  1. IoT Edge デバイスにログインします。

    ssh -l <user>@IoTEdge-<extension>.<region>.cloudapp.azure.com
    
  2. 実行中のすべてのコンテナーを一覧表示します。 モジュールに対応する名前を持つ各モジュールのコンテナーが表示されます。 また、このコマンドは、バージョンを含むコンテナの正確なイメージを一覧表示するので、期待に沿っているか確認できます。 コマンドで "container" の "image" を置き換えることで、イメージを一覧表示することもできます。

    sudo docker container ls
    
  3. コンテナーのログを取得します。 このコマンドは、コンテナー内の StdErr と StdOut に書き込まれたものを出力します。 このコマンドは、何らかの理由で起動してから終了したコンテナーに対して機能します。 また、edgeAgent または edgeHub コンテナーで何が起こっているのかを理解するのにも役立ちます。

    sudo docker container logs <container id>
    
  4. コンテナーを検査します。 このコマンドは、イメージに関するたくさんの情報を表示します。 データは、探しているものに応じてフィルター処理できます。 例として、avroFileWriter のバインドが正しいかどうかを確認する場合は、次のコマンドを使用できます。

    sudo docker container inspect -f "{{ json .Mounts }}" avroFileWriter | python -m json.tool
    
  5. 実行中のコンテナーに接続します。 このコマンドは、実行中にコンテナーを調べる場合に役立ちます。

    sudo docker exec -it avroFileWriter bash
    

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

このチュートリアルは、各記事が前の記事で行われた作業に基づいて構築されるセットの一部です。 最後のチュートリアルが完了するまで、リソースのクリーンアップをお待ちください。

次のステップ

この記事では、分類子、ルーター、ファイル ライター/アップローダーの 3 つのモジュールを使用して、Visual Studio Code で IoT Edge ソリューションを作成しました。 モジュールがエッジ デバイス上で相互に通信できるように、ルートを設定します。 エッジ デバイスの構成を変更し、Dockerfile を更新して依存関係をインストールし、モジュールのコンテナーにバインド マウントを追加しました。

次に、IoT Hub の構成を更新して、種類に基づいてメッセージをルーティングし、ファイルのアップロードを処理しました。 すべてが整ったので、モジュールを IoT Edge デバイスにデプロイし、モジュールが正しく実行されていることを確認しました。

次の記事に進み、データの送信を開始し、ソリューションの動作を確認します。