共用方式為


教學課程:使用 SQL Server 資料庫將數據儲存在邊緣

適用於:IoT Edge 1.5 複選標記 IoT Edge 1.5 IoT Edge 1.4 複選標記 IoT Edge 1.4

重要

支援 IoT Edge 1.5 LTS 和 IoT Edge 1.4 LTS 版本。 IoT Edge 1.4 LTS 於 2024 年 11 月 12 日結束生命週期。 如果您是舊版,請參閱更新 IoT Edge

部署 SQL Server 模組,以將資料儲存在執行 Azure IoT Edge 與 Linux 容器的裝置上。

使用 Azure IoT Edge 和 SQL Server 來儲存和查詢邊緣的數據。 如果裝置離線,Azure IoT Edge 有基本的記憶體功能可快取訊息,然後在重新建立連線時轉送訊息。 不過,您可能想要更進階的記憶體功能,例如能夠在本機查詢數據。 IoT Edge 裝置可以使用本機資料庫來執行更複雜的運算,而不需要維護與 IoT 中樞 的連線。

本文提供將 SQL Server 資料庫部署到 IoT Edge 裝置的指示。 在 IoT Edge 裝置上執行的 Azure Functions 會建構傳入的數據,然後將它傳送至資料庫。 本文中的步驟也可以套用至在容器中運作的其他資料庫,例如 MySQL 或 PostgreSQL。

在本教學課程中,您會了解如何:

  • 使用 Visual Studio Code 建立 Azure 函式
  • 將 SQL 資料庫部署至 IoT Edge 裝置
  • 使用 Visual Studio Code 建置模組,並將其部署至 IoT Edge 裝置
  • 檢視產生的資料

