將您的應用程式邏輯遷移到雲端
手繪筆記由 Nitya Narasimhan 提供。點擊圖片查看大圖。
本課程是 IoT 01 for Beginners Project 2 - Digital Agriculture series 的一部分,由 Microsoft Reactor 教授。
課前測驗
簡介
在上一課中,您學會了如何將植物土壤濕度監測和繼電器控制連接到基於雲端的 IoT 服務。下一步是將控制繼電器定時的伺服器代碼移動到雲端。在本課中,您將學習如何使用無伺服器函數來完成此操作。
在本課 中,我們將涵蓋:
什麼是無伺服器?
無伺服器,或無伺服器計算,涉及創建在雲端運行的小代碼塊,以響應不同類型的事件。當事件發生時,您的代碼會運行,並且會傳遞有關事件的數據。這些事件可以來自許多不同的事物,包括網絡請求、放置在隊列中的消息、數據庫中的數據變更或 IoT 設備發送到 IoT 服務的消息。
💁 如果您以前使用過數據庫觸發器,您可以將其視為相同的東西,代碼由插入行等事件觸發。
您的代碼僅在事件發生時運行,其他時間不會保持您的代碼處於活動狀態。事件發生時,您的代碼會被加載並運行。這使得無伺服器非常可擴展 - 如果許多事件同時發生,雲提供商可以同時運行您的函數多次,跨越他們可用的任何伺服器。這樣的缺點是,如果您需要在事件之間共享信息,您需要將其保存在某個地方,例如數據庫,而不是存儲在內存中。
您的代碼被寫成一個函數,該函數將有關事件的詳細信息作為參數。您可以使用多種編程語言來編寫這些無伺服器函數。
🎓 無伺服器也被稱為函數即服務 (FaaS),因為每個事件觸發器都在代碼中實現為一個函數。
儘管名稱如此,無伺服器實際上確實使用伺服器。這個名稱是因為作為開發人員的您不需要關心運行代碼所需的伺服器,您只需要關心代碼是否響應事件而運行。雲提供商有一個無伺服器運行時,負責管理分配伺服器、網絡、存儲、CPU、內存和運行代碼所需的所有其他資源。這種模式意味著您不能按伺服器付費,因為沒有伺服器。相反,您按代碼運行的時間和使用的內存量付費。
💰 無伺服器是雲端運行代碼的最便宜方式之一。例如,在撰寫本文時,一個雲提供商允許您的所有無伺服器函數每月執行總共 1,000,000 次,然後才 開始向您收費,之後每 1,000,000 次執行收費 0.20 美元。當您的代碼不運行時,您不需要付費。
作為 IoT 開發人員,無伺服器模型是理想的。您可以編寫一個函數,該函數會響應從連接到您的雲託管 IoT 服務的任何 IoT 設備發送的消息。您的代碼將處理所有發送的消息,但僅在需要時運行。
✅ 回顧您編寫的作為伺服器代碼監聽 MQTT 消息的代碼。這如何在雲端使用無伺服器運行?您認為代碼需要如何更改以支持無伺服器計算?
💁 無伺服器模型正在移動到其他雲服務,除了運行代碼。例如,雲中提供無伺服器定價模型的無伺服器數據庫,您按對數據庫的每次請求付費,例如查詢或插入,通常基於完成請求所需的工作量定價。例如,針對主鍵選擇一行的單個選擇將比聯接多個表並返回數千行的複雜操作花費更少。
創建無伺服器應用程式
Microsoft 的無伺服器計算服務稱為 Azure Functions。
下面的短視頻概述了 Azure Functions
🎥 點擊上面的圖片觀看視頻
✅ 花點時間進行一些研究,閱讀 Microsoft Azure Functions 文檔 中的 Azure Functions 概述。
要編寫 Azure Functions,您需要使用您選擇的語言創建一個 Azure Functions 應用程式。開箱即用的 Azure Functions 支持 Python、JavaScript、TypeScript、C#、F#、Java 和 Powershell。在本課中,您將學習如何使用 Python 編寫 Azure Functions 應用程式。
💁 Azure Functions 還支持自定義處理程序,因此您可以使用任何支持 HTTP 請求的語言編寫函數,包括較舊的語言如 COBOL。
函數應用程式由一個或多個觸發器組成 - 響應事件的函數。您可以在一個函數應用程式中擁有多個觸發器,所有觸發器共享共同的配置。例如,在您的函數應用程式的配置文件中,您可以擁有 IoT 中樞的連接詳細信息,應用程式中的所有函數都可以使用這些詳細信息進行連接並監聽事件。
任務 - 安裝 Azure Functions 工具
在撰寫本文時,Azure Functions 代碼工具在 Apple Silicon 上與 Python 項目不完全兼容。您需要使用基於 Intel 的 Mac、Windows PC 或 Linux PC。
Azure Functions 的一個很棒的功能是您可以在本地運行它們。雲中使用的相同運行時可以在您的計算機上運行,允許您編寫響應 IoT 消息的代碼並在本地運行它。您甚至可以在處理事件時調試代碼。一旦您對代碼感到滿意,就可以將其部署到雲端。
Azure Functions 工具可作為 CLI 使用,稱為 Azure Functions Core Tools。
-
按照 Azure Functions Core Tools 文檔 中的說明安裝 Azure Functions 核心工具
-
安裝 VS Code 的 Azure Functions 擴展。此擴展提供創建、調試和部署 Azure 函數的支持。請參閱 Azure Functions 擴展文檔 了解在 VS Code 中安裝此擴展的說明。
當您將 Azure Functions 應用程式部署到雲端時,它需要使用少量雲存儲來存儲應用程式文件和日誌文件等內容。當您在本地運行函數應用程式時,您仍然需要連接到雲存儲,但可以使用名為 Azurite 的存儲模擬器,而不是使用實際的雲存儲。這在本地運行,但表現得像雲存儲。
🎓 在 Azure 中,Azure Functions 使用的存儲是一個 Azure 存儲帳戶。這些帳戶可以存儲文件、Blob、表中的數據或隊列中的數據。您可以在多個應用程式之間共享一個存儲帳戶,例如函數應用程式和 Web 應用程式。
-
Azurite 是一個 Node.js 應用程式 ,因此您需要安裝 Node.js。您可以在 Node.js 網站 上找到下載和安裝說明。如果您使用的是 Mac,您也可以從 Homebrew 安裝它。
-
使用以下命令安裝 Azurite(
npm
是安裝 Node.js 時安裝的工具):npm install -g azurite
-
創建一個名為
azurite
的文件夾供 Azurite 用於存儲數據:mkdir azurite
-
運行 Azurite,將此新文件夾傳遞給它:
azurite --location azurite
Azurite 存儲模擬器將啟動並準備好連接本地函數運行時。
➜ ~ azurite --location azurite
Azurite Blob service is starting at http://127.0.0.1:10000
Azurite Blob service is successfully listening at http://127.0.0.1:10000
Azurite Queue service is starting at http://127.0.0.1:10001
Azurite Queue service is successfully listening at http://127.0.0.1:10001
Azurite Table service is starting at http://127.0.0.1:10002
Azurite Table service is successfully listening at http://127.0.0.1:10002
任務 - 創建 Azure Functions 項目
Azure Functions CLI 可用於創建新的函數應用程式。
-
為您的函數應用程式創建一個文件夾並導航到該文件夾。將其命名為
soil-moisture-trigger
mkdir soil-moisture-trigger
cd soil-moisture-trigger -
在此文件夾中創建一個 Python 虛擬環境:
python3 -m venv .venv
-
激活虛擬環境:
-
在 Windows 上:
-
如果您使用的是命令提示符或 Windows 終端中的命令提示符,請運行:
.venv\Scripts\activate.bat
-
如果您使用的是 PowerShell,請運行:
.\.venv\Scripts\Activate.ps1
-
-
在 macOS 或 Linux 上,運行:
source ./.venv/bin/activate
💁 這些命令應該從您運行創建虛擬環境 命令的相同位置運行。您永遠不需要導航到
.venv
文件夾,您應該始終從創建虛擬環境時所在的文件夾運行激活命令和任何安裝包或運行代碼的命令。 -
-
運行以下命令在此文件夾中創建一個函數應用程式:
func init --worker-runtime python soil-moisture-trigger
這將在當前文件夾中創建三個文件:
host.json
- 這個 JSON 文檔包含您的函數應用程式的設置。您不需要修改這些設置。local.settings.json
- 這個 JSON 文檔包含您的應用程式在本地運行時使用的設置,例如 IoT 中樞的連接字符串。這些設置僅限於本地,不應添加到源代碼控制中。當您將應用程式部署到雲端時,這些設置不會被部署,而是從應用程式設置中加載。這將在本課後面介紹。requirements.txt
- 這是一個 Pip requirements 文件,包含運行您的函數應用程式所需的 Pip 包。
-
local.settings.json
文件有一個設置,用於函數應用程式將使用的存儲帳戶。默認為空設置,因此需要設置。要連接到本地存儲模擬器 Azurite,將此值設置為以下內容:"AzureWebJobsStorage": "UseDevelopmentStorage=true",
-
使用 requirements 文件安裝必要的 Pip 包:
pip install -r requirements.txt
💁 必需的 Pip 包需要在此文件中,以便當函數應用程式部署到雲端時,運行時可以確保安裝正確的包。
-
為了測試一切是否正常工作,您可以啟動函數運行時。運行以下命令來啟動它:
func start
您將看到運行時啟動並報告未找到任何作業函數(觸發器)。
(.venv) ➜ soil-moisture-trigger func start
Found Python version 3.9.1 (python3).
Azure Functions Core Tools
Core Tools Version: 3.0.3442 Commit hash: 6bfab24b2743f8421475d996402c398d2fe4a9e0 (64-bit)
Function Runtime Version: 3.0.15417.0
[2021-05-05T01:24:46.795Z] No job functions found.⚠️ 如果您收到防火牆通知,請授予訪問權限,因為
func
應用程式需要能夠讀寫您的網絡。⚠️ 如果您使用的是 macOS,輸出中可能會有警告:
(.venv) ➜ soil-moisture-trigger func start
Found Python version 3.9.1 (python3).
Azure Functions Core Tools
Core Tools Version: 3.0.3442 Commit hash: 6bfab24b2743f8421475d996402c398d2fe4a9e0 (64-bit)
Function Runtime Version: 3.0.15417.0
[2021-06-16T08:18:28.315Z] Cannot create directory for shared memory usage: /dev/shm/AzureFunctions
[2021-06-16T08:18:28.316Z] System.IO.FileSystem: Access to the path '/dev/shm/AzureFunctions' is denied. Operation not permitted.
[2021-06-16T08:18:30.361Z] No job functions found.只要函數應用程式啟動並正確列出運行的函數,您就可以忽略這些警告。如 Microsoft Docs Q&A 中的這個問題 所述,可以忽略它們。
-
按
ctrl+c
停止函數應用程式。 -
在 VS Code 中打開當前文件夾,無論是通過打開 VS Code 然後打開此文件夾,還是運行以下命令:
code .
VS Code 將檢測到您的函數項目並顯示一個通知,說明:
檢測到文件夾 "soil-moisture-trigger" 中的 Azure Functions 項目,可能是在 VS Code 之外創建的。初始化以便在 VS Code 中最佳使用?
從此通知中選擇是。
-
確保 Python 虛擬環境在 VS Code 終端中運行。如有必要,終止並重新啟動它。
創建 IoT 中樞事件觸發器
函數應用程式是您的無伺服器代碼的外殼。要響應 IoT 中樞事件,您可以向此應用程式添加一個 IoT 中樞觸發器。此觸發器需要連接到發送到 IoT 中樞的消息流並響應它們。要獲取此消息流,您的觸發器需要連接到 IoT 中樞的事件中樞兼容端點。
IoT 中樞基於另一個 Azure 服務 Azure 事件中樞。事件中樞是一個允許您發送和接收消息的服務,IoT 中樞擴展了這一點,增加了 IoT 設備的功能。連接以從 IoT 中樞讀取消息的方式與使用事件中樞的方式相同。
✅ 進行一些研究:閱讀 Azure 事件中樞文檔 中的事件中樞概述。基本功能與 IoT 中樞相比如何?
要連接到 IoT 中樞的 IoT 設備,必須使用一個秘密密鑰,以確保只有允許的設備可以連接。連接以讀取消息時也是如此,您的代碼需要一個包含秘密密鑰的連接字符串,以及 IoT 中樞的詳細信息。
💁 您獲取的默認連接字符串具有 iothubowner 權限,這使得使用它的任何代碼都具有 IoT 中樞的完全權限。理想情況下,您應該使用最低級別的權限進行連接。這將在下一課中介紹。
一旦您的觸發器連接,函數內的代碼將對 IoT 中樞發送的每條消息進行調用,無論是哪個設備發送的。觸發器將消息作為參數傳遞。
任務 - 獲取事件中樞兼容端點連接字符串
-
從 VS Code 終端運行以下命令以獲取 IoT 中樞事件中樞兼容端點的連接字符串:
az iot hub connection-string show --default-eventhub \
--output table \
--hub-name <hub_name>將
<hub_name>
替換為您用於 IoT 中樞的名稱。 -
在 VS Code 中打開
local.settings.json
文件。在Values
部分內添加以下附加值:"IOT_HUB_CONNECTION_STRING": "<connection string>"
將
<connection string>
替換為上一步中的值。您需要在上面的行後添加逗號以使其成為有效的 JSON。
任務 - 創建事件觸發器
您現在可以創建事件觸發器了。
-
從 VS Code 終端運行以下命令,從
soil-moisture-trigger
文件夾內運行:func new --name iot-hub-trigger --template "Azure Event Hub trigger"
這將創建一個名為
iot-hub-trigger
的新函數。觸發器將連接到 IoT 中樞的事件中樞兼容端點,因此您可以使用事件中樞觸發器。沒有特定的 IoT 中樞觸發器。
這將在 soil-moisture-trigger
文件夾內創建一個名為 iot-hub-trigger
的文件夾,其中包含此函數。此文件夾內將包含以下文件:
-
__init__.py
- 這是包含觸發器的 Python 代碼文件,使用標準的 Python 文件名約定將此文件夾轉換為 Python 模塊。此文件將包含以下代碼:
import logging
import azure.functions as func
def main(event: func.EventHubEvent):
logging.info('Python EventHub trigger processed an event: %s',
event.get_body().decode('utf-8'))觸發器的核心是
main
函數。每當 IoT 中樞發送消息時,這個函數就會被調用,將該消息作為event
傳遞,並附帶與上一課中看到的註釋相同的屬性。函數的核心是記錄事件。
-
function.json
- 這包含觸發器的配置。主要配置在名為bindings
的部分中。綁定是 Azure Functions 與其他 Azure 服務之間連接的術語。此函數具有輸入綁定到事件中樞 - 它連接到事件中樞並接收數據。💁 您還可以有輸出綁定,以便函數的輸出發送到另一個服務。例如,您可以添加一個輸出綁定到數據庫並返回 IoT 中樞事件,並且它將自動插入到數據庫中。
✅ 進行一些研究:閱讀 Azure Functions 觸發器和綁定概念文檔 中的綁定。
bindings
部分包括綁定的配置。感興趣的值是:-
"type": "eventHubTrigger"
- 這告訴函數它需要監聽來自事件中樞的事件 -
"name": "events"
- 這是用於事件中樞事件的參數名稱。這與 Python 代碼中main
函數中的參數名稱匹配。 -
"direction": "in"
- 這是一個輸入綁定,來自事件中樞的數據進入函數 -
"connection": ""
- 這定義了讀取連接字符串的設置名稱。在本地運行時,這將從local.settings.json
文件中讀取此設置。💁 連接字符串不能存儲在
function.json
文件中,必須從設置中讀取。這是為了防止您意外暴露連接字符串。
-
-
由於 Azure Functions 模板中的錯誤,
function.json
中的cardinality
字段值不正確。將此字段從many
更新為one
:"cardinality": "one",
-
更新
function.json
文件中"connection"
的值,以指向您在local.settings.json
文件中添加的新值:"connection": "IOT_HUB_CONNECTION_STRING",
💁 記住 - 這需要指向設置,而不是包含實際的連接字符串。
-
連接字符串包含
eventHubName
值,因此function.json
文件中的此值需要清空。將此值更新為空字符串:"eventHubName": "",
任務 - 運行事件觸發器
-
確保您未運行 IoT 中樞事件監視器。如果這與函數應用程式同時運行,函數應用程式將無法連接並消耗事件。
💁 多個應用程式可以使用不同的消費者組連接到 IoT 中樞端點。這些將在後面的課程中介紹。
-
要運行函數應用程式,請從 VS Code 終端運行以下命令
func start
函數應用程式將啟動,並將發現
iot-hub-trigger
函數。然後它將處理過去一天內發送到 IoT 中樞的任何事件。(.venv) ➜ soil-moisture-trigger func start
Found Python version 3.9.1 (python3).
Azure Functions Core Tools
Core Tools Version: 3.0.3442 Commit hash: 6bfab24b2743f8421475d996402c398d2fe4a9e0 (64-bit)
Function Runtime Version: 3.0.15417.0
Functions:
iot-hub-trigger: eventHubTrigger
For detailed output, run func with --verbose flag.
[2021-05-05T02:44:07.517Z] Worker process started and initialized.
[2021-05-05T02:44:09.202Z] Executing 'Functions.iot-hub-trigger' (Reason='(null)', Id=802803a5-eae9-4401-a1f4-176631456ce4)
[2021-05-05T02:44:09.205Z] Trigger Details: PartitionId: 0, Offset: 1011240-1011632, EnqueueTimeUtc: 2021-05-04T19:04:04.2030000Z-2021-05-04T19:04:04.3900000Z, SequenceNumber: 2546-2547, Count: 2
[2021-05-05T02:44:09.352Z] Python EventHub trigger processed an event: {"soil_moisture":628}
[2021-05-05T02:44:09.354Z] Python EventHub trigger processed an event: {"soil_moisture":624}
[2021-05-05T02:44:09.395Z] Executed 'Functions.iot-hub-trigger' (Succeeded, Id=802803a5-eae9-4401-a1f4-176631456ce4, Duration=245ms)每次調用函數時,輸出中都會有一個
Executing 'Functions.iot-hub-trigger'
/Executed 'Functions.iot-hub-trigger'
塊,因此您可以看到每次函數調用處理了多少消息。 -
確保您的 IoT 設備正在運行。您將看到新的土壤濕度消息出現在函數應用程式中。
-
停止並重新啟動函數應用程式。您將看到它不會再次處理以前的消息,只會處理新消息。
💁 VS Code 還支持調試您的函數。您可以通過點擊每行代碼開始處的邊框設置斷點,或將光標放在代碼行上並選擇運行 -> 切換斷點,或按
F9
。您可以通過選擇運行 -> 開始調試、按F5
或選擇運行和調試窗格並選擇開始調試按鈕來啟動調試器。通過這樣做,您可以查看正在處理的事件的詳細信息。