다음을 통해 공유


자습서: SQL Server 데이터베이스를 사용하여 에지에 데이터 저장

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

중요합니다

IoT Edge 1.5 LTS 및 IoT Edge 1.4는 지원되는 릴리스입니다. 이전 릴리스에 있는 경우 업데이트 IoT Edge를 참조하세요.

Sql Server 모듈을 배포하여 Linux 컨테이너를 사용하여 Azure IoT Edge를 실행하는 디바이스에 데이터를 저장합니다.

Azure IoT Edge 및 SQL Server를 사용하여 에지에 데이터를 저장하고 쿼리합니다. Azure IoT Edge에는 디바이스가 오프라인 상태가 되면 메시지를 캐시한 다음 연결이 다시 설정될 때 전달하는 기본 스토리지 기능이 있습니다. 그러나 데이터를 로컬로 쿼리하는 것과 같은 고급 스토리지 기능을 원할 수 있습니다. IoT Edge 디바이스는 로컬 데이터베이스를 사용하여 IoT Hub에 대한 연결을 유지하지 않고도 더 복잡한 컴퓨팅을 수행할 수 있습니다.

이 문서에서는 IoT Edge 디바이스에 SQL Server 데이터베이스를 배포하기 위한 지침을 제공합니다. IoT Edge 디바이스에서 실행되는 Azure Functions는 들어오는 데이터를 구조화한 다음 데이터베이스로 보냅니다. 이 문서의 단계는 MySQL 또는 PostgreSQL과 같은 컨테이너에서 작동하는 다른 데이터베이스에도 적용할 수 있습니다.

이 자습서에서는 다음 방법을 알아봅니다.

  • Visual Studio Code를 사용하여 Azure 함수 만들기
  • IoT Edge 디바이스에 SQL 데이터베이스 배포
  • Visual Studio Code를 사용하여 모듈을 빌드하고 IoT Edge 디바이스에 배포
  • 생성된 데이터 보기

Azure 계정이 없는 경우 시작하기 전에 체험 계정을 만듭니다.

필수 조건

이 자습서를 시작하기 전에 이전 자습서를 통해 Linux 컨테이너 개발을 위한 개발 환경을 설정해야 합니다. Visual Studio Code를 사용하여 Azure IoT Edge 모듈 개발. 이 자습서를 완료하면 다음과 같은 필수 구성 요소가 있어야 합니다.

이 자습서에서는 Azure Functions 모듈을 사용하여 SQL Server로 데이터를 보냅니다. Azure Functions를 사용하여 IoT Edge 모듈을 개발하려면 개발 머신에 다음 추가 필수 구성 요소를 설치합니다.

함수 프로젝트 만들기

데이터베이스로 데이터를 보내려면 데이터를 올바르게 구조화한 다음 테이블에 저장할 수 있는 모듈이 필요합니다.

새 프로젝트 만들기

다음 단계에서는 Visual Studio Code 및 Azure IoT Edge 확장을 사용하여 IoT Edge 함수를 만드는 방법을 보여줍니다.

  1. Visual Studio Code를 엽니다.

  2. 명령> 보기 팔레트를 선택하여 Visual Studio Code명령 팔레트를 엽니다.

  3. 명령 팔레트에서 Azure IoT Edge: 새 IoT Edge 솔루션을 입력하고 실행합니다. 명령 팔레트에서 다음 정보를 제공하여 솔루션을 만듭니다.

    분야 가치
    폴더 선택 Visual Studio Code용 개발 머신의 위치를 선택하여 솔루션 파일을 만듭니다.
    솔루션 이름 제공 솔루션의 설명이 포함된 이름(예: SqlSolution)을 입력하거나 기본값을 적용합니다.
    모듈 템플릿 선택 Azure Functions - C#을 선택합니다.
    모듈 이름 제공 모듈 의 이름을 sqlFunction으로 지정합니다.
    모듈에 대한 Docker 이미지 리포지토리 제공 이미지 리포지토리에는 컨테이너 레지스트리의 이름과 컨테이너 이미지의 이름이 포함됩니다. 컨테이너 이미지는 마지막 단계에서 미리 채워집니다. localhost:5000을 Azure Container Registry의 로그인 서버 값으로 바꿉다. Azure Portal의 컨테이너 레지스트리 개요 페이지에서 로그인 서버를 검색할 수 있습니다.

    마지막 문자열은 registry name.azurecr.io/sqlfunction> 같습니다<.

    Visual Studio Code 창에서 IoT Edge 솔루션 작업 영역을 로드합니다.

