チュートリアル: Visual Studio Code を使用して IoT Edge モジュールを開発する

適用対象:IoT Edge 1.4 checkmark IoT Edge 1.4

重要

IoT Edge 1.4 がサポートされているリリースです。 以前のリリースの場合は、「IoT Edge を更新する」を参照してください。

このチュートリアルでは、独自のコードを開発して IoT Edge デバイスにデプロイするまでを順を追って説明します。 Azure IoT Edge モジュールを使用して、ビジネス ロジックを実装するコードを IoT Edge デバイスに直接展開できます。 Linux デバイスへのコードのデプロイクイックスタートでは、IoT Edge デバイスを作成し、Azure Marketplace からモジュールをデプロイしました。

この記事には、2 つの IoT Edge 開発ツールの手順が含まれています。

  • "Azure IoT Edge 開発ツール" コマンド ライン (CLI)。 このツールは開発に適しています。
  • "Visual Studio Code 用の Azure IoT Edge ツール" 拡張機能。 拡張機能はメンテナンス モードになっています。

この記事の冒頭にあるツール セレクター ボタンを使用して、ツールのバージョンを選択してください。

このチュートリアルでは、以下の内容を学習します。

  • 開発マシンを設定する。
  • IoT Edge Tools を使用して、新しいプロジェクトを作成します。
  • プロジェクトを Docker コンテナーとしてビルドして、Azure コンテナー レジストリに格納します。
  • コードを IoT Edge デバイスにデプロイする。

このチュートリアルで作成する IoT Edge モジュールは、デバイスが生成する温度データをフィルター処理します。 これは、指定されたしきい値を温度が上回っているときにのみ、メッセージを上流に送信します。 エッジでのこの種の分析は、クラウドに送信および保存されるデータ量を削減するうえで役に立ちます。

前提条件

開発マシン:

  • 自分のパソコンまたは仮想マシンを使用できます。
  • 開発マシンでは、コンテナー エンジンを実行するために入れ子になった仮想化をサポートする必要があります。
  • コンテナー エンジンを実行できるほとんどのオペレーティング システムを使用して、Linux デバイス用の IoT Edge モジュールを開発することができます。 このチュートリアルでは、Windows コンピューターを使用しますが、macOS または Linux での既知の相違点を指摘します。
  • Visual Studio Code をインストールします
  • Azure CLI をインストールします。

Azure IoT Edge デバイス:

クラウド リソース:

  • Azure の Free レベルまたは Standard レベルの IoT Hub

Azure サブスクリプションをお持ちでない場合は、開始する前に Azure 無料アカウントを作成してください。

ヒント

Visual Studio Code または Visual Studio 2022 での対話型デバッグに関するガイダンスについて。

このチュートリアルでは、Visual Studio Code の開発手順を説明します。

主要な概念

このチュートリアルでは、IoT Edge モジュールの開発について順を追って説明します。 "IoT Edge モジュール" は、実行可能コードのコンテナーです。 IoT Edge デバイスには 1 つ以上のモジュールをデプロイできます。 モジュールは、センサーからのデータの取り込み、データのクリーニングと分析、IoT ハブへのメッセージの送信などの特定のタスクを実行します。 詳細については、「Azure IoT Edge モジュールについて」を参照してください。

IoT Edge モジュールを開発する場合は、開発マシンと、モジュールがデプロイされるターゲット IoT Edge デバイスの違いを理解することが重要です。 モジュール コードを保持するためにビルドするコンテナーは、ターゲット デバイスのオペレーティング システム (OS) と一致している必要があります。 たとえば、最も一般的なシナリオは、ある人が Windows コンピューターでモジュールを開発しているが、そのターゲットとして、IoT Edge を実行している Linux デバイスを予定している場合です。 その場合、コンテナーのオペレーティング システムは Linux になります。 このチュートリアルを進めていくときには、開発マシンの OSコンテナーの OS の違いに留意してください。

ヒント

IoT Edge for Linux on Windows を使用している場合、シナリオの "ターゲット デバイス" は、Windows ホストではなく Linux 仮想マシンです。

このチュートリアルでは、Linux コンテナーを使用して IoT Edge を実行しているデバイスをターゲットとしています。 ご使用の開発マシンで Linux コンテナーが実行される限り、自分の好きなオペレーティング システムを使用することができます。 Linux コンテナーを使用した開発には Visual Studio Code を使用することをお勧めします。そのため、このチュートリアルでもそれを使用します。 Visual Studio も使用できますが、この 2 つのツールの間にはサポートに違いがあります。

次の表に、Linux コンテナーに関して Visual Studio Code と Visual Studio でサポートされる開発シナリオを示します。

Visual Studio Code Visual Studio 2019/2022
Linux のデバイスのアーキテクチャ Linux AMD64
Linux ARM32v7
Linux ARM64
Linux AMD64
Linux ARM32
Linux ARM64
Azure サービス Azure Functions
Azure Stream Analytics
Azure Machine Learning
Languages C
C#
Java
Node.js
Python
C
C#
詳細情報 Visual Studio Code 用の Azure IoT Edge Visual Studio 2019 用の Azure IoT Edge ツール
Visual Studio 2022 用の Azure IoT Edge Tools

コンテナー エンジンをインストールする

