자습서: Visual Studio Code를 사용하여 IoT Edge 모듈 개발

적용 대상:IoT Edge 1.5 확인 표시 IoT Edge 1.5 IoT Edge 1.4 확인 표시 IoT Edge 1.4

Important

IoT Edge 1.5 LTS 및 IoT Edge 1.4 LTS는 지원되는 릴리스입니다. IoT Edge 1.4 LTS는 2024년 11월 12일에 수명이 종료됩니다. 이전 릴리스에 있는 경우 IoT Edge 업데이트를 참조하세요.

이 자습서에서는 고유한 코드를 개발하고 IoT Edge 디바이스에 배포하는 과정을 안내합니다. 비즈니스 논리를 직접 Azure IoT Edge 디바이스에 구현하는 코드를 배포하려면 IoT Edge 모듈을 사용할 수 있습니다. Linux 디바이스에 코드 배포 빠른 시작에서는 IoT Edge 디바이스를 만들고 Azure Marketplace에서 모듈을 배포했습니다.

이 문서에는 두 가지 IoT Edge 개발 도구에 대한 단계가 포함되어 있습니다.

  • Azure IoT Edge Dev Tool 명령줄(CLI). 이 도구는 개발에 기본 설정됩니다.
  • Visual Studio Code용 Azure IoT Edge 도구 확장. 확장이 유지 관리 모드에 있습니다.

도구 버전을 선택하려면 이 문서의 시작 부분에 있는 도구 선택기 단추를 사용합니다.

이 자습서에서는 다음을 하는 방법을 알아볼 수 있습니다.

  • 개발 머신을 설정합니다.
  • IoT Edge 도구를 사용하여 새 프로젝트를 만듭니다.
  • 프로젝트를 Docker 컨테이너로 빌드하고 Azure 컨테이너 레지스트리에 저장합니다.
  • IoT Edge 디바이스에 코드를 배포합니다.

이 자습서에서 만드는 IoT Edge 모듈은 디바이스가 만드는 온도 데이터를 필터링합니다. 온도가 지정된 임계값을 초과하는 경우에만 메시지 업스트림을 전송합니다. Edge에서 이 유형의 분석은 클라우드로 전송되고 저장되는 데이터 양을 줄이는 데 유용합니다.

필수 조건

개발 머신:

  • 사용자 고유의 컴퓨터 또는 가상 머신을 사용합니다.
  • 개발 머신은 컨테이너 엔진을 실행할 수 있도록 중첩된 가상화를 지원해야 합니다.
  • 컨테이너 엔진을 실행할 수 있는 대부분의 운영 체제에서 Linux 디바이스용 IoT Edge 모듈을 개발할 수 있습니다. 이 자습서에서는 Windows 머신을 사용하지만 macOS 또는 Linux에서 알려진 차이점을 설명합니다.
  • Visual Studio Code를 설치합니다.
  • Azure CLI를 설치합니다.

Azure IoT Edge 디바이스:

클라우드 리소스:

  • Azure의 무료 또는 표준 계층 IoT Hub입니다.

Azure를 구독하고 있지 않다면 시작하기 전에 Azure 체험 계정을 만듭니다.

Visual Studio Code 또는 Visual Studio 2022에서 대화형 디버깅을 수행하는 방법에 대한 지침은 다음과 같습니다.

이 자습서에서는 Visual Studio Code에 대한 개발 단계를 설명합니다.

주요 개념

이 자습서는 IoT Edge 모듈 개발 과정을 안내합니다. IoT Edge 모듈은 실행 가능한 코드가 포함된 컨테이너입니다. 하나 이상의 모듈을 IoT Edge 디바이스에 배포할 수 있습니다. 모듈은 센서에서 데이터 수집, 데이터 정리 및 분석 또는 IoT 허브로 메시지 보내기 등의 특정 작업을 수행합니다. 자세한 내용은 Azure IoT Edge 모듈 이해를 참조하세요.

IoT Edge 모듈을 개발할 때에는 개발 머신과 모듈이 배포하는 대상 IoT Edge 디바이스 간의 차이를 이해하는 것이 중요합니다. 모듈 코드를 포함하기 위해 빌드하는 컨테이너는 대상 디바이스의 OS(운영 체제)와 일치해야 합니다. 예를 들어, 가장 일반적인 시나리오는 Windows 머신에서 IoT Edge를 실행하는 Linux 디바이스 대상의 모듈을 개발하는 경우입니다. 이 경우 컨테이너 운영 체제는 Linux일 것입니다. 이 자습서를 진행할 때는 개발 머신 OS컨테이너 OS 간의 차이점에 유의해야 합니다.