레지스트리 자격 증명 추가

환경 파일은 컨테이너 레지스트리에 대한 자격 증명을 저장하고 IoT Edge 런타임과 공유합니다. 프라이빗 이미지를 IoT Edge 디바이스로 끌어오려면 런타임에 이러한 자격 증명이 필요합니다.

IoT Edge 확장은 Azure에서 컨테이너 레지스트리 자격 증명을 끌어와서 환경 파일에 채웁니다. 자격 증명이 이미 포함되어 있는지 확인합니다. 그렇지 않은 경우 지금 추가합니다.

  1. Visual Studio Code 탐색기에서 .env 파일을 엽니다.
  2. Azure Container Registry에서 복사한 사용자 이름암호 값으로 필드를 업데이트합니다.
  3. 이 파일을 저장합니다.

비고

이 자습서에서는 개발 및 테스트 시나리오에 편리한 Azure Container Registry에 대한 관리자 로그인 자격 증명을 사용합니다. 프로덕션 시나리오에 대한 준비가 되면 서비스 주체와 같은 최소 권한 인증 옵션을 사용하는 것이 좋습니다. 자세한 내용은 컨테이너 레지스트리에 대한 액세스 관리를 참조하세요.

대상 아키텍처 선택

컨테이너가 빌드되고 각 아키텍처 유형에 대해 다르게 실행되므로 각 솔루션에서 대상으로 지정하는 아키텍처를 선택해야 합니다. 기본값은 Linux AMD64입니다.

  1. 명령 팔레트를 열고 Azure IoT Edge를 검색합니다. Edge 솔루션에 대한 기본 대상 플랫폼 설정 또는 창 아래쪽의 사이드바에서 바로 가기 아이콘을 선택합니다.

  2. 명령 팔레트의 옵션 목록에서 대상 아키텍처를 선택합니다. 이 자습서에서는 Ubuntu 가상 머신을 IoT Edge 디바이스로 사용하므로 기본 amd64를 유지합니다.