如果您沒有 Azure 訂閱,請在開始之前,先建立 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 StudioCode命令選擇區。

  3. 在命令選擇區中,輸入並執行命令 Azure IoT Edge:新的 IoT Edge 解決方案。 在命令選擇區中,提供下列資訊來建立您的解決方案:

    欄位
    選取資料夾 選擇 Visual Studio Code 開發電腦上的位置,以建立方案檔。
    提供解決方案名稱 輸入解決方案的描述性名稱,例如 SqlSolution,或接受預設值。
    選取模組範本 選擇 [Azure Functions - C#]。
    提供模組名稱 將您的模組 命名為 sqlFunction
    提供模組的 Docker 映像存放庫 映像存放庫包含容器登錄的名稱和容器映像的名稱。 您的容器映像會從最後一個步驟預先填入。 將localhost:5000取代為您的 Azure 容器登錄中的登入伺服器值。 您可以從容器登錄 Azure 入口網站 的 [概觀] 頁面擷取登入伺服器。

    最後一個字串看起來像 <登錄名稱>.azurecr.io/sqlfunction。

    Visual Studio Code 視窗會載入 IoT Edge 解決方案工作區。

新增登錄認證

環境檔案會儲存容器登錄的認證,並與IoT Edge運行時間共用認證。 運行時間需要這些認證,才能將私人映像提取到IoT Edge裝置。

IoT Edge 擴充功能會嘗試從 Azure 提取容器登錄認證,並在環境檔案中填入這些認證。 檢查是否已包含您的認證。 如果沒有,請立即新增它們:

  1. 在 Visual Studio Code 總管中,開啟 .env 檔案。
  2. 使用您從 Azure 容器登錄複製的使用者名稱和密碼值來更新欄位。
  3. 儲存此檔案。

注意

本教學課程使用適用於 Azure Container Registry 的管理員登入認證,這對開發和測試案例而言很方便。 當您準備好進行生產案例時,建議您使用最低許可權驗證選項,例如服務主體。 如需詳細資訊,請參閱 管理容器登錄的存取權。

選取您的目標架構

您必須選取每個解決方案的目標架構,因為容器會針對每個架構類型建置和執行方式不同。 預設值為Linux AMD64。

  1. 開啟命令選擇區並搜尋 Azure IoT Edge:設定 Edge 解決方案的預設目標平臺,或選取視窗底部側邊列中的快捷方式圖示。

  2. 在命令選擇區中,從選項清單中選取目標架構。 在本教學課程中,我們會使用Ubuntu虛擬機作為IoT Edge裝置,因此會保留預設 amd64

使用自定義程式代碼更新模組

  1. 在 Visual Studio Code 總管中,開啟 >sqlFunction sqlFunction.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 threashold.
                        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=Strong!Passw0rd;TrustServerCertificate=False;Connection Timeout=30;
    
  7. 儲存 sqlFunction.cs 檔案。

新增 SQL Server 容器

部署 指令清單 會宣告 IoT Edge 運行時間將在 IoT Edge 裝置上安裝的模組。 您已提供程式碼來在上一節中建立自定義函式模組,但已在 Azure Marketplace 中建置 SQL Server 模組並可供使用。 您只需要告訴IoT Edge執行時間包含它,然後在您的裝置上設定它。

  1. 在 Visual Studio Code 中,選取 [檢視>命令選擇區],以開啟命令選擇區。

  2. 在命令選擇區中,輸入並執行 Azure IoT Edge:新增 IoT Edge 模組命令。 在命令選擇區中,提供下列資訊以新增模組:

    欄位
    選取部署範本檔案 命令選擇區會 反白顯示您目前方案資料夾中deployment.template.json 檔案。 選取該檔案。
    選取模組範本 從 Azure Marketplace 選取 [模組]。
  3. 在 Azure IoT Edge 模組市集中,搜尋並選取 [SQL Server 模組]。

  4. 將所有小寫的模組名稱變更為 sql。 此名稱符合sqlFunction.cs檔案中 連接字串 中宣告的容器名稱。

  5. 選取 [ 入] 將模組新增至您的解決方案。

  6. 在您的方案資料夾中,開啟 deployment.template.json 檔案。

  7. 尋找modules區段。 您應該會看到三個模組。 SimulatedTemperatureSensor 模組預設包含在新的解決方案中,並提供要與其他模組搭配使用的測試數據。 sqlFunction 模組是您最初以新程式代碼建立和更新的模組。 最後,已從 Azure Marketplace 匯入模組 sql

    提示

    SQL Server 模組隨附部署指令清單環境變數中設定的默認密碼。 每當您在生產環境中建立 SQL Server 容器時,都應該 變更預設的系統管理員密碼

  8. 關閉deployment.template.json檔案。

建置IoT Edge解決方案

在上一節中,您已使用一個模組建立解決方案,然後將另一個模組新增至部署指令清單範本。 SQL Server 模組是由 Microsoft 公開裝載,但您需要在 Functions 模組中容器化程式代碼。 在本節中,您會建置解決方案、建立 sqlFunction 模組的容器映像,並將映像推送至容器登錄。

  1. 在 Visual Studio Code 中,選取 [檢視]>[終端],以開啟整合式終端。

  2. 在 Visual Studio Code 中登入容器登錄,以便您將映像推送至登錄。 使用您新增至 .env 檔案的相同 Azure Container Registry (ACR) 認證。 在整合式終端機中輸入下列命令:

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

    您可能會看到建議使用 --password-stdin 參數的安全性警告。 雖然本文的使用超出本文的範圍,但建議您遵循此最佳做法。 如需詳細資訊,請參閱 docker login 命令參考。

  3. 在 Visual Studio Code 總管中,以滑鼠右鍵按兩下deployment.template.json檔案,然後選取 [建置和推送 IoT Edge 解決方案]。

    建置和推送命令會啟動三個作業。 首先,它會在名為 config 的解決方案中建立新的資料夾,以保存完整的部署指令清單,此指令清單內建在部署範本和其他解決方案檔案中的資訊中。 其次,它會執行 docker build ,根據目標架構的適當 dockerfile 來建置容器映像。 然後,它會執行 docker push ,將映像存放庫推送至容器登錄。

    此程式第一次可能需要幾分鐘的時間,但下次執行命令時會更快。

    您可以確認 sqlFunction 模組已成功推送至容器登錄。 在 Azure 入口網站中,瀏覽到您的容器登錄。 選取 存放庫 並搜尋 sqlFunction。 其他兩個模組 SimulatedTemperatureSensor 和 sql 將不會推送至您的容器登錄,因為它們的存放庫已經在 Microsoft 登錄中。

將解決方案部署至裝置

您可以透過 IoT 中樞 在裝置上設定模組,但您也可以透過 Visual Studio Code 存取 IoT 中樞 和裝置。 在本節中,您會設定對 IoT 中樞 的存取權,然後使用 Visual Studio Code 將解決方案部署至 IoT Edge 裝置。

  1. 在 Visual Studio Code 總管的 [Azure IoT 中樞] 區段底下,展開 [裝置] 以查看您的 IoT 裝置清單。

  2. 以滑鼠右鍵按下您想要以部署為目標的裝置,然後選取 [ 為單一裝置建立部署]。

  3. 選取 config 資料夾中的deployment.amd64.json檔案,然後按兩下 [選取 Edge 部署指令清單]。 請勿使用deployment.template.json檔案。

  4. 在您的裝置下,展開 [模組 ] 以查看已部署和執行的模組清單。 按兩下 [重新整理] 按鈕。 您應該會看到新的 sql 和 sqlFunction 模組與 SimulatedTemperatureSensor 模組以及$edgeAgent$edgeHub一起執行。

    您也可以檢查是否已在裝置上啟動並執行所有模組。 在您的 IoT Edge 裝置上,執行下列命令以查看模組的狀態。

    iotedge list
    

    模組可能需要幾分鐘的時間才能啟動。 IoT Edge 執行時間必須接收新的部署指令清單、從容器運行時間提取模組映像,然後啟動每個新模組。

建立 SQL 資料庫

當您將部署指令清單套用至裝置時,您會執行三個模組。 SimulatedTemperatureSensor 模組會產生仿真的環境數據。 sqlFunction 模組會擷取數據並將其格式化為資料庫。 本節會引導您設定 SQL 資料庫來儲存溫度數據。

在 IoT Edge 裝置上執行下列命令。 這些命令會連線到 在裝置上執行的 sql 模組,並建立資料庫和數據表來保存要傳送至它的溫度數據。

  1. 在 IoT Edge 裝置上的命令行工具中,連線到您的資料庫。

    sudo docker exec -it sql bash
    
  2. 開啟 SQL 命令工具。

    /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P 'Strong!Passw0rd'
    
  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
    

您可以自定義 SQL Server Docker 檔案,以自動設定要部署在多個 IoT Edge 裝置上的 SQL Server。 如需詳細資訊,請參閱 Microsoft SQL Server 容器示範專案

檢視本機數據

建立數據表之後,sqlFunction 模組就會開始將數據儲存在 IoT Edge 裝置上的本機 SQL Server 2017 資料庫中。

從 SQL 命令工具內,執行下列命令來檢視格式化的數據表資料:

SELECT * FROM MeasurementsDB.dbo.TemperatureMeasurements
GO

檢視本機資料庫的內容

清除資源

如果您打算繼續閱讀下一篇建議的文章,您可以保留您所建立的資源和組態並重複使用它們。 您也可以繼續使用與測試裝置相同的 IoT Edge 裝置。

否則,您可以刪除本文中建立的本機設定和 Azure 資源,以避免產生費用。

刪除 Azure 資源

刪除 Azure 資源和資源群組是無法回復的動作。 請確定您不會不小心刪除錯誤的資源群組或資源。 如果您在現有資源群組內建立IoT中樞,且該資源群組具有您想要保留的資源,請只刪除IoT中樞資源本身,而不是資源群組。

若要刪除資源:

  1. 登入 Azure 入口網站,然後選取 [資源群組]。

  2. 選取包含IoT Edge測試資源的資源群組名稱。

  3. 檢閱資源群組中包含的資源清單。 如果您想要刪除所有資源群組,您可以選取 [ 刪除資源群組]。 如果您想要只刪除其中一些資源,您可以按下每個資源來個別刪除它們。

在本教學課程中,您已建立 Azure Functions 模組,其中包含程式代碼來篩選 IoT Edge 裝置所產生的原始數據。 當您準備好建置自己的模組時,您可以深入瞭解如何使用 Visual Studio Code 開發 Azure IoT Edge 模組。

下一步

如果您想要嘗試邊緣的另一個記憶體方法,請閱讀如何在IoT Edge上使用 Azure Blob 儲存體。