Windows에서 Linux용 IoT Edge를 사용하는 경우 시나리오의 대상 디바이스는 Windows 호스트가 아닌 Linux 가상 머신입니다.

이 자습서는 Linux 컨테이너에서 IoT Edge를 실행하는 디바이스를 대상으로 합니다. 개발 머신이 Linux 컨테이너를 실행하는 한 선호하는 운영 체제를 사용할 수 있습니다. Visual Studio Code를 사용하여 Linux 컨테이너로 개발하는 것이 좋으므로 이 자습서에서는 Visual Studio Code를 사용합니다. 두 도구 간에 지원 차이가 있긴 하지만, Visual Studio를 사용할 수도 있습니다.

다음 표에는 Visual Studio Code 및 Visual Studio의 Linux 컨테이너에 대해 지원되는 개발 시나리오가 나와 있습니다.

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
언어 C
C#
Java
Node.js
Python
C
C#
추가 정보 Azure IoT Edge for Visual Studio Code Azure IoT Edge Tools for Visual Studio 2019
Azure IoT Edge Tools for Visual Studio 2022

컨테이너 엔진 설치

IoT Edge 모듈은 컨테이너로 패키지되므로, 컨테이너를 빌드하고 관리하는 데 사용할 Docker 호환 컨테이너 관리 시스템이 개발 머신에 있어야 합니다. 해당 기능 지원과 인기로 인해 Docker Desktop 개발을 권장합니다. Windows의 Docker Desktop을 사용하면 Linux 컨테이너와 Windows 컨테이너 간에 전환하면서 다양한 유형의 IoT Edge 디바이스에 사용할 모듈을 개발할 수 있습니다.

개발 머신에 설치하려면 다음 Docker 설명서를 참조하세요.

  • Windows용 Docker Desktop 설치

    • Windows용 Docker Desktop을 설치할 때 Linux 컨테이너를 사용할지 아니면 Windows 컨테이너를 사용할지 묻는 메시지가 표시됩니다. 언제든지 이 결정을 바꿀 수 있습니다. 이 자습서의 모듈은 Linux 디바이스를 대상으로 하기 때문에 Linux 컨테이너를 사용합니다. 자세한 내용은 Windows 및 Linux 컨테이너 간 전환을 참조하세요.
  • Mac용 Docker Desktop 설치

  • 여러 Linux 플랫폼의 설치 정보에 대해서는 Docker CE 정보를 참조하세요.

    • WSL(Linux용 Windows 하위 시스템)의 경우 Windows용 Docker Desktop을 설치합니다.

도구 설정

IoT Edge 솔루션을 만들려면 Python 기반 Azure IoT Edge 개발 도구를 설치합니다. 두 옵션이 있습니다.

Important