사용자 지정 코드로 모듈 업데이트

  1. Visual Studio Code 탐색기에서 모듈>sqlFunctionsqlFunction.csproj>를 엽니다.

  2. 패키지 참조 그룹을 찾고 SqlClient를 포함할 새 참조를 추가합니다.

    <PackageReference Include="System.Data.SqlClient" Version="4.5.1"/>
    
  3. sqlFunction.csproj 파일을 저장합니다.

  4. sqlFunction.cs 파일을 엽니다.

  5. 파일의 전체 내용을 다음 코드로 바꿉니다.

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Text;
    using System.Threading.Tasks;
    using Microsoft.Azure.Devices.Client;
    using Microsoft.Azure.WebJobs;
    using Microsoft.Azure.WebJobs.Extensions.EdgeHub;
    using Microsoft.Azure.WebJobs.Host;
    using Microsoft.Extensions.Logging;
    using Newtonsoft.Json;
    using Sql = System.Data.SqlClient;
    
    namespace Functions.Samples
    {
        public static class sqlFunction
        {
            [FunctionName("sqlFunction")]
            public static async Task FilterMessageAndSendMessage(
                [EdgeHubTrigger("input1")] Message messageReceived,
                [EdgeHub(OutputName = "output1")] IAsyncCollector<Message> output,
                ILogger logger)
            {
                const int temperatureThreshold = 20;
                byte[] messageBytes = messageReceived.GetBytes();
                var messageString = System.Text.Encoding.UTF8.GetString(messageBytes);
    
                if (!string.IsNullOrEmpty(messageString))
                {
                    logger.LogInformation("Info: Received one non-empty message");
                    // Get the body of the message and deserialize it.
                    var messageBody = JsonConvert.DeserializeObject<MessageBody>(messageString);
    
                    //Store the data in SQL db
                    const string str = "<sql connection string>";
                    using (Sql.SqlConnection conn = new Sql.SqlConnection(str))
                    {
                        conn.Open();
                        var insertMachineTemperature = "INSERT INTO MeasurementsDB.dbo.TemperatureMeasurements VALUES (CONVERT(DATETIME2,'" + messageBody.timeCreated + "', 127), 'machine', " + messageBody.machine.temperature + ");";
                        var insertAmbientTemperature = "INSERT INTO MeasurementsDB.dbo.TemperatureMeasurements VALUES (CONVERT(DATETIME2,'" + messageBody.timeCreated + "', 127), 'ambient', " + messageBody.ambient.temperature + ");";
                        using (Sql.SqlCommand cmd = new Sql.SqlCommand(insertMachineTemperature + "\n" + insertAmbientTemperature, conn))
                        {
                            //Execute the command and log the # rows affected.
                            var rows = await cmd.ExecuteNonQueryAsync();
                            logger.LogInformation($"{rows} rows were updated");
                        }
                    }
    
                    if (messageBody != null && messageBody.machine.temperature > temperatureThreshold)
                    {
                        // Send the message to the output as the temperature value is greater than the threshold.
                        using (var filteredMessage = new Message(messageBytes))
                        {
                             // Copy the properties of the original message into the new Message object.
                             foreach (KeyValuePair<string, string> prop in messageReceived.Properties)
                             {filteredMessage.Properties.Add(prop.Key, prop.Value);}
                             // Add a new property to the message to indicate it is an alert.
                             filteredMessage.Properties.Add("MessageType", "Alert");
                             // Send the message.
                             await output.AddAsync(filteredMessage);
                             logger.LogInformation("Info: Received and transferred a message with temperature above the threshold");
                        }
                    }
                }
            }
        }
        //Define the expected schema for the body of incoming messages.
        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;}
        }
    }
    
  6. 줄 35에서 문자열 <sql 연결 문자열> 을 다음 문자열로 바꿉다. 데이터 원본 속성은 아직 존재하지 않는 SQL Server 컨테이너를 참조합니다. 다음 섹션에서 SQL 이름으로 만듭니다. 암호 키워드에 대한 강력한 암호를 선택합니다.

    Data Source=tcp:sql,1433;Initial Catalog=MeasurementsDB;User Id=SA;Password=<YOUR-STRONG-PASSWORD>;TrustServerCertificate=False;Connection Timeout=30;
    
  7. sqlFunction.cs 파일을 저장합니다.

SQL Server 컨테이너 추가

배포 매니페스트는 IoT Edge 런타임이 IoT Edge 디바이스에 설치할 모듈을 선언합니다. 이전 섹션에서 사용자 지정된 함수 모듈을 만드는 코드를 제공했지만 SQL Server 모듈은 이미 빌드되어 Microsoft Artifact Registry에서 사용할 수 있습니다. IoT Edge 런타임에 이를 포함하도록 지시한 다음 디바이스에서 구성하기만 하면 됩니다.

  1. Visual Studio Code에서 명령 팔레트 보기를> 선택하여명령 팔레트를 엽니다.

  2. 명령 팔레트에서 Azure IoT Edge: IoT Edge 모듈 추가 명령을 입력하고 실행합니다. 명령 팔레트에서 다음 정보를 제공하여 새 모듈을 추가합니다.

    분야 가치
    배포 템플릿 파일 선택 명령 팔레트는 현재 솔루션 폴더의 deployment.template.json 파일을 강조 표시합니다. 해당 파일을 선택합니다.
    모듈 템플릿 선택 기존 모듈을 선택합니다(전체 이미지 URL 입력).
    모듈 이름 제공 sql을 입력합니다. 이 이름은 sqlFunction.cs 파일의 연결 문자열에 선언된 컨테이너 이름과 일치합니다.
    모듈에 대한 Docker 이미지 제공 다음 URI를 입력하여 Microsoft 아티팩트 레지스트리에서 SQL Server 컨테이너 이미지를 가져옵니다. Ubuntu 기반 이미지의 mcr.microsoft.com/mssql/server:latest경우 . RHEL(Red Hat Enterprise Linux) 기반 이미지의 mcr.microsoft.com/mssql/rhel/server:latest경우 .

    Azure SQL Edge 컨테이너 이미지는 IoT Edge 디바이스에서 실행할 수 있는 컨테이너화된 경량 버전의 SQL Server입니다. 에지 시나리오에 최적화되어 있으며 ARM 및 AMD64 디바이스에서 실행할 수 있습니다.

  3. 솔루션 폴더에서 deployment.template.json 파일을 엽니다.

  4. 모듈 섹션을 찾습니다. 세 개의 모듈이 표시됩니다. SimulatedTemperatureSensor 모듈은 기본적으로 새 솔루션에 포함되며 다른 모듈과 함께 사용할 테스트 데이터를 제공합니다. sqlFunction 모듈은 새 코드로 처음 만들고 업데이트한 모듈입니다. 마지막으로 Microsoft Artifact Registry에서 모듈 sql 을 가져왔습니다.

    팁 (조언)

    SQL Server 모듈에는 배포 매니페스트의 환경 변수에 설정된 기본 암호가 함께 제공됩니다. 프로덕션 환경에서 SQL Server 컨테이너를 만들 때마다 기본 시스템 관리자 암호를 변경해야 합니다.

  5. deployment.template.json 파일을 닫습니다.

