教學課程:使用 Linux 容器開發 JAVA IoT Edge 模組
適用于:IoT Edge 1.4
您可以使用 Azure IoT Edge 模組來部署程式碼,直接在 IoT Edge 裝置上實作您的商務邏輯。 本教學課程會逐步引導您建立並部署能篩選感應器資料的 IoT Edge 模組。 您將在快速入門文章的模擬裝置上使用您在模擬裝置上部署 Azure IoT Edge中所建立的模擬IoT Edge裝置。 在本教學課程中,您會了解如何:
- 使用 Visual Studio Code 來根據 Azure IoT Edge maven 範本套件和 Azure IoT Java 裝置 SDK,建立 IoT Edge Java 模組。
- 使用 Visual Studio Code 和 Docker 建立 Docker 映像,並將其發佈至您的登錄中。
- 將模組部署到您的 IoT Edge 裝置。
- 檢視產生的資料。
您於此教學課程中建立的 IoT Edge 模組,能夠篩選由您裝置所產生的溫度資料。 它只有在溫度超過指定的閾值時,才會將訊息往上游傳送。 這類於邊緣所進行的分析,對於減少針對雲端所傳輸及儲存的資料量相當有幫助。
如果您沒有 Azure 訂閱,請在開始之前,先建立 Azure 免費帳戶。
必要條件
本教學課程示範如何使用Visual Studio Code在JAVA中開發模組,以及如何將其部署至IoT Edge裝置。 IoT Edge不支援建置為 Windows 容器的 JAVA 模組。
使用下表來了解開發及部署 Java 模組的選項:
Java | Visual Studio Code | Visual Studio 2017/2019 |
---|---|---|
Linux AMD64 | ![]() |
|
Linux ARM32 | ![]() |
|
Linux ARM64 | ![]() |
在開始本教學課程之前,您應該已經完成先前的教學課程,以針對 Linux 容器開發設定您的開發環境:開發適用於 Linux 裝置的 IoT Edge 模組。 完成上述任一教學課程後,您應該會具備下列必要條件:
- Azure 中的免費或標準層 IoT 中樞。
- 使用 Linux 容器執行 Azure IoT Edge 的裝置。 您可以使用快速入門來設定 Linux 裝置 或 Windows 裝置。
- 容器登錄,像是 Azure Container Registry。
- Visual Studio Code使用Azure IoT Edge和Azure IoT 中樞擴充功能進行設定。
- 在您的開發電腦上下載並安裝 Docker 相容的容器管理系統 。 將它設定為執行 Linux 容器。
若要以 Java 開發 IoT Edge 模組,請在您的開發機器上安裝下列其他必要條件:
適用於 Visual Studio Code 的 Java 擴充套件 (英文)。
JAVA SE 開發工具組 11,並將 環境變數設定
JAVA_HOME
為指向您的 JDK 安裝。-
提示
Java 和 Maven 安裝程序會將環境變數新增至您的系統。 在完成安裝之後,重新開機任何開啟的Visual Studio Code終端機、PowerShell 或命令提示字元實例。 此步驟可確保這些公用程式往後可以辨識 Java 和 Maven 命令。
建立模組專案
下列步驟會建立一個 IoT Edge 模組專案,此專案會以 Azure IoT Edge maven 範本套件和 Azure IoT Java 裝置 SDK 為基礎。 您需使用 Visual Studio Code 和 Azure IoT Edge 延伸模組來建立此專案。
建立新專案
建立可讓您使用自己的程式碼自訂的 Java 解決方案範本。
在 Visual Studio Code 中,選取 [檢視] >[命令選擇區] ,以開啟 VS Code 命令選擇區。
在命令選擇區中,輸入並執行命令 Azure IoT Edge:新增 IoT Edge 解決方案。 依照命令選擇區中的提示建立解決方案。
欄位 值 選取資料夾 選擇開發機器上可供 VS Code 建立解決方案檔案的位置。 提供解決方案名稱 輸入解決方案的描述性名稱或接受預設值 EdgeSolution。 選取模組範本 選擇 [Java 模組] 。 提供模組名稱 將模組命名為 JavaModule。 提供模組的 Docker 映像存放庫 映像存放庫包含容器登錄名稱和容器映像名稱。 您的容器映像會從您在上一個步驟中提供的名稱預先填入。 將 localhost:5000 取代為 Azure Container Registry 的登入伺服器值。 您可以在 Azure 入口網站中,從容器登錄的概觀頁面擷取登入伺服器。
最終的映像存放庫看起來類似於:<登錄名稱>.azurecr.io/javamodule。提供 groupId 值 輸入群組識別碼值,或接受預設值 com.edgemodule。
如果您第一次建立 Java 模組,可能需要幾分鐘的時間下載 maven 套件。 當解決方案準備就緒時,VS Code 視窗會載入您的 IoT Edge 解決方案工作區。 解決方案工作區包含五個最上層元件:
- [modules] 資料夾包含您模組的 Java 程式碼,以及用來將模組建置成容器映像的 Docker 檔案。
- .env檔案會儲存您的容器登錄認證。
- Deployment.template.json 檔案包含 IoT Edge 執行階段用來在裝置上部署模組的資訊。
- deployment.debug.template.json 檔案包含模組的偵錯版本。
- 在本教學課程中,您不會編輯 .vscode 資料夾或 .gitignore 檔案。
如果您在建立方案時未指定容器登錄,但已接受預設 localhost:5000 值,則不會有 .env 檔案。
新增登錄認證
環境檔案會儲存容器登錄的認證,並與 IoT Edge 執行階段共用這些認證。 執行階段需要有這些認證才能將私人映像提取到 IoT Edge 裝置。
IoT Edge 擴充功能會嘗試從 Azure 提取您的容器登錄認證,並將這些認證填入到環境檔案中。 請查看您的認證是否已包含其中。 如果沒有,請立即新增:
- 在 VS Code 總管中,開啟 .env 檔案。
- 使用從 Azure Container Registry 複製過來的 [使用者名稱] 和 [密碼] 值來更新欄位。
- 儲存這個檔案。
注意
本教學課程會針對Azure Container Registry使用系統管理員登入認證,這適用于開發和測試案例。 當您準備好進行生產案例時,建議使用最低權限驗證選項,例如服務主體。 如需詳細資訊,請參閱管理您容器登錄的存取權。
選取您的目標架構
目前,Visual Studio Code 可以開發適用於 Linux AMD64 和 Linux ARM32v7 裝置的 Java 模組。 您必須為每個解決方案都選取要作為目標的架構,因為容器是針對每個架構類型,以不同方式建置和執行。 預設值為 Linux AMD64。
開啟命令選擇區並搜尋 Azure IoT Edge:Set Default Target Platform for Edge Solution,或選取視窗底部側邊欄的捷徑圖示。
在命令選擇區中,從選項清單中選取目標架構。 針對此教學課程,我們是使用 Ubuntu 虛擬機器作為 IoT Edge 裝置,因此會保留預設 amd64。
使用自訂程式碼來更新模組
在 VS Code 總管中,開啟 [modules] >[JavaModule] >[src] >[main] >[java] >[com] >[edgemodule] >[App.java] 。
在檔案頂端新增下列程式碼,以匯入新的參考類別。
import java.io.StringReader; import java.util.concurrent.atomic.AtomicLong; import java.util.HashMap; import java.util.Map; import javax.json.Json; import javax.json.JsonObject; import javax.json.JsonReader; import com.microsoft.azure.sdk.iot.device.DeviceTwin.Pair; import com.microsoft.azure.sdk.iot.device.DeviceTwin.Property; import com.microsoft.azure.sdk.iot.device.DeviceTwin.TwinPropertyCallBack;
將下列定義新增至 App 類別。 此變數會設定溫度閾值。 所測得的機器溫度在超出此值之後才會回報給「IoT 中樞」。
private static final String TEMP_THRESHOLD = "TemperatureThreshold"; private static AtomicLong tempThreshold = new AtomicLong(25);
將 MessageCallbackMqtt 的執行方法換成下列程式碼。 每當模組從 IoT Edge 中樞收到 MQTT 訊息時,就會呼叫此方法。 它會篩選所報告溫度低於 (透過模組對應項所設定) 之溫度閾值的訊息。
protected static class MessageCallbackMqtt implements MessageCallback { private int counter = 0; @Override public IotHubMessageResult execute(Message msg, Object context) { this.counter += 1; String msgString = new String(msg.getBytes(), Message.DEFAULT_IOTHUB_MESSAGE_CHARSET); System.out.println( String.format("Received message %d: %s", this.counter, msgString)); if (context instanceof ModuleClient) { try (JsonReader jsonReader = Json.createReader(new StringReader(msgString))) { final JsonObject msgObject = jsonReader.readObject(); double temperature = msgObject.getJsonObject("machine").getJsonNumber("temperature").doubleValue(); long threshold = App.tempThreshold.get(); if (temperature >= threshold) { ModuleClient client = (ModuleClient) context; System.out.println( String.format("Temperature above threshold %d. Sending message: %s", threshold, msgString)); client.sendEventAsync(msg, eventCallback, msg, App.OUTPUT_NAME); } } catch (Exception e) { e.printStackTrace(); } } return IotHubMessageResult.COMPLETE; } }
將下列兩個靜態內部類別新增至 App 類別。 這些類別會在模組對應項的預期屬性變更時更新 tempThreshold 變數。 所有模組都具有自己的模組對應項,這可讓您直接從雲端設定於模組內執行的程式碼。
protected static class DeviceTwinStatusCallBack implements IotHubEventCallback { @Override public void execute(IotHubStatusCode status, Object context) { System.out.println("IoT Hub responded to device twin operation with status " + status.name()); } } protected static class OnProperty implements TwinPropertyCallBack { @Override public void TwinPropertyCallBack(Property property, Object context) { if (!property.getIsReported()) { if (property.getKey().equals(App.TEMP_THRESHOLD)) { try { long threshold = Math.round((double) property.getValue()); App.tempThreshold.set(threshold); } catch (Exception e) { System.out.println("Faile to set TemperatureThread with exception"); e.printStackTrace(); } } } } }
在 main 方法的 client.open() 後面新增下列幾行,以訂閱模組對應項的更新。
client.startTwin(new DeviceTwinStatusCallBack(), null, new OnProperty(), null); Map<Property, Pair<TwinPropertyCallBack, Object>> onDesiredPropertyChange = new HashMap<Property, Pair<TwinPropertyCallBack, Object>>() { { put(new Property(App.TEMP_THRESHOLD, null), new Pair<TwinPropertyCallBack, Object>(new OnProperty(), null)); } }; client.subscribeToTwinDesiredProperties(onDesiredPropertyChange); client.getTwin();
儲存 App.java 檔案。
在 VS Code 總管中,於 IoT Edge 解決方案工作區中開啟 deployment.template.json 檔案。
將 JavaModule 模組對應項新增至部署資訊清單。 在 moduleContent 區段底部,於 $edgeHub 模組對應項後面插入下列 JSON 內容:
"JavaModule": { "properties.desired":{ "TemperatureThreshold":25 } }
儲存 deployment.template.json 檔案。
建置和推送模組
在上一節中,您已建立 IoT Edge 解決方案,並將程式碼新增至 JavaModule,以篩選掉所回報機器溫度低於可接受限制的訊息。 現在,請將解決方案建置成容器映像,並將其推送到容器登錄。
選取 [檢視] >[終端機] ,以開啟 VS Code 整合式終端機。
在終端機中輸入下列命令來登入 Docker。 使用您 Azure 容器登錄中的使用者名稱、密碼和登入伺服器登入。 您可以在 Azure 入口網站中,從登錄的 [存取金鑰] 區段擷取這些值。
docker login -u <ACR username> -p <ACR password> <ACR login server>
您可能會收到安全性警告,建議您使用
--password-stdin
。 雖然建議生產案例使用該最佳做法,但是不在本教學課程的討論範圍內。 如需詳細資訊,請參閱 docker login 參考。在 VS Code 總管中,以滑鼠右鍵按一下 deployment.template.json 檔案,然後選取 [建置並推送 IoT Edge 解決方案]。
建置和推送命令會啟動三項作業。 首先,它會在解決方案中建立名為 config 的新資料夾,以保存完整部署資訊清單 (根據部署範本中的資訊建立),以及其他解決方案檔案。 接著,它會執行
docker build
,以根據目標架構的適當 dockerfile 建置容器映像。 然後,它會執行docker push
以將映像存放庫推送至您的容器登錄。此程序第一次進行時可能需要幾分鐘的時間,但下一次執行命令時速度就會變快。
將模組部署到裝置
使用Visual Studio Code總管和 Azure IoT Edge擴充功能,將模組專案部署至您的IoT Edge裝置。 您已備妥您的案例所需的部署資訊清單,即 config 資料夾中的 deployment.amd64.json 檔案。 現在您只需選取要接收部署的裝置即可。
請確定您的 IoT Edge 裝置已啟動並執行。
在 Visual Studio Code 總管中,展開 [Azure IoT 中樞] 區段下的 [裝置] 來查看您的 IoT 裝置清單。
以滑鼠右鍵按一下 IoT Edge 裝置的名稱,然後選取 [建立單一裝置的部署]。
選取 config 資料夾中的 deployment.amd64.json 檔案,然後按一下 [選取 Edge 部署資訊清單]。 請勿使用 deployment.template.json 檔案。
請展開裝置下的模組,以查看已部署且執行中的模組清單。 按一下 [重新整理] 按鈕。 您應該會看到新的 JavaModule 正在與 SimulatedTemperatureSensor 模組以及 $edgeAgent 和 $edgeHub 一起執行。
模組可能需要幾分鐘才會啟動。 IoT Edge 執行階段需要接收其新的部署資訊清單、從容器執行階段提取模組映像,然後啟動每個新的模組。
檢視所產生的資料
在您將部署資訊清單套用至 IoT Edge 裝置後,裝置的 IoT Edge 執行階段即會收集新的部署資訊,並開始在裝置上執行。 裝置上任何執行中、但未包含在部署資訊清單中的模組都會停止。 裝置中遺漏的任何模組都會啟動。
在 Visual Studio Code 總管中,以滑鼠右鍵按一下 IoT Edge 裝置的名稱,然後選取 [開始監視內建事件端點] 。
檢視送達 IoT 中樞的訊息。 訊息可能需要一段時間才會送達。 IoT Edge 裝置必須接收其新的部署,並啟動所有模組。 然後,我們對 JavaModule 程式碼所做的變更會等到機器溫度達到 25 度時才會傳送訊息。 它也會將 [警示] 訊息類型新增至任何觸達該溫度閾值的訊息。
編輯模組對應項
我們已使用部署資訊清單中的 JavaModule 模組對應項,設定 25 度的溫度閾值。 您可以使用模組對應項來變更此功能,而不必更新模組程式碼。
在 Visual Studio Code 中,展開您 IoT Edge 裝置底下的詳細資料,以查看執行中的模組。
以滑鼠右鍵按一下 JavaModule 並選取 [編輯模組對應項] 。
在所需的屬性中尋找 TemperatureThreshold。 將其值變更為高於最近報告溫度 5 到 10 度的新溫度。
儲存模組對應項檔案。
以滑鼠右鍵按一下模組對應項編輯窗格中的任意位置,然後選取 [更新模組對應項] 。
監視傳入的裝置到雲端訊息。 在新的溫度閾值送達前,您應該會看到訊息停止。
清除資源
如果您打算繼續閱讀下一篇建議的文章,則可以保留您所建立的資源和組態,並加以重複使用。 您可以也繼續使用相同的 IoT Edge 裝置作為測試裝置。
否則,可以刪除您在本文中建立的本機組態和 Azure 資源,以避免產生費用。
刪除 Azure 資源
刪除 Azure 資源和資源群組是無法回復的動作。 請確定您不會誤刪錯誤的資源群組或資源。 如果您在現有的資源群組內建立了 IoT 中樞,而該群組包含您想要保留的資源,則您只需刪除 IoT 中樞資源本身,而不要刪除資源群組。
若要刪除資源:
登入 Azure 入口網站,然後選取 [資源群組]。
選取您的 IoT Edge 測試資源所屬的資源群組名稱。
檢閱您的資源群組中包含的資源清單。 若要將其全部刪除,您可以選取 [刪除資源群組] 。 如果只要刪除某些部分,您可以按一下各個資源將其個別刪除。
後續步驟
在本教學課程中,您已建立 IoT Edge 模組,其可篩選您 IoT Edge 裝置所產生的原始資料。
繼續進行後續教學課程,以了解 Azure IoT Edge 如何協助您部署 Azure 雲端服務,以在邊緣處理和分析資料。