IoT Edge モジュールはコンテナーとしてパッケージ化されるので、それらをビルドおよび管理するためには、開発用コンピューター上に Docker 互換のコンテナー管理システムが必要です。 機能のサポートと人気があるため、開発には Docker Desktop をお勧めします。 Windows で Docker デスクトップ を使用すると、Linux コンテナーと Windows コンテナーを切り替えて、さまざまな型の IoT Edge デバイス用のモジュールを開発することができます。

次の Docker のドキュメントを使用して、ご使用の開発マシンにインストールします。

  • Install Docker Desktop for Windows

    • Docker Desktop for Windows をインストールするときに、Linux コンテナーを使用するか Windows コンテナーを使用するかを尋ねられます。 この決定はいつでも変更できます。 このチュートリアルでは、モジュールが Linux デバイスをターゲットとしているので Linux コンテナーを使用します。 詳細については、「Switch between Windows and Linux containers」を参照してください。
  • Install Docker Desktop for Windows

  • いくつかの Linux プラットフォームでのインストール情報については、「About Docker CE」をお読みください。

    • Linux 用 Windows サブシステム (WSL) の場合は、Docker Desktop for Windows をインストールします。

ツールを設定する

IoT Edge ソリューションを作成するための、Python ベースの Azure IoT Edge 開発ツールをインストールします。 2 つのオプションがあります。

重要

"Visual Studio Code 用の Azure IoT Edge Tools" 拡張機能は、メンテナンス モードになっています。 推奨される開発ツールは、コマンド ライン (CLI) の "Azure IoT Edge 開発ツール" です。

Visual Studio Code の IoT 拡張機能を使用して、IoT Edge モジュールを開発します。 これらの拡張機能は、プロジェクト テンプレートを提供し、配置マニフェストの作成を自動化し、IoT Edge デバイスの監視および管理を可能にします。 このセクションでは、Visual Studio Code と IoT 拡張機能をインストールし、次に Visual Studio Code 内から IoT Hub のリソースを管理する Azure アカウントを設定します。

  1. Azure IoT Edge 拡張機能をインストールします。

  2. Azure IoT Hub 拡張機能をインストールします。

  3. 拡張機能をインストールしたら、[表示]>[コマンド パレット]を選択してコマンド パレットを開きます。

  4. 再度コマンド パレットで、「Azure IoT Hub:IoT Hub の選択」を検索して選びます。 プロンプトに従って、Azure サブスクリプションと IoT Hub を選択します。

  5. 左側のアクティビティ バーでアイコンを選択するか、 [表示]>[エクスプローラー] を選択して、Visual Studio Code のエクスプローラー セクションを開きます。

  6. エクスプローラー セクションの下部で、折りたたまれている [Azure IoT Hub Devices](Azure IoT Hub デバイス) メニューを展開します。 コマンド パレットから選択した IoT Hub に関連付けられたデバイスと IoT Edge デバイスが表示されるはずです。

言語固有のツールをインストールする

開発に使用する言語に固有のツールをインストールします:

コンテナー レジストリの作成

このチュートリアルでは、Azure IoT Edge および Azure IoT Hub 拡張機能を使用してモジュールをビルドし、ファイルからコンテナー イメージを作成します。 その後、このイメージをレジストリにプッシュし、格納および管理します。 最後に、レジストリからイメージを展開し、IoT Edge デバイスで実行します。

重要

Azure IoT Edge Visual Studio Code 拡張機能はメンテナンス モードです。

コンテナー イメージは、Docker と互換性のある任意のレジストリを使用して格納できます。 2 つの一般的な Docker レジストリ サービスは、Azure Container RegistryDocker Hub です。 このチュートリアルでは、Azure Container Registry を使用します。

コンテナー レジストリがまだない場合は、次の手順に従って、Azure に新しいコンテナー レジストリを作成します。

  1. Azure portal で、 [リソースの作成]>[コンテナー]>[コンテナー レジストリ] の順に選択します。

  2. コンテナー レジストリを作成するために、以下の必須値を指定します。

    フィールド
    サブスクリプション ドロップダウン リストで、サブスクリプションを選択します。
    Resource group IoT Edge のクイックスタートおよびチュートリアルで作成したすべてのテスト リソースに対して同じリソース グループを使用します。 たとえば、IoTEdgeResources を使用します。
    レジストリ名 一意の名前を指定します。
    Location 近くの場所を選択します。
    SKU [Basic] を選択します。
  3. [確認および作成][作成] の順に選択します。

  4. Azure portal ホーム ページの [リソース] セクションから新しいコンテナー レジストリを選択して開きます。

  5. コンテナー レジストリの左側のウィンドウで、設定にあるメニューから [アクセス キー] を選択します。

    Screenshot of the Access Keys menu location.

  6. トグル ボタンを使用して 管理者ユーザー を有効にし、コンテナー レジストリの ユーザー名パスワード を表示します。

  7. ログイン サーバーユーザー名、およびパスワードの値をコピーして、どこか都合のいい場所に保存します。 このチュートリアルではこれらの値を使用して、コンテナー レジストリへのアクセスを提供します。

新しいモジュール プロジェクトを作成する

この Azure IoT Edge 拡張機能には、Visual Studio Code でサポートされているすべての IoT Edge モジュール言語のプロジェクト テンプレートが用意されています。 これらのテンプレートは、作業モジュールをデプロイして IoT Edge をテストするために必要なすべてのファイルとコードを含んでいます。または、独自のビジネス ロジックを使用してテンプレートをカスタマイズするための開始点を提供します。