IoT Edge 솔루션 빌드

이전 섹션에서는 한 모듈을 사용하여 솔루션을 만든 다음 배포 매니페스트 템플릿에 다른 모듈을 추가했습니다. SQL Server 모듈은 Microsoft에서 공개적으로 호스트되지만 Functions 모듈에서 코드를 컨테이너화해야 합니다. 이 섹션에서는 솔루션을 빌드하고, sqlFunction 모듈에 대한 컨테이너 이미지를 만들고, 이미지를 컨테이너 레지스트리에 푸시합니다.

  1. Visual Studio Code에서 터미널 보기를> 선택하여 통합터미널을 엽니다.

  2. 이미지를 레지스트리에 푸시할 수 있도록 Visual Studio Code에서 컨테이너 레지스트리에 로그인합니다. .env 파일에 추가한 것과 동일한 ACR(Azure Container Registry) 자격 증명을 사용합니다. 통합 터미널에서 다음 명령을 입력합니다.

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

    --password-stdin 매개 변수 사용을 권장하는 보안 경고가 표시될 수 있습니다. 사용은 이 문서의 범위를 벗어나지만 이 모범 사례를 따르는 것이 좋습니다. 자세한 내용은 docker 로그인 명령 참조를 참조하세요.

  3. Visual Studio Code 탐색기에서deployment.template.json파일을 마우스 오른쪽 단추 로 클릭하고 빌드 및 푸시 IoT Edge 솔루션을 선택합니다.

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

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

    sqlFunction 모듈이 컨테이너 레지스트리에 성공적으로 푸시되었는지 확인할 수 있습니다. Azure Portal에서 컨테이너 레지스트리로 이동합니다. 리포지토리를 선택하고 sqlFunction을 검색합니다. 다른 두 모듈인 SimulatedTemperatureSensor 및 sql은 해당 리포지토리가 이미 Microsoft 레지스트리에 있으므로 컨테이너 레지스트리로 푸시되지 않습니다.

디바이스에 솔루션 배포