Visual Studio Code용 Azure IoT Edge 도구 확장은 유지 관리 모드에 있습니다. 기본 설정되는 개발 도구는 명령줄(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/디바이스 메뉴를 확장합니다. 명령 팔레트를 통해 선택한 IoT Hub와 연결된 디바이스 및 IoT Edge 디바이스가 표시됩니다.

언어별 도구 설치

개발에 사용 중인 언어와 관련된 도구를 설치합니다.

컨테이너 레지스트리 만들기

이 자습서에서는 Azure IoT EdgeAzure IoT Hub 확장을 사용하여 모듈을 빌드하고 파일에서 컨테이너 이미지를 만듭니다. 그런 후 이미지를 저장하고 관리하는 레지스트리에 이 이미지를 푸시합니다. 마지막으로 IoT Edge 디바이스에서 실행되도록 레지스트리의 이미지를 배포합니다.

Important

Azure IoT Edge Visual Studio Code 확장은 유지 관리 모드에 있습니다.

임의 Docker 호환 레지스트리를 사용하여 컨테이너 이미지를 유지할 수 있습니다. 두 개의 인기 있는 Docker 레지스트리 서비스는 Azure Container RegistryDocker Hub입니다. 이 자습서에서는 Azure Container Registry를 사용합니다.

컨테이너 레지스트리가 아직 없는 경우 다음 단계를 따라 Azure에서 새로 만드세요.

  1. Azure Portal에서 리소스 만들기>컨테이너>Container Registry를 선택합니다.

  2. 필요한 다음 값을 입력하여 컨테이너 레지스트리를 만듭니다.

    필드
    구독 드롭다운 목록에서 구독을 선택합니다.
    Resource group IoT Edge 빠른 시작 및 자습서에서 만드는 모든 테스트 리소스에 동일한 리소스 그룹을 사용합니다. 예를 들어 IoTEdgeResources를 사용합니다.
    레지스트리 이름 고유한 이름을 입력합니다.
    위치 가까운 위치를 선택합니다.
    SKU 기본을 선택합니다.
  3. 검토 + 만들기를 선택한 다음, 만들기를 선택합니다.

  4. Azure Portal 홈페이지의 리소스 섹션에서 새 컨테이너 레지스트리를 선택하여 엽니다.

  5. 컨테이너 레지스트리의 왼쪽 창에서 설정 아래에 있는 메뉴에서 액세스 키를 선택합니다.

    액세스 키 메뉴 위치를 보여주는 스크린샷.

  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: 새로운 IoT Edge 솔루션 명령을 입력하고 실행합니다.
  3. 새 솔루션을 만들려는 폴더로 이동한 후 폴더 선택을 선택합니다.
  4. 솔루션에 대한 이름을 입력합니다.
  5. 원하는 개발 언어의 모듈 템플릿을 솔루션의 첫 번째 모듈로 선택합니다.
  6. 모듈의 이름을 입력합니다. 컨테이너 레지스트리 내에서 고유한 이름을 선택합니다.
  7. 모듈의 이미지 리포지토리 이름을 입력합니다. Visual Studio Code는 localhost:5000/<모듈 이름>으로 모듈 이름을 자동으로 채웁니다. 고유한 레지스트리 정보로 바꿉니다. 테스트를 위해 로컬 Docker 레지스트리를 사용하는 경우 localhost를 사용합니다. Azure Container Registry를 사용하는 경우 레지스트리 설정의 로그인 서버를 사용합니다. 로그인 서버는 <레지스트리 이름>.azurecr.io와 같이 표시됩니다. 최종 결과가 <레지스트리 이름>.azurecr.io/<모듈 이름>과 같이 표시되도록 문자열의 localhost:5000 부분을 바꾸기만 하면 됩니다.

Visual Studio Code는 입력한 정보를 사용하여 IoT Edge 솔루션을 만든 다음, 새 창에서 로드합니다.

솔루션을 만든 후에는 다음과 같은 기본 파일이 솔루션에 있습니다.

  • .vscode 폴더에는 구성 파일 launch.json이 포함되어 있습니다.

  • 각 모듈에 대한 하위 폴더가 들어 있는 modules 폴더. 각 모듈의 하위 폴더 내에는 파일 module.json 파일이 모듈을 빌드하고 배포하는 방법을 제어합니다.

  • .env 파일은 환경 변수를 나열합니다. 컨테이너 레지스트리의 환경 변수는 기본적으로 localhost:5000입니다.

  • deployment.template.jsondeployment.debug.template.json이라는 두 개의 모듈 배포 파일에는 디바이스에 배포할 모듈이 나열되어 있습니다. 기본적으로 목록에는 IoT Edge 시스템 모듈(edgeAgent 및 edgeHub)과 다음과 같은 샘플 모듈이 포함됩니다.

    참고 항목

    설치된 정확한 모듈은 선택한 언어에 따라 달라질 수 있습니다.

IoT Edge 런타임 버전 설정

안정적인 최신 IoT Edge 시스템 모듈 버전은 1.5입니다. 시스템 모듈을 버전 1.5로 설정합니다.

  1. Visual Studio Code에서 deployment.template.json 배포 매니페스트 파일을 엽니다. 배포 매니페스트는 대상 IoT Edge 디바이스에 구성할 모듈을 설명하는 JSON 문서입니다.

  2. 시스템 런타임 모듈 이미지 edgeAgentedgeHub의 런타임 버전을 변경합니다. 예를 들어 IoT Edge 런타임 버전 1.5를 사용하려면 배포 매니페스트 파일에서 다음 줄을 변경합니다.

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

IoT Edge 에이전트에 레지스트리 자격 증명 제공

환경 파일은 컨테이너 레지스트리의 자격 증명을 저장하고 IoT Edge 런타임과 공유합니다. 이러한 자격 증명은 런타임에서 컨테이너 이미지를 IoT Edge 디바이스로 가져오기 위해 필요합니다.

IoT Edge 확장은 Azure에서 컨테이너 레지스트리 자격 증명을 끌어온 후 환경 파일에 채우려고 합니다.

참고 항목

환경 파일은 모듈에 대한 이미지 리포지토리를 제공하는 경우에만 생성됩니다. localhost 기본값을 로컬로 테스트하고 디버그하도록 수락하는 경우 환경 변수를 선언할 필요가 없습니다.

자격 증명이 이미 있는지 확인합니다. 그렇지 않은 경우 다음과 같이 지금 추가합니다.

  1. Azure Container Registry가 레지스트리인 경우 Azure Container Registry 사용자 이름 및 암호를 설정합니다. 이러한 값은 Azure Portal에 있는 컨테이너 레지스트리의 설정>액세스 키 메뉴에서 가져옵니다.

  2. 모듈 솔루션의 .env 파일을 엽니다.

  3. Azure Container Registry에서 복사한 사용자 이름암호 값을 추가합니다. 예시:

    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: Edge 솔루션용 기본 대상 플랫폼 설정을 검색하거나 창의 맨 아래에 있는 사이드바에서 바로 가기 아이콘을 선택합니다.

  2. 명령 팔레트의 옵션 목록에서 대상 아키텍처를 선택합니다.

대상 아키텍처는 이후 단계에서 컨테이너 이미지를 만들 때 설정됩니다.

사용자 지정 코드를 사용하여 모듈 업데이트

각 템플릿에는 SimulatedTemperatureSensor 모듈에서 시뮬레이션된 센서 데이터를 가져와서 IoT 허브에 라우팅하는 샘플 코드가 포함되어 있습니다. 샘플 모듈은 메시지 수신한 후 전달합니다. 파이프라인 기능은 IoT Edge의 중요한 개념인 모듈이 서로 통신하는 방식을 보여 줍니다.

각 모듈의 코드에는 여러 개의 입력출력 큐가 선언될 수 있습니다. 디바이스에서 실행되는 IoT Edge 허브는 모듈 중 하나의 출력에 있는 메시지를 하나 이상의 모듈 입력으로 라우팅합니다. 입력 및 출력을 선언하는 특정 언어는 코드마다 다르지만 개념은 모든 모듈에서 동일합니다. 모듈 간 라우팅에 대한 자세한 내용은 경로 선언을 참조하세요.

프로젝트 템플릿과 함께 제공되는 샘플 C# 코드는 .NET용 IoT Hub SDK에서 ModuleClient 클래스를 사용합니다.

  1. Visual Studio Code 탐색기에서 modules>filtermodule>ModuleBackgroundService.cs를 엽니다.

  2. filtermodule 네임스페이스 앞에, 나중에 사용되는 유형의 using 문 3개를 추가합니다.

    using System.Collections.Generic;     // For KeyValuePair<>
    using Microsoft.Azure.Devices.Shared; // For TwinCollection
    using Newtonsoft.Json;                // For JsonConvert
    
  3. temperatureThreshold 변수를 ModuleBackgroundService 클래스에 추가합니다. 이 변수는 데이터가 IoT 허브로 전송되기 위해 측정된 온도가 초과해야 하는 값을 설정합니다.

    static int temperatureThreshold { get; set; } = 25;
    
  4. MessageBody, MachineAmbient 클래스를 추가합니다. 이러한 클래스는 수신 메시지 본문의 예상 스키마를 정의합니다.

    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 Hub에서 메시지를 수신할 때마다 호출됩니다. 모듈 쌍을 통해 설정된 온도 임계값 아래의 온도를 보고하는 메시지를 필터링합니다. 또한 값이 Alert로 설정된 MessageType 속성을 메시지에 추가합니다.

    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 모듈 쌍에서 경로 섹션을 찾습니다. sensorTofiltermodule 경로를 업데이트하여 input1inputFromSensor로 바꿉니다.

    "sensorTofiltermodule": "FROM /messages/modules/tempSensor/outputs/temperatureOutput INTO BrokeredEndpoint(\"/modules/filtermodule/inputs/inputFromSensor\")"
    
  11. filtermodule 모듈 쌍을 배포 매니페스트에 추가합니다. $edgeHub 모듈 쌍 뒤에 있는 modulesContent 섹션의 아래쪽에 다음 JSON 내용을 삽입합니다.

       "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 통합 터미널을 엽니다.

Linux 및 amd64 아키텍처용 컨테이너 이미지를 빌드하려면 dotnet publish 명령을 사용합니다. 프로젝트의 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. ACR(Azure Container Registry) 자격 증명을 사용하여 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 파일을 마우스 오른쪽 단추로 클릭하고 IoT Edge 솔루션 빌드 및 푸시를 선택합니다.

빌드 및 푸시 명령은 세 가지 작업을 시작합니다. 먼저, 배포 템플릿 및 기타 솔루션 파일의 정보로 작성된 전체 배포 매니페스트를 포함하는 config라는 새 폴더를 솔루션에 만듭니다. 둘째, docker build를 실행하여 대상 아키텍처의 적절한 dockerfile을 기준으로 컨테이너 이미지를 빌드합니다. 그런 다음, docker push를 실행하여 컨테이너 레지스트리에 이미지 리포지토리를 푸시합니다.

이 프로세스는 처음에는 몇 분 정도 걸릴 수 있지만 다음번에 명령을 실행할 때는 더 빨라집니다.

선택 사항: 모듈 및 이미지 업데이트

모듈 코드를 변경하는 경우 모듈 이미지를 다시 빌드하고 컨테이너 레지스트리에 푸시해야 합니다. 이 섹션의 단계에서 빌드 및 컨테이너 이미지를 업데이트합니다. 모듈 코드를 변경하지 않은 경우 이 섹션을 건너뛸 수 있습니다.

새로 만든 config 폴더에서 deployment.amd64.json 파일을 엽니다. 파일 이름은 대상 아키텍처를 반영하므로 다른 아키텍처를 선택하면 파일 이름이 달라집니다.

이제 자리 표시자가 있는 두 매개 변수가 적절한 값으로 채워졌습니다. 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 파일을 다시 마우스 오른쪽 단추로 클릭하고 IoT Edge 솔루션 빌드 및 푸시를 다시 선택합니다.

deployment.amd64.json 파일을 다시 엽니다. 빌드 및 푸시 명령을 다시 실행하면 빌드 시스템이 새 파일을 만들지 않습니다. 그 대신 동일한 파일이 변경 내용을 반영하도록 업데이트됩니다. 이제 filtermodule 이미지는 컨테이너의 0.0.2 버전을 가리킵니다.

빌드 및 푸시 명령이 어떤 작업을 수행했는지를 추가로 확인하려면 Azure Portal로 이동한 후 컨테이너 레지스트리로 이동합니다.

컨테이너 레지스트리에서 리포지토리를 선택한 다음 필터 모듈을 선택합니다. 이미지의 두 버전 모두 레지스트리에 푸시하는지 확인합니다.

컨테이너 레지스트리에서 두 이미지 버전을 모두 볼 수 있는 위치를 보여주는 스크린샷.

문제 해결

모듈 이미지를 빌드 및 푸시할 때 오류가 발생하는 경우 개발 머신의 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-name, device-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>"

Azure Portal에서 공유 액세스 키를 포함한 IoT Hub 연결 문자열을 찾을 수 있습니다. IoT Hub >보안 설정>공유 액세스 정책>iothubowner로 이동합니다.

  1. Visual Studio Code 탐색기의 Azure IoT Hub 섹션에서 디바이스를 확장하여 IoT 디바이스 목록을 표시합니다.

  2. 배포하려는 IoT Edge 디바이스를 마우스 오른쪽 단추로 클릭한 다음, 단일 디바이스용 배포 만들기를 선택합니다.

  3. 파일 탐색기에서 config 폴더로 이동한 후 deployment.amd64.json 파일을 선택합니다.

    deployment.template.json 파일은 컨테이너 레지스트리 자격 증명 또는 모듈 이미지 값을 갖고 있지 않으므로 사용하지 마세요. Linux ARM32 디바이스를 대상으로 하는 경우 배포 매니페스트의 이름은 deployment.arm32v7.json입니다.

  4. 배포되어 실행 중인 모듈의 목록을 보려면 디바이스 아래에서 모듈을 확장합니다. 새로 고침 단추를 선택합니다. 디바이스에서 실행 중인 새로운 tempSensorfiltermodule 모듈이 표시되어야 합니다.

    모듈이 시작되는 데 몇 분 정도 걸릴 수 있습니다. IoT Edge 런타임은 새 배포 매니페스트를 받고, 컨테이너 런타임에서 모듈 이미지를 끌어온 후 각 새 모듈을 시작해야 합니다.

디바이스에서 메시지 보기

SampleModule 코드는 입력 큐의 메시지를 받고 출력 큐를 통해 메시지를 전달합니다. 배포 매니페스트는 tempSensor에서 filtermodule로 메시지를 전달한 다음 filtermodule에서 IoT Hub로 메시지를 전달하는 경로를 선언했습니다. Azure IoT Edge 및 Azure IoT Hub 확장을 사용하면 개별 디바이스에서 IoT Hub에 도착하는 메시지를 볼 수 있습니다.

  1. Visual Studio Code 탐색기에서 모니터링하려는 IoT Edge 디바이스를 마우스 오른쪽 단추로 클릭한 다음, 기본 제공 이벤트 엔드포인트 모니터링 시작을 선택합니다.

  2. Visual Studio Code의 출력 창에서 IoT Hub에 메시지가 도착하는 것을 확인합니다.

    들어오는 디바이스 클라우드 간 메시지를 볼 수 있는 위치를 보여주는 스크린샷.

디바이스에서 변경 내용 보기

디바이스 자체에서 발생하는 상황을 확인하려는 경우 이 섹션의 명령을 사용하여 디바이스에서 실행되는 IoT Edge 런타임 및 모듈을 검사합니다.

이 섹션의 명령은 개발 머신용이 아니라 IoT Edge 디바이스용입니다. IoT Edge 디바이스용으로 가상 머신을 사용하고 있는 경우 지금 연결합니다. Azure에서 가상 머신의 개요 페이지로 이동한 후 연결을 선택하여 보안 셸 연결에 액세스합니다.

  • 디바이스에 배포된 모든 모듈을 확인하고 해당 상태를 확인합니다.

    iotedge list
    

    2개의 IoT Edge 런타임 모듈, tempSensorfiltermodule이라는 4개의 모듈이 표시됩니다. 4개 모두 실행 중으로 표시되는 것을 볼 수 있습니다.

  • 특정 모듈에 대한 로그를 검사합니다.

    iotedge logs <module name>
    

    IoT Edge 모듈은 대/소문자를 구분하지 않습니다.

    tempSensorfiltermodule 로그에는 처리 중인 메시지가 표시되어야 합니다. edgeAgent 모듈은 다른 모듈을 시작하므로, 해당 로그는 배포 매니페스트 구현에 대한 정보를 포함합니다. 모듈이 목록에 없거나 실행되고 있지 않으면 edgeAgent 로그에 오류가 있는 것일 수 있습니다. edgeHub 모듈은 모듈과 IoT Hub 간의 통신을 담당합니다. 모듈이 작동하고 실행 중이지만 IoT 허브에 메시지가 도착하지 않으면 edgeHub 로그에 오류가 있는 것일 수 있습니다.

리소스 정리

권장되는 다음 문서를 계속 진행하려는 경우 만든 리소스와 구성을 그대로 유지하고 다시 사용할 수 있습니다. 테스트 디바이스와 동일한 IoT Edge 디바이스를 계속 사용해도 됩니다.

그렇지 않은 경우 요금이 발생하지 않도록 이 문서에서 사용한 로컬 구성 및 Azure 리소스를 삭제할 수 있습니다.

Azure 리소스 삭제

Azure 리소스와 리소스 그룹을 삭제하면 되돌릴 수 없습니다. 잘못된 리소스 그룹 또는 리소스를 자동으로 삭제하지 않도록 해야 합니다. 보관하려는 리소스가 있는 기존 리소스 그룹 내에 IoT 허브를 만든 경우 리소스 그룹이 아닌 IoT 허브 리소스만 삭제해야 합니다.

리소스를 삭제하려면:

  1. Azure Portal에 로그인한 다음, 리소스 그룹을 선택합니다.

  2. IoT Hub 테스트 리소스가 포함된 리소스 그룹 이름을 선택합니다.

  3. 리소스 그룹에 포함된 리소스의 목록을 검토합니다. 모든 항목을 삭제하려는 경우리소스 그룹 삭제를 선택할 수 있습니다. 일부만 삭제하려는 경우 각 리소스를 클릭하여 개별적으로 삭제할 수 있습니다.

다음 단계

이 자습서에서는 개발 머신에서 Visual Studio Code를 설정하고 IoT Edge 디바이스에서 생성된 원시 데이터를 필터링하는 코드가 포함된 첫 번째 IoT Edge 모듈을 배포했습니다.

다음 자습서를 계속 진행하면서 Azure Cloud Services를 배포하여 에지에서 데이터를 처리 및 분석하는 데 Azure IoT Edge를 어떻게 활용할 수 있는지 알아볼 수 있습니다.