プロジェクト テンプレートを作成する

IoT Edge 開発ツールを使用すると、環境変数によって駆動されるコマンドに Azure IoT Edge の開発が簡略化されます。 デフォルト モジュールと必要なすべての構成ファイルを含む IoT Edge 開発コンテナーと IoT Edge ソリューション スキャフォールディングを使用して、IoT Edge の開発を開始できます。

  1. 任意のパスを使用して、ソリューションのディレクトリを作成します。 iotedgesolution ディレクトリに 変更します。

    mkdir c:\dev\iotedgesolution
    cd c:\dev\iotedgesolution
    
  2. iotedgedev solution init コマンドを使用してソリューションを作成し、選択した開発言語で Azure IoT Hub を設定します。

    iotedgedev solution init --template csharp
    

iotedgedev solution init スクリプトでは、次のようないくつかの手順を完了するように求められます。

  • Azure に対して認証します
  • Azure サブスクリプションを選択する
  • リソース グループを選択または作成する
  • Azure IoT Hub を選択または作成する
  • Azure IoT Edge デバイスを選択または作成する

Visual Studio Code と Azure IoT Edge 拡張機能を使います。 まずはソリューションを作成し、次にそのソリューション内に最初のモジュールを生成します。 各ソリューションには複数のモジュールを含めることができます。

  1. [ビュー]>[コマンド パレット] を選択します。
  2. コマンド パレットで、Azure IoT Edge:New IoT Edge solution コマンドを入力して実行します。
  3. 新しいソリューションを作成するフォルダーを参照し、 [フォルダーの選択] を選択します。
  4. ソリューションの名前を入力します。
  5. ソリューション内の最初のモジュールになるように、好きな開発言語用のモジュール テンプレートを選択します。
  6. モジュールの名前を入力します。 コンテナー レジストリ内に一意の名前を選択します。
  7. モジュールのイメージ リポジトリの名前を指定します。 Visual Studio Code により、モジュール名には自動的に localhost:5000/<対象のモジュール名> が設定されます。 独自のレジストリ情報に置き換えます。 テスト用に Docker のローカル レジストリを使用する場合、localhost を使用します。 Azure Container Registry を使用する場合、お使いのレジストリの設定のログイン サーバーを使用します。 サインイン サーバーは <レジストリ名>.azurecr.io のようになります。 この文字列の localhost:5000 部分だけを置き換えて、最終的な結果が <レジストリ名>.azurecr.io/<対象のモジュール名> になるようにします。

Visual Studio Code は、指定された情報を取得し、IoT Edge ソリューションを作成して、それを新しいウィンドウに読み込みます。

ソリューションの作成後、次のメイン ファイルがソリューションに含まれます:

  • .vscode フォルダーには、構成ファイル launch.json が含まれています。

  • モジュール フォルダーにはモジュールごとのサブフォルダーが含まれています。 各モジュールのフォルダー内には module.json というファイルがあります。これは、モジュールのビルドとデプロイの方法を制御します。

  • .env ファイルには環境変数の一覧が表示されます。 コンテナー レジストリの環境変数は、既定では localhost:5000 です。

  • deployment.template.jsondeployment.debug.template.json という名前の 2 つのモジュール デプロイ ファイルでは、デバイスにデプロイするモジュールのリストが示されます。 既定では、このリストには、IoT Edge システム モジュール (edgeAgent と edgeHub) と次のようなサンプル モジュールが含まれます:

    注意

    インストールされる正確なモジュールは、選択した言語によって異なる場合があります。

IoT Edge ランタイム バージョンを設定する