IoT Hub를 통해 디바이스에서 모듈을 설정할 수 있지만 Visual Studio Code를 통해 IoT Hub 및 디바이스에 액세스할 수도 있습니다. 이 섹션에서는 IoT Hub에 대한 액세스를 설정한 다음 Visual Studio Code를 사용하여 IoT Edge 디바이스에 솔루션을 배포합니다.

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

  2. 배포를 대상으로 지정할 디바이스를 마우스 오른쪽 단추로 클릭하고 단일 디바이스에 대한 배포 만들기를 선택합니다.

  3. 구성 폴더에서 deployment.amd64.json 파일을 선택한 다음 에지 배포 매니페스트 선택을 클릭합니다. deployment.template.json 파일을 사용하지 마세요.

  4. 디바이스에서 모듈을 확장하여 배포되고 실행 중인 모듈 목록을 확인합니다. 새로 고침 단추를 클릭합니다. SimulatedTemperatureSensor 모듈 및 $edgeAgent$edgeHub 함께 실행되는 새 sqlsqlFunction 모듈이 표시됩니다.

    모든 모듈이 디바이스에서 실행되고 있는지 확인할 수도 있습니다. IoT Edge 디바이스에서 다음 명령을 실행하여 모듈의 상태를 확인합니다.

    iotedge list
    

    모듈을 시작하는 데 몇 분 정도 걸릴 수 있습니다. IoT Edge 런타임은 새 배포 매니페스트를 수신하고, 컨테이너 런타임에서 모듈 이미지를 풀다운한 다음, 각 새 모듈을 시작해야 합니다.

SQL 데이터베이스 만들기

디바이스에 배포 매니페스트를 적용하면 세 개의 모듈이 실행됩니다. SimulatedTemperatureSensor 모듈은 시뮬레이션된 환경 데이터를 생성합니다. sqlFunction 모듈은 데이터를 가져와서 데이터베이스에 대한 형식을 지정합니다. 이 섹션에서는 온도 데이터를 저장하도록 SQL 데이터베이스를 설정하는 방법을 안내합니다.

IoT Edge 디바이스에서 다음 명령을 실행합니다. 이러한 명령은 디바이스에서 실행되는 sql 모듈에 연결하고 전송되는 온도 데이터를 저장할 데이터베이스 및 테이블을 만듭니다. YOUR-STRONG-PASSWORD>를 연결 문자열에서 선택한 강력한 암호로 바꿉<다.

  1. IoT Edge 디바이스의 명령줄 도구에서 데이터베이스에 연결합니다.

    sudo docker exec -it sql bash
    
  2. SQL 명령 도구를 엽니다.

    /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P '<YOUR-STRONG-PASSWORD>'
    
  3. 데이터베이스를 만듭니다.

    CREATE DATABASE MeasurementsDB
    ON
    (NAME = MeasurementsDB, FILENAME = '/var/opt/mssql/measurementsdb.mdf')
    GO
    
  4. 테이블을 정의합니다.

    CREATE TABLE MeasurementsDB.dbo.TemperatureMeasurements (measurementTime DATETIME2, location NVARCHAR(50), temperature FLOAT)
    GO
    

여러 IoT Edge 디바이스에 배포되도록 SQL Server를 자동으로 설정하도록 SQL Server Docker 파일을 사용자 지정할 수 있습니다. 자세한 내용은 Microsoft SQL Server 컨테이너 데모 프로젝트를 참조하세요.

로컬 데이터 보기

테이블이 만들어지면 sqlFunction 모듈은 IoT Edge 디바이스의 로컬 SQL Server 2017 데이터베이스에 데이터를 저장하기 시작합니다.

SQL 명령 도구 내에서 다음 명령을 실행하여 서식이 지정된 테이블 데이터를 봅니다.

SELECT * FROM MeasurementsDB.dbo.TemperatureMeasurements
GO

로컬 데이터베이스의 콘텐츠 보기

자원을 정리하세요

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

그렇지 않으면 요금이 부과되지 않도록 이 문서에서 만든 로컬 구성 및 Azure 리소스를 삭제할 수 있습니다.

Azure 리소스 삭제

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

리소스를 삭제하려면 다음을 수행합니다.

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

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

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

이 자습서에서는 IoT Edge 디바이스에서 생성된 원시 데이터를 필터링하는 코드를 포함하는 Azure Functions 모듈을 만들었습니다. 고유한 모듈을 빌드할 준비가 되면 Visual Studio Code를 사용하여 Azure IoT Edge 모듈을 개발하는 방법에 대해 자세히 알아볼 수 있습니다.

다음 단계

에지에서 다른 스토리지 방법을 사용하려는 경우 IoT Edge에서 Azure Blob Storage를 사용하는 방법을 읽어보세요.