最新の安定した IoT Edge システム モジュールのバージョンは 1.4 です。 システム モジュールをバージョン 1.4 に設定します。

  1. Visual Studio Code で、deployment.template.json 配置マニフェスト ファイルを開きます。 配置マニフェストは、ターゲットの IoT Edge デバイス上で構成されるモジュールを記述した JSON ドキュメントです。

  2. システム ランタイム モジュール イメージ edgeAgent および edgeHub のランタイム バージョンを変更します。 たとえば、IoT Edge ランタイム バージョン 1.4 を使用する場合は、配置マニフェスト ファイルで次の行を変更します。

    "systemModules": {
        "edgeAgent": {
    
            "image": "mcr.microsoft.com/azureiotedge-agent:1.4",
    
        "edgeHub": {
    
            "image": "mcr.microsoft.com/azureiotedge-hub:1.4",
    

レジストリの資格情報を IoT Edge エージェントに提供する

コンテナー レジストリの資格情報は、環境ファイルに格納され、IoT Edge ランタイムと共有されます。 ランタイムでは、コンテナー イメージを IoT Edge デバイスにプルするためにこれらの資格情報が必要です。

IoT Edge 拡張機能は、Azure からコンテナー レジストリの資格情報をプルし、それらを環境ファイルに取り込もうとします。

Note

環境ファイルは、モジュールのイメージ リポジトリを指定した場合にのみ作成されます。 localhost の既定値を受け入れてローカルでテストおよびデバッグする場合は、環境変数を宣言する必要はありません。

資格情報が存在するかどうかを確認します。 含まれていない場合は、次のようにして追加します。

  1. レジストリが Azure Container Registry の場合、Azure Container Registry のユーザー名とパスワードを設定します。 Azure portal のコンテナー レジストリの [設定]> [アクセス キー] メニューからこれらの値を取得します。

  2. モジュール ソリューション内の .env ファイルを開きます。

  3. Azure コンテナー レジストリからコピーした usernamepassword の値を追加します。 次に例を示します。

    CONTAINER_REGISTRY_SERVER="myacr.azurecr.io"
    CONTAINER_REGISTRY_USERNAME="myacr"
    CONTAINER_REGISTRY_PASSWORD="<registry_password>"
    
  4. 変更内容を .env ファイルに保存します。

注意

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

ターゲット アーキテクチャ

アーキテクチャはコンテナーのビルド方法と実行方法に影響を与えるため、ターゲットにしているアーキテクチャをソリューションごとに選択する必要があります。 既定値は Linux AMD64 です。 このチュートリアルでは、Ubuntu 仮想マシンを IoT Edge デバイスとして使用するため、既定値の amd64 のままにします。

ソリューションのターゲット アーキテクチャを変更する必要がある場合は、次のステップを使用します。

  1. コマンド パレットを開き、次を検索します: 「Azure IoT Edge: Set Default Target Platform for Edge Solution (Azure IoT Edge: Edge ソリューションの既定のターゲット プラットフォームの設定) 」。または、ウィンドウの下部にあるサイド バーで、ショートカット アイコンを選択します。

  2. コマンド パレットで、オプションの一覧からターゲット アーキテクチャを選択します。

ターゲット アーキテクチャは、後の手順でコンテナー イメージを作成するときに設定されます。

カスタム コードでモジュールを更新する

各テンプレートにはサンプル コードが付属しており、シミュレートされたセンサー データが SimulatedTemperatureSensor モジュールから取得され、IoT Hub にルーティングされます。 このサンプル モジュールは、メッセージを受け取って渡します。 パイプライン機能は、モジュールがどのようにして相互に通信を行うかという、IoT Edge での重要な概念を示します。

各モジュールは、コードで宣言された複数の 入力キューと 出力キューを持つことができます。 デバイスで実行されている IoT Edge ハブは、1 つのモジュールの出力から、1 つ以上のモジュールの入力にメッセージをルーティングします。 入力と出力を宣言するための特定のコードは、言語によって異なりますが、その概念はすべてのモジュールで同じです。 モジュール間のルーティングの詳細については、ルートの宣言に関する記事を参照してください。

プロジェクト テンプレートに含まれるサンプル C# コードには、.NET 用 IoT Hub SDK の ModuleClient クラスが使用されています。

  1. Visual Studio Code エクスプローラーで、[モジュール]>[filtermodule]>[ModuleBackgroundService.cs] の順に開きます。

  2. [filtermodule] 名前空間の前に、後で使用する型として 3 つの using ステートメントを追加します。

    using System.Collections.Generic;     // For KeyValuePair<>
    using Microsoft.Azure.Devices.Shared; // For TwinCollection
    using Newtonsoft.Json;                // For JsonConvert
    
  3. temperatureThreshold 変数を ModuleBackgroundService クラスに追加します。 この変数により、データが IoT Hub に送信される基準値が設定されます。データは、測定温度がこの値を超えると送信されます。

    static int temperatureThreshold { get; set; } = 25;
    
  4. MessageBodyMachineAmbient の各クラスを追加します。 これらのクラスは、受信メッセージの本文に対して予期されるスキーマを定義します。

    class MessageBody
    {
        public Machine machine {get;set;}
        public Ambient ambient {get; set;}
        public string timeCreated {get; set;}
    }
    class Machine
    {
        public double temperature {get; set;}
        public double pressure {get; set;}
    }
    class Ambient
    {
        public double temperature {get; set;}
        public int humidity {get; set;}
    }
    
  5. ExecuteAsync 関数を見つけます。 この関数では、ModuleClient オブジェクトを作成して構成します。これにより、モジュールはローカルの Azure IoT Edge ランタイムに接続して、メッセージを送受信できるようになります。 ModuleClient の作成後、コードによって、モジュール ツインの目的のプロパティから temperatureThreshold が読み取られ、 このコードによって、input1 と呼ばれるエンドポイントを介して IoT Edge ハブからメッセージを受信するためのコールバックが登録されます。

    ProcessMessageAsync メソッドの呼び出しを、エンドポイント名と入力の到着時に呼び出されるメソッドを更新する、新しいものに置き換えます。 また、必要なプロパティを更新するために SetDesiredPropertyUpdateCallbackAsync メソッドも追加します。 この変更を行うには、次のコードに ExecuteAsync メソッドの最後の行を置き換えます。

    // Register a callback for messages that are received by the module.
    // await _moduleClient.SetInputMessageHandlerAsync("input1", PipeMessage, cancellationToken);
    
    // Read the TemperatureThreshold value from the module twin's desired properties
    var moduleTwin = await _moduleClient.GetTwinAsync();
    await OnDesiredPropertiesUpdate(moduleTwin.Properties.Desired, _moduleClient);
    
    // Attach a callback for updates to the module twin's desired properties.
    await _moduleClient.SetDesiredPropertyUpdateCallbackAsync(OnDesiredPropertiesUpdate, null);
    
    // Register a callback for messages that are received by the module. Messages received on the inputFromSensor endpoint are sent to the FilterMessages method.
    await _moduleClient.SetInputMessageHandlerAsync("inputFromSensor", FilterMessages, _moduleClient);
    
  6. onDesiredPropertiesUpdate メソッドを ModuleBackgroundService クラスに追加します。 このメソッドは、モジュール ツインから対象プロパティの更新を受け取り、それに合わせて temperatureThreshold 変数を更新します。 すべてのモジュールに独自のモジュール ツインがあり、これにより、モジュール内で実行されているコードをクラウドから直接構成できます。

    static Task OnDesiredPropertiesUpdate(TwinCollection desiredProperties, object userContext)
    {
        try
        {
            Console.WriteLine("Desired property change:");
            Console.WriteLine(JsonConvert.SerializeObject(desiredProperties));
    
            if (desiredProperties["TemperatureThreshold"]!=null)
                temperatureThreshold = desiredProperties["TemperatureThreshold"];
    
        }
        catch (AggregateException ex)
        {
            foreach (Exception exception in ex.InnerExceptions)
            {
                Console.WriteLine();
                Console.WriteLine("Error when receiving desired property: {0}", exception);
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine();
            Console.WriteLine("Error when receiving desired property: {0}", ex.Message);
        }
        return Task.CompletedTask;
    }
    
  7. FilterMessages メソッドを追加します。 このメソッドは、モジュールが IoT Edge ハブからメッセージを受け取るたびに呼び出されます。 これにより、モジュール ツインで設定されているしきい値を下回る温度を報告するメッセージは除外されます。 また、MessageType プロパティを、値が Alert に設定されたメッセージに追加します。

    async Task<MessageResponse> FilterMessages(Message message, object userContext)
    {
        var counterValue = Interlocked.Increment(ref _counter);
        try
        {
            ModuleClient moduleClient = (ModuleClient)userContext;
            var messageBytes = message.GetBytes();
            var messageString = Encoding.UTF8.GetString(messageBytes);
            Console.WriteLine($"Received message {counterValue}: [{messageString}]");
    
            // Get the message body.
            var messageBody = JsonConvert.DeserializeObject<MessageBody>(messageString);
    
            if (messageBody != null && messageBody.machine.temperature > temperatureThreshold)
            {
                Console.WriteLine($"Machine temperature {messageBody.machine.temperature} " +
                    $"exceeds threshold {temperatureThreshold}");
                using (var filteredMessage = new Message(messageBytes))
                {
                    foreach (KeyValuePair<string, string> prop in message.Properties)
                    {
                        filteredMessage.Properties.Add(prop.Key, prop.Value);
                    }
    
                    filteredMessage.Properties.Add("MessageType", "Alert");
                    await moduleClient.SendEventAsync("output1", filteredMessage);
                }
            }
    
            // Indicate that the message treatment is completed.
            return MessageResponse.Completed;
        }
        catch (AggregateException ex)
        {
            foreach (Exception exception in ex.InnerExceptions)
            {
                Console.WriteLine();
                Console.WriteLine("Error in sample: {0}", exception);
            }
            // Indicate that the message treatment is not completed.
            var moduleClient = (ModuleClient)userContext;
            return MessageResponse.Abandoned;
        }
        catch (Exception ex)
        {
            Console.WriteLine();
            Console.WriteLine("Error in sample: {0}", ex.Message);
            // Indicate that the message treatment is not completed.
            ModuleClient moduleClient = (ModuleClient)userContext;
            return MessageResponse.Abandoned;
        }
    }
    
  8. ModuleBackgroundService.cs ファイルを保存します。

  9. Visual Studio Code エクスプローラーで、ご自身の IoT Edge ソリューション ワークスペースの deployment.template.json ファイルを開きます。

  10. モジュールがリッスンするエンドポイントの名前を変更したので、配置マニフェスト内のルートも、"edgeHub" が新しいエンドポイントにメッセージを送信するように更新する必要があります。

    $edgeHub モジュール ツインで routes セクションを見つけます。 sensorTofiltermodule ルートを更新して、input1inputFromSensor に置き換えます。

    "sensorTofiltermodule": "FROM /messages/modules/tempSensor/outputs/temperatureOutput INTO BrokeredEndpoint(\"/modules/filtermodule/inputs/inputFromSensor\")"
    
  11. filtermodule モジュール ツインを配置マニフェストに追加します。 次の JSON コンテンツを modulesContent セクションの下部、 $edgeHub モジュール ツインの後に挿入します。

       "filtermodule": {
           "properties.desired":{
               "TemperatureThreshold":25
           }
       }
    
  12. deployment.template.json ファイルを保存します。

ソリューションをビルドしてプッシュする

いくつかの主要なデプロイ概念を理解できるように、モジュール コードと展開テンプレートを更新しました。 次に、モジュール コンテナー イメージをビルドして、コンテナー レジストリにプッシュします。

Visual Studio Code で、deployment.template.json 配置マニフェスト ファイルを開きます。 配置マニフェストは、ターゲットの IoT Edge デバイス上で構成されるモジュールを記述します。 デプロイの前に、Azure Container Registry 資格情報とモジュール イメージを適切な createOptions の値で更新する必要があります。 createOption の値の詳細については、「IoT Edge モジュールのコンテナー作成オプションを構成する方法」を参照してください。

Azure Container Registry を使用してモジュール イメージを保存している場合は、deployment.template.jsonmodulesContent>edgeAgent>settings>registryCredentials セクションに資格情報を追加します。 myacr を独自のレジストリ名に置き換え、パスワードと ログイン サーバー アドレスを指定します。 次に例を示します。

"registryCredentials": {
    "myacr": {
        "username": "myacr",
        "password": "<your_acr_password>",
        "address": "myacr.azurecr.io"
    }
}

一覧表示されているシステム (edgeHub と edgeAgent) とカスタム モジュール (filtermodule と tempSensor) ごとに、次の文字列化されたコンテンツを "createOptions" の値に追加するか置き換えます。 必要に応じて、値を変更します。

"createOptions": "{\"HostConfig\":{\"PortBindings\":{\"5671/tcp\":[{\"HostPort\":\"5671\"}],\"8883/tcp\":[{\"HostPort\":\"8883\"}],\"443/tcp\":[{\"HostPort\":\"443\"}]}}}"

たとえば、filtermodule の構成は次のようになります:

"filtermodule": {
"version": "1.0",
"type": "docker",
"status": "running",
"restartPolicy": "always",
"settings": {
   "image": "myacr.azurecr.io/filtermodule:0.0.1-amd64",
   "createOptions": "{\"HostConfig\":{\"PortBindings\":{\"5671/tcp\":[{\"HostPort\":\"5671\"}],\"8883/tcp\":[{\"HostPort\":\"8883\"}],\"443/tcp\":[{\"HostPort\":\"443\"}]}}}"
}

モジュールの Docker イメージをビルドする

[ターミナル]>[新しいターミナル] の順に選択して、Visual Studio Code 統合ターミナルを開きます。

dotnet publish コマンドを使って、Linux および amd64 アーキテクチャ用のコンテナー イメージをビルドします。 ディレクトリをプロジェクトの filtermodule ディレクトリに変更し、dotnet publish コマンドを実行します。

dotnet publish --os linux --arch x64 /t:PublishContainer

現在、iotedgedev ツール テンプレートは .NET 7.0 を対象としています。 別のバージョンの .NET を対象にする場合は、filtermodule.csproj ファイルを編集して、TargetFrameworkPackageReference の値を変更します。 たとえば、.NET 8.0 を対象にするには、filtermodule.csproj ファイルは次のようになります。

<Project Sdk="Microsoft.NET.Sdk.Worker">
    <PropertyGroup>
        <TargetFramework>net8.0</TargetFramework>
        <Nullable>enable</Nullable>
        <ImplicitUsings>enable</ImplicitUsings>
    </PropertyGroup>
    <ItemGroup>
        <PackageReference Include="Microsoft.Azure.Devices.Client" Version="1.42.0" />
        <PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
    </ItemGroup>
</Project>

コンテナー レジストリ情報、バージョン、アーキテクチャで Docker イメージにタグを付けます。 myacr を独自のレジストリ名に置き換えます。

docker tag filtermodule myacr.azurecr.io/filtermodule:0.0.1-amd64

モジュールの Docker イメージをプッシュする

コンテナー イメージをレジストリ内のストレージにプッシュできるように、Docker にコンテナー レジステリの資格情報を提供します。

  1. Azure Container Registry (ACR) 資格情報を使って Docker にサインインします。

    docker login -u <ACR username> -p <ACR password> <ACR login server>
    

    --password-stdin の使用を推奨するセキュリティ警告が表示される場合があります。 これは運用環境のシナリオでの推奨されているベスト プラクティスですが、このチュートリアルの範囲外になります。 詳細については、docker login のリファレンスをご覧ください。

  2. Azure Container Registry にサインインします。 az コマンドを使うには、Azure CLI をインストールする必要があります。 このコマンドでは、[設定]>[アクセス キー] でのコンテナー レジストリで見つかったユーザー名とパスワードが求められます。

    az acr login -n <ACR registry name>
    

    ヒント

    このチュートリアルの任意の時点でログアウトした場合、Docker および Azure Container Registry のサインイン ステップを繰り返して続行します。

  3. モジュール イメージをローカル レジストリまたはコンテナー レジストリにプッシュします。

    docker push <ImageName>
    

    次に例を示します。

    # Push the Docker image to the local registry
    
    docker push localhost:5000/filtermodule:0.0.1-amd64
    
    # Or push the Docker image to an Azure Container Registry. Replace myacr with your Azure Container Registry name.
    
    az acr login --name myacr
    docker push myacr.azurecr.io/filtermodule:0.0.1-amd64
    

デプロイ テンプレートを更新する

デプロイ テンプレート "deployment.template.json" をコンテナー レジストリ イメージの場所で更新します。 たとえば、Azure Container Registry "myacr.azurecr.io" を使用していて、イメージが "filtermodule:0.0.1-amd64" の場合は、"filtermodule" 構成を次のように更新します。

"filtermodule": {
    "version": "1.0",
    "type": "docker",
    "status": "running",
    "restartPolicy": "always",
    "settings": {
        "image": "myacr.azurecr.io/filtermodule:0.0.1-amd64",
        "createOptions": "{\"HostConfig\":{\"PortBindings\":{\"5671/tcp\":[{\"HostPort\":\"5671\"}],\"8883/tcp\":[{\"HostPort\":\"8883\"}],\"443/tcp\":[{\"HostPort\":\"443\"}]}}}"
    }
}

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

ビルドおよびプッシュ コマンドでは、3 つの操作を開始します。 最初に、デプロイ テンプレートと他のソリューション ファイルの情報からビルドされた完全な配置マニフェストを保持する、config という新しいフォルダーをソリューション内に作成します。 次に、docker build を実行して、お使いのターゲット アーキテクチャ用の適切な Dockerfile に基づいてコンテナー イメージをビルドします。 そして、docker push を実行して、イメージ リポジトリをコンテナー レジストリにプッシュします。

このプロセスは、初回は数分間かかる可能性がありますが、次回これらのコマンドを実行するときは、それより速くなります。

省略可能: モジュールとイメージを更新する

モジュール コードを変更する場合は、モジュール イメージをリビルドしてコンテナー レジストリにプッシュする必要があります。 このセクションの手順を使って、ビルドとコンテナー イメージを更新します。 モジュール コードを変更しなかった場合は、このセクションをスキップできます。

新しく作成した config フォルダーで deployment.amd64.json ファイルを開きます。 このファイル名はターゲット アーキテクチャを反映しているため、別のアーキテクチャを選択した場合は別の名前になります。

プレースホルダーがある 2 つのパラメーターに、適切な値が入れられていることに注意してください。 RegistryCredentials セクションには、.envファイルからプルされたレジストリのユーザー名とパスワードが入っています。 filtermodule には、module.jsonファイルからの名前、バージョン、アーキテクチャのタグを含む完全なイメージ レポジトリがあります。

  1. filtermodule フォルダー内の module.json ファイルを開きます。

  2. モジュール イメージのバージョン番号を変更します。 たとえば、モジュール コードで軽微な修正を行ったかのように、パッチのバージョン番号を "version": "0.0.2" に増分します。

    ヒント

    モジュール バージョンではバージョン管理が有効であり、実稼働環境に更新プログラムをデプロイする前に、少数のデバイスで変更をテストすることができます。 ビルドとプッシュの前にモジュール バージョンを増分しないと、コンテナー レジストリ内のリポジトリが上書きされます。

  3. 変更内容を module.json ファイルに保存します。

0.0.2 バージョン タグを使用して、更新されたイメージをビルドしてプッシュします。 たとえば、ローカル レジストリまたは Azure コンテナー レジストリのイメージをビルドしてプッシュするには、次のコマンドを使用します:


# Build the container image for Linux and amd64 architecture.

dotnet publish --os linux --arch x64

# For local registry:
# Tag the image with version 0.0.2, x64 architecture, and the local registry.

docker tag filtermodule localhost:5000/filtermodule:0.0.2-amd64

# For Azure Container Registry:
# Tag the image with version 0.0.2, x64 architecture, and your container registry information. Replace **myacr** with your own registry name.

docker tag filtermodule myacr.azurecr.io/filtermodule:0.0.2-amd64

deployment.template.json ファイルをもう一度右クリックし、 [Build and Push IoT Edge Solution](IoT Edge ソリューションのビルドとプッシュ) を再度選択します。

deployment.amd64.json ファイルを再び開きます。 ビルド コマンドとプッシュ コマンドをもう一度実行しても、ビルド システムで新しいファイルが作成されないことに注意してください。 代わりに、同じファイルが変更を反映するように更新されます。 "filtermodule" イメージは現在、コンテナーの 0.0.2 バージョンを指しています。

ビルドおよびプッシュ コマンドで何が行われたかをさらに確認するには、Azure portal にアクセスして、コンテナー レジストリに移動します。

コンテナー レジストリで、[リポジトリ]、次に samplemodule を選択します。 イメージの両方のバージョンがレジストリにプッシュされることを確認します。

Screenshot of where to view both image versions in your container registry.

トラブルシューティング

モジュール イメージをビルドおよびプッシュしているときにエラーが発生する場合は、開発マシン上の Docker 構成に関連していることがよくあります。 次のチェックを使用して構成を確認してください。

  • コンテナー レジストリからコピーした資格情報を使用して docker login コマンドを実行したか。 これらの資格情報は、Azure にサインインする際に使用するものとは異なります。
  • コンテナー リポジトリは正しいか。 正しいコンテナー レジストリ名と正しいモジュール名が含まれているか。 "filtermodule" フォルダー内の module.json ファイルを確認のために開きます。 リポジトリ値は、<レジストリ名>.azurecr.io/filtermodule のようになるはずです。
  • filtermodule とは異なる名前を自分のモジュールに使用した場合、その名前はソリューション全体で一貫しているか。
  • 対象のマシンは、ビルドしているのと同じ種類のコンテナーを実行しているか。 このチュートリアルは Linux IoT Edge デバイスを対象としているため、Visual Studio Code のサイド バーには amd64 または arm32v7 と表示され、Docker Desktop は Linux コンテナーを実行している必要があります。

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

ビルドしたコンテナー イメージがコンテナー レジストリに保存されているのを確認したので、次にそれらをデバイスにデプロイします。 お使いの IoT Edge デバイスが稼働していることを確認します。

IoT Edge Azure CLI set-modules コマンドを使用して、モジュールを Azure IoT Hub にデプロイします。 たとえば、"deployment.template.json" ファイルで定義されているモジュールを、IoT Edge デバイス "my-device" の IoT Hub "my-iot-hub" にデプロイするには、次のコマンドを使用します。 hub-namedevice-idlogin という IoT Hub 接続文字列の値をご使用の値に置き換えます。

az iot edge set-modules --hub-name my-iot-hub --device-id my-device --content ./deployment.template.json --login "HostName=my-iot-hub.azure-devices.net;SharedAccessKeyName=iothubowner;SharedAccessKey=<SharedAccessKey>"

ヒント

IoT Hub 接続文字列は共有アクセス キーを含め、Azure portal にあります。 [IoT Hub]>[セキュリティの設定]>[共有アクセス ポリシー]>[iothubowner] に移動します。

  1. Visual Studio Code エクスプローラーの [Azure IoT Hub] セクションで、 [デバイス] を展開して IoT デバイスの一覧を表示します。

  2. デプロイ先の IoT Edge デバイスを右クリックし、次に [Create Deployment for Single Device](単一デバイスのデプロイの作成) を選択します。

  3. ファイル エクスプローラーで、config フォルダーに移動して、deployment.amd64.json ファイルを選択します。

    deployment.template.json ファイルは使用しないでください。これには、コンテナー レジストリ資格情報もモジュール イメージの値も含まれていません。 Linux ARM32 デバイスをターゲットとする場合、配置マニフェストの名前は deployment.arm32v7.json です。

  4. お使いのデバイスの [モジュール] を展開し、デプロイされて実行中のモジュールの一覧を表示します。 [更新] ボタンを選択します。 新しい "tempSensor" と "filtermodule" モジュールがデバイスで実行されていることがわかります。

    モジュールが開始されるまでに数分かかる場合があります。 IoT Edge ランタイムは、新しい配置マニフェストを受け取り、コンテナー ランタイムからモジュール イメージを取得して、それぞれの新しいモジュールを開始する必要があります。

デバイスからのメッセージを表示する

サンプルのモジュール コードは、入力キュー経由でメッセージを受け取り、出力キュー経由でそれらを渡します。 配置マニフェストは、メッセージを "tempSensor" から "filtermodule" に渡し、次に "filtermodule" から IoT Hub にメッセージを転送したルートを宣言しました。 Azure IoT Edge と Azure IoT Hub の拡張機能を使うと、個々のデバイスから IoT Hub に到着したメッセージを表示できます。

  1. Visual Studio Code のエクスプローラーで、監視する IoT Edge デバイスを右クリックして、 [Start Monitoring Built-in Event Endpoint](組み込みイベント エンドポイントの監視を開始する) を選択します。

  2. Visual Studio Code の出力ウィンドウを監視して、IoT ハブに到着するメッセージを確認してください。

    Screenshot showing where to view incoming device to cloud messages.

デバイスでの変更を表示する

デバイス自体で何が起こっているかを確認する場合は、このセクションのコマンドを使用して、ご使用のデバイスで実行されている IoT Edge ランタイムとモジュールを検査します。

このセクションのコマンドは、開発マシンではなく、IoT Edge デバイスを対象としています。 IoT Edge デバイスに仮想マシンを使用している場合は、すぐに接続してください。 Azure で、仮想マシンの概要ページに移動し、 [接続] を選択して Secure Shell 接続にアクセスします。

  • お使いのデバイスにデプロイされているすべてのモジュールを表示し、それらの状態をチェックします。

    iotedge list
    

    4 つのモジュール (2 つの IoT Edge ランタイム モジュール、"tempSensor"、および "filtermodule") が表示されるはずです。 4 つすべてが実行中として一覧に表示されるはずです。

  • 次のように、特定のモジュールのログを検査します。

    iotedge logs <module name>
    

    IoT Edge モジュールでは大文字と小文字の区別があります。

    "tempSensor" と "filtermodule" のログには、処理しているメッセージが表示されるはずです。 edgeAgent モジュールには、他のモジュールを開始する責任があります。そのため、そのログには、配置マニフェストの実装に関する情報が含まれます。 モジュールが一覧に含まれていないか、実行されていない場合は、おそらく edgeAgent ログにエラーが記録されています。 edgeHub モジュールは、モジュールと IoT Hub 間の通信を担当します。 モジュールは稼働しているものの、メッセージが IoT ハブに到着していない場合は、おそらく edgeHub のログにエラーが記録されています。

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

次の推奨記事に進む場合は、作成したリソースおよび構成を維持して、再利用することができます。 また、同じ IoT Edge デバイスをテスト デバイスとして使用し続けることもできます。

そうでない場合は、課金されないようにするために、ローカル構成と、この記事で使用した Azure リソースを削除できます。

Azure リソースを削除する

Azure のリソースとリソース グループは、削除すると元に戻すことができません。 間違ったリソース グループやリソースをうっかり削除しないようにしてください。 保持したいリソースが含まれている既存のリソース グループ内に IoT ハブを作成した場合は、リソース グループを削除するのではなく、IoT ハブ リソースだけを削除してください。

リソースを削除するには、次の手順に従います。

  1. Azure portal にサインインし、 [リソース グループ] を選択します。

  2. IoT Edge のテスト リソースを含んだリソース グループの名前を選択します。

  3. リソース グループに含まれているリソースの一覧を確認します。 それらすべてを削除する場合は、 [リソース グループの削除] を選択します。 一部だけを削除する場合は、削除する各リソースをクリックして個別に削除してください。

次のステップ

このチュートリアルでは、Visual Studio Code を開発用コンピューターに設定して、最初の IoT Edge モジュールをデプロイしました。このモジュールには、IoT Edge デバイスによって生成された生データをフィルター処理するコードが含まれます。

次のチュートリアルに進むと、Azure のクラウド サービスをデプロイしてエッジでデータの処理と分析を行ううえで、Azure IoT Edge がどのように役立つかを確認できます。