在 Linux 上使用自訂容器建立函式
在本教學課程中,您會使用 Linux 基礎映像,建立您的程式碼並將其部署至 Azure Functions 作為自訂 Docker 容器。 當您的函式需要特定的語言版本,或有內建映像所未提供的特定相依性或組態時,您通常會想使用自訂映像。
Azure Functions 支援使用自訂處理常式的任何語言或執行階段。 針對某些語言 (例如本教學課程中使用的 R 程式設計語言),您需要將執行階段或其他程式庫安裝為需要使用自訂容器的相依性。
在自訂 Linux 容器中部署您的函式程式碼需要進階方案或專用 (App Service) 方案裝載。 完成本教學課程會在您的 Azure 帳戶中產生費用 (以美元計價),您可以在完成時清除資源,將這些成本降到最低。
您也可以如建立您在 Linux 上託管的第一個函式所述,使用預設 Azure App Service 容器。 在 Azure Functions 基底映像存放庫中可找到針對 Azure Functions 支援的基底映像。
在本教學課程中,您會了解如何:
- 使用 Azure Functions Core Tools 建立函式應用程式和 Dockerfile。
- 使用 Docker 建置自訂映像。
- 將自訂映像發佈到容器登錄中。
- 在 Azure 中建立函式應用程式的支援資源
- 從 Docker Hub 部署函式應用程式。
- 將應用程式設定加入函式應用程式。
- 啟用持續部署。
- 啟用容器的 SSH 連線。
- 新增佇列儲存體輸出繫結。
- 使用 Azure Functions Core Tools 建立函式應用程式和 Dockerfile。
- 使用 Docker 建置自訂映像。
- 將自訂映像發佈到容器登錄中。
- 在 Azure 中建立函式應用程式的支援資源
- 從 Docker Hub 部署函式應用程式。
- 將應用程式設定加入函式應用程式。
- 啟用持續部署。
- 啟用容器的 SSH 連線。
您可以在任何執行 Windows、macOS 或 Linux 的電腦上遵循此教學課程。
設定您的本機環境
開始之前,您必須具備下列條件:
Azure Functions Core Tools 3.x 版。
下列其中一項用來建立 Azure 資源的工具:
Azure CLI 2.4 版或更新版本。
Azure Az PowerShell 模組 5.9.0 版或更新版本。
Azure CLI 2.4 版或更新版本。
- Node.js、作用中 LTS 和維修 LTS 版本 (建議使用 8.11.1 和 10.14.1)。
- Python 3.8 (64 位元)、Python 3.7 (64 位元)、Python 3.6 (64 位元)(由 Azure Functions 支援)。
Java Developer Kit 第 8 或第 11 版。
Apache Maven 3.0 版或更高版本。
- 您所用語言的開發工具。 本教學課程使用 R 程式設計語言作為範例。
您也需要具有作用中訂用帳戶的 Azure 帳戶。 免費建立帳戶。
建立並啟用虛擬環境
在適用的資料夾中執行下列命令,以建立並啟用名為 .venv
的虛擬環境。 請務必使用受 Azure Functions 支援的 Python 3.8、3.7 或 3.6。
python -m venv .venv
source .venv/bin/activate
如果 Python 未在您的 Linux 發行版本上安裝 venv 套件,請執行下列命令:
sudo apt-get install python3-venv
您將在這個已啟用的虛擬環境中執行所有後續命令。
建立和測試本機 Functions 專案
在終端機或命令提示字元中,針對您選擇的語言執行下列命令,以在目前資料夾中建立函式應用程式專案。
func init --worker-runtime node --language javascript --docker
func init --worker-runtime powershell --docker
func init --worker-runtime python --docker
func init --worker-runtime node --language typescript --docker
在空的資料夾中,執行下列命令以從 Maven 原型 \(英文\) 產生 Functions 專案。
mvn archetype:generate -DarchetypeGroupId=com.microsoft.azure -DarchetypeArtifactId=azure-functions-archetype -DjavaVersion=8 -Ddocker
-DjavaVersion
參數會告知函式執行階段要使用哪個 JAVA 版本。 如果您希望函式在 Java 11 上執行,請使用 -DjavaVersion=11
。 若未指定 -DjavaVersion
,Maven 預設為 JAVA 8。 如需詳細資訊,請參閱 JAVA 版本。
重要
JAVA_HOME
環境變數必須設定為正確 JDK 版本的安裝位置,才能完成本文。
Maven 會要求您提供在部署時完成產生專案所需的值。
當系統提示時,提供下列值:
Prompt | 值 | 描述 |
---|---|---|
groupId | com.fabrikam |
此值可在所有專案中唯一識別您的專案,並遵循適用於 Java 的套件命名規則。 |
artifactId | fabrikam-functions |
此值是 jar 的名稱 (不含版本號碼)。 |
version | 1.0-SNAPSHOT |
選擇預設值。 |
套件 | com.fabrikam.functions |
此值是所產生函式程式碼的 Java 套件。 使用預設值。 |
輸入 Y
或按 Enter 進行確認。
Maven 會以 artifactId 名稱在新資料夾中建立專案檔案,在此例中為 fabrikam-functions
。
func init --worker-runtime custom --docker
--docker
選項會產生專案的 Dockerfile
,這會定義適合用於 Azure Functions 和所選執行階段的自訂容器。
瀏覽至專案資料夾:
cd fabrikam-functions
使用下列命令,將函式新增至您的專案,其中 --name
引數是函式的唯一名稱,而 --template
引數可指定函式的觸發程序。 func new
在您的專案中建立 C# 程式碼檔案。
func new --name HttpExample --template "HTTP trigger" --authlevel anonymous
使用下列命令,將函式新增至您的專案,其中 --name
引數是函式的唯一名稱,而 --template
引數可指定函式的觸發程序。 func new
會建立符合函式名稱的子資料夾,其中包含名為 function.json 的組態檔。
func new --name HttpExample --template "HTTP trigger" --authlevel anonymous
在文字編輯器中,於名為 handler.R 的專案資料夾中建立檔案。 新增下列內容做為其內容。
library(httpuv)
PORTEnv <- Sys.getenv("FUNCTIONS_CUSTOMHANDLER_PORT")
PORT <- strtoi(PORTEnv , base = 0L)
http_not_found <- list(
status=404,
body='404 Not Found'
)
http_method_not_allowed <- list(
status=405,
body='405 Method Not Allowed'
)
hello_handler <- list(
GET = function (request) {
list(body=paste(
"Hello,",
if(substr(request$QUERY_STRING,1,6)=="?name=")
substr(request$QUERY_STRING,7,40) else "World",
sep=" "))
}
)
routes <- list(
'/api/HttpExample' = hello_handler
)
router <- function (routes, request) {
if (!request$PATH_INFO %in% names(routes)) {
return(http_not_found)
}
path_handler <- routes[[request$PATH_INFO]]
if (!request$REQUEST_METHOD %in% names(path_handler)) {
return(http_method_not_allowed)
}
method_handler <- path_handler[[request$REQUEST_METHOD]]
return(method_handler(request))
}
app <- list(
call = function (request) {
response <- router(routes, request)
if (!'status' %in% names(response)) {
response$status <- 200
}
if (!'headers' %in% names(response)) {
response$headers <- list()
}
if (!'Content-Type' %in% names(response$headers)) {
response$headers[['Content-Type']] <- 'text/plain'
}
return(response)
}
)
cat(paste0("Server listening on :", PORT, "...\n"))
runServer("0.0.0.0", PORT, app)
在 host.json 中,修改 customHandler
區段以設定自訂處理常式的啟動命令。
"customHandler": {
"description": {
"defaultExecutablePath": "Rscript",
"arguments": [
"handler.R"
]
},
"enableForwardingHttpRequest": true
}
若要在本機測試函式,請啟動專案根資料夾中的本機 Azure Functions 執行階段主機:
func start
func start
npm install
npm start
mvn clean package
mvn azure-functions:run
R -e "install.packages('httpuv', repos='http://cran.rstudio.com/')"
func start
一旦看到 HttpExample
端點出現在輸出中,請瀏覽至 http://localhost:7071/api/HttpExample?name=Functions
。 瀏覽器應該會顯示 "hello" 訊息,回應 Functions
,這是提供給 name
查詢參數的值。
使用 Ctrl-C 將主機停止。
建立容器映像並在本機進行測試
(選用) 檢查專案根資料夾中的 Dockerfile。 Dockerfile 描述在 Linux 上執行函式應用程式所需的環境。 在 Azure Functions 基底映像頁面中可找到針對 Azure Functions 支援的完整基底映像清單。
檢查專案根資料夾中的 Dockerfile。 Dockerfile 描述在 Linux 上執行函式應用程式所需的環境。 自訂處理常式應用程式會使用 mcr.microsoft.com/azure-functions/dotnet:3.0-appservice
映像做為其基底。
修改 Dockerfile 以安裝 R。將 Dockerfile 的內容取代為下列內容。
FROM mcr.microsoft.com/azure-functions/dotnet:3.0-appservice
ENV AzureWebJobsScriptRoot=/home/site/wwwroot \
AzureFunctionsJobHost__Logging__Console__IsEnabled=true
RUN apt update && \
apt install -y r-base && \
R -e "install.packages('httpuv', repos='http://cran.rstudio.com/')"
COPY . /home/site/wwwroot
在根專案資料夾中,執行 docker build 命令,然後提供名稱、azurefunctionsimage
和標記 (v1.0.0
)。 將 <DOCKER_ID>
取代為 Docker Hub 帳戶識別碼。 此命令會建置容器的 Docker 映像。
docker build --tag <DOCKER_ID>/azurefunctionsimage:v1.0.0 .
當命令完成時,您就能在本機執行新容器。
若要測試組建,請使用 docker run 命令在本機容器中執行映像,再以您的 Docker ID 取代 <DOCKER_ID
並新增連接埠引數 -p 8080:80
:
docker run -p 8080:80 -it <docker_id>/azurefunctionsimage:v1.0.0
映射在本機容器中啟動之後,流覽至 http://localhost:8080/api/HttpExample?name=Functions
,應該會顯示與之前相同的 「hello」 訊息。 因為您建立的 HTTP 觸發函式使用匿名授權,所以您可以呼叫在容器中執行的函式,而不需要取得存取金鑰。 若要深入瞭解,請參閱 授權金鑰。
在容器中驗證過函式應用程式容器之後,請利用 Ctrl+C停止 Docker。
將映像推送至 Docker 中樞
Docker Hub 是一個容器登錄,其裝載映像並提供映像和容器服務。 若要共用您的映像 (包括部署至 Azure),您必須將其推送到登錄。
如果您尚未登入 Docker,請使用 docker login 命令,將
<docker_id>
取代為您的 Docker 識別碼。 此命令會提示您輸入使用者名稱和密碼。 「登入成功」訊息會確認您已登入。docker login
登入之後,使用 docker push 命令將映像推送到 Docker Hub,再次將
<docker_id>
取代為您的 Docker 識別碼。docker push <docker_id>/azurefunctionsimage:v1.0.0
根據您的網路速度而定,第一次推送映像可能需要幾分鐘的時間 (推送後續變更的速度會更快)。 在等候時,您可以繼續進行下一節,並在另一個終端機中建立 Azure 資源。
為您的函式建立支援的 Azure 資源
若要將函式程式碼部署至 Azure,您必須先建立三個資源:
- 資源群組,這是相關資源的邏輯容器。
- 儲存體帳戶,用來維護函式的狀態和其他資訊。
- 函式應用程式,可提供用來執行函式程式碼的環境。 函式應用程式可對應至您的本機函式專案,並可讓您將函式分組為邏輯單位,以便管理、部署和共用資源。
請使用下列命令來建立這些項目。 Azure CLI 和 PowerShell 均受支援。
如果您尚未登入 Azure,請於此時登入:
az login
az login 命令會將您登入您的 Azure 帳戶。
在您選擇的區域中建立名為
AzureFunctionsContainers-rg
的資源群組:az group create --name AzureFunctionsContainers-rg --location <REGION>
az group create 命令會建立資源群組。 在上述命令中,使用az account list-locations命令傳回的可用區功能變數代碼,將 取代
<REGION>
為您附近的區域。在您的資源群組和區域中建立一般用途的儲存體帳戶:
az storage account create --name <STORAGE_NAME> --location <REGION> --resource-group AzureFunctionsContainers-rg --sku Standard_LRS
az storage account create 命令會建立儲存體帳戶。
在上述範例中,請將
<STORAGE_NAME>
取代為適合您且在 Azure 儲存體中是唯一的名稱。 名稱只能包含 3 到 24 個字元的數字和小寫字母。Standard_LRS
會指定受 Functions 支援的一般用途帳戶。使用 命令,在Elastic 進階版 1定價層 (
--sku EP1
) 、您的<REGION>
和 Linux (--is-linux
容器中建立名為 Azure Functions) 的進階版方案myPremiumPlan
。az functionapp plan create --resource-group AzureFunctionsContainers-rg --name myPremiumPlan --location <REGION> --number-of-workers 1 --sku EP1 --is-linux
我們在此使用進階方案,其可視需要進行調整。 若要深入了解裝載,請參閱 Azure Functions 裝載方案比較。 若要計算成本,請參閱 Functions 定價頁面。
此命令也會在相同的資源群組中佈建相關聯的 Azure Application Insights 執行個體,您可將其用於監視函式應用程式和檢視記錄。 如需詳細資訊,請參閱監視 Azure Functions。 在您啟用此執行個體之前,並不會產生任何成本。
使用映像在 Azure 上建立及設定函式應用程式
函式應用程式可管理您主控方案中函式的執行。 在這一節中,您會使用上一節的 Azure 資源,從 Docker Hub 上的映像建立函式應用程式,並使用 Azure 儲存體的連接字串加以設定。
使用下列命令建立函式應用程式:
az functionapp create --name <APP_NAME> --storage-account <STORAGE_NAME> --resource-group AzureFunctionsContainers-rg --plan myPremiumPlan --deployment-container-image-name <DOCKER_ID>/azurefunctionsimage:v1.0.0
在 az functionapp create 命令中, deployment-container-image-name 參數會指定要用於函式應用程式的映射。 您可使用 az functionapp config container show 命令來檢視部署所用映像的相關資訊。 您也可使用 az functionapp config container set 命令,從不同映像進行部署。 注意:如果您使用自訂容器登錄, deployment-container-image-name 參數會參考登錄 URL。
在此範例中,將 取代
<STORAGE_NAME>
為您在上一節中為儲存體帳戶使用的名稱。 另請以適合您的全域唯一名稱取代 ,並以<DOCKER_ID>
您的 DockerHub 識別碼取代<APP_NAME>
。 從自訂容器登錄進行部署時,請使用deployment-container-image-name
參數來指出登錄的 URL。提示
您可以使用
DisableColor
host.json 檔案中的 設定,以防止 ANSI 控制字元寫入容器記錄。使用下列命令來取得您所建立儲存體帳戶的連接字串:
az storage account show-connection-string --resource-group AzureFunctionsContainers-rg --name <STORAGE_NAME> --query connectionString --output tsv
儲存體帳戶的連接字串會使用 az storage account show-connection-string 命令傳回。
將 取代
<STORAGE_NAME>
為您先前建立的儲存體帳戶名稱。使用下列命令將此設定新增至函式應用程式:
az functionapp config appsettings set --name <APP_NAME> --resource-group AzureFunctionsContainers-rg --settings AzureWebJobsStorage=<CONNECTION_STRING>
在此命令中,將 取代為函式應用程式的名稱,並以
<CONNECTION_STRING>
上一個步驟中的連接字串取代<APP_NAME>
。 連接應該是開頭為 的長編碼字串DefaultEndpointProtocol=
。函式現在可以使用此連接字串來存取儲存體帳戶。
注意
如果您將自訂映射發佈至私人容器登錄,您應該改用 Dockerfile 中的環境變數作為連接字串。 如需詳細資訊,請參閱 ENV 指示。 您也應該設定變數 DOCKER_REGISTRY_SERVER_USERNAME
和 DOCKER_REGISTRY_SERVER_PASSWORD
。 若要使用這些值,您必須重建映像、將映像推送至登錄,然後在 Azure 上重新啟動函式應用程式。
在 Azure 上驗證您的函式
將映射部署至 Azure 中的函式應用程式之後,您現在可以透過 HTTP 要求叫用函式。 在您的瀏覽器中,流覽至如下所示的 URL:
https://<APP_NAME>.azurewebsites.net/api/HttpExample?name=Functions
以函式應用程式的名稱取代 <APP_NAME>
。 當您流覽至此 URL 時,瀏覽器應該會顯示類似您在本機執行函式時的輸出。
啟用持續部署至 Azure
您可以在每次更新登錄中的映像時,讓 Azure Functions 自動更新您的映像部署。
使用下列命令啟用持續部署並取得 Webhook URL:
az functionapp deployment container config --enable-cd --query CI_CD_URL --output tsv --name <APP_NAME> --resource-group AzureFunctionsContainers-rg
az functionapp deployment container config命令會啟用持續部署,並傳回部署 Webhook URL。 您稍後可以使用 az functionapp deployment container show-cd-url 命令來擷取此 URL。
如同先前,請將 取代
<APP_NAME>
為您的函式應用程式名稱。將部署 Webhook URL 複製到剪貼簿。
開啟 Docker Hub、登入,然後選取導覽列上的 [存放庫]。 找出並選取映像,選取 [Webhook] 索引標籤、指定 [Webhook 名稱]、在 [Webhook URL] 中貼入您的 URL,然後選取 [建立]:
設定 Webhook 後,每當您在 Docker Hub 中更新映像時,Azure Functions 就會重新部署您的映像。
啟用 SSH 連線
SSH 可讓容器和用戶端之間進行安全通訊。 啟用 SSH 之後,您就能使用 App Service 進階工具 (Kudu) 連線到您的容器。 為了讓您可以輕鬆地使用 SSH 連線到容器,Azure Functions 會提供已經啟用 SSH 的基底映像。 您只需要編輯 Dockerfile,然後重建並重新部署映像。 接著,您可以透過進階工具 (Kudu) 連線到容器
在您的 Dockerfile 中,將字串
-appservice
附加至FROM
指令中的基底映像:FROM mcr.microsoft.com/azure-functions/dotnet:3.0-appservice
FROM mcr.microsoft.com/azure-functions/node:2.0-appservice
FROM mcr.microsoft.com/azure-functions/powershell:2.0-appservice
FROM mcr.microsoft.com/azure-functions/python:2.0-python3.7-appservice
FROM mcr.microsoft.com/azure-functions/node:2.0-appservice
再次使用
docker build
命令重建映像,並以您的 Docker ID 取代<docker_id>
:docker build --tag <docker_id>/azurefunctionsimage:v1.0.0 .
將已更新的映像推送至 Docker Hub,這應該比第一次只推送所需上傳的映像更新後區段少很多時間。
docker push <docker_id>/azurefunctionsimage:v1.0.0
Azure Functions 會自動將映像重新部署至您的函式應用程式;此程序所需的時間不到一分鐘。
在瀏覽器中,開啟
https://<app_name>.scm.azurewebsites.net/
,以您的唯一名稱取代<app_name>
。 此 URL 是您函式應用程式容器的進階工具(Kudu) 端點。登入您的 Azure 帳戶,然後選取 [SSH],以建立與容器的連線。 如果 Azure 仍在更新容器映像,連線可能需要幾分鐘的時間。
建立與容器的連線之後,執行
top
命令來檢視目前執行中的程序。
寫入 Azure 佇列儲存體
Azure Functions 可讓您無須撰寫自己的整合程式碼,就能將函式連線到其他 Azure 服務與資源。 這些繫結同時代表輸入和輸出,會宣告於函式定義內。 繫結中的資料會提供給函式作為參數。 「觸發程序」是一種特殊的輸入繫結。 雖然函式只有一個觸發程序,但可以有多個輸入和輸出繫結。 若要深入了解,請參閱 Azure Functions 觸發程序和繫結概念。
本節說明如何將函式與 Azure 佇列儲存體整合。 您新增至此函式的輸出繫結,會將資料從 HTTP 要求寫入至佇列中的訊息。
擷取 Azure 儲存體連接字串
您稍早已建立可供函式應用程式使用的 Azure 儲存體帳戶。 此帳戶的連接字串會安全地儲存在 Azure 的應用程式設定中。 藉由將設定下載到 local.settings.json 檔案中,您可以在本機執行函式時,使用該連線寫入至相同帳戶中的儲存體佇列。
從專案的根目錄執行下列命令 (請將
<APP_NAME>
取代為先前快速入門中的函式應用程式名稱)。 此命令將會覆寫檔案中任何現有的值。func azure functionapp fetch-app-settings <APP_NAME>
開啟 local.settings.json 並找出名為
AzureWebJobsStorage
的值,也就是儲存體帳戶連接字串。 您會在本文的其他章節中使用名稱AzureWebJobsStorage
和連接字串。
重要
由於 local.settings.json 中包含從 Azure 下載的祕密,因此請一律將此檔案排除在原始檔控制以外。 使用本機函式專案建立的 .gitignore 檔案依預設會排除該檔案。
註冊繫結延伸模組
除了 HTTP 和計時器觸發程序之外,繫結皆會以擴充套件的形式實作。 在終端機視窗中執行下列 dotnet add package 命令來將儲存體套件新增至您的專案。
現在,您可以將儲存體輸出繫結新增至您的專案。
將輸出繫結定義新增至函式
一個函式只能有一個觸發程序,但可以有多個輸入和輸出繫結,如此,您無須撰寫自訂整合程式碼,即可連線至其他 Azure 服務和資源。
您會在函式資料夾中的 function.json 檔案中宣告這些繫結。 在先前的快速入門中,HttpExample 資料夾中的 function.json 檔案包含 bindings
集合中的兩個繫結:
"bindings": [
{
"authLevel": "function",
"type": "httpTrigger",
"direction": "in",
"name": "req",
"methods": [
"get",
"post"
]
},
{
"type": "http",
"direction": "out",
"name": "res"
}
]
"scriptFile": "__init__.py",
"bindings": [
{
"authLevel": "function",
"type": "httpTrigger",
"direction": "in",
"name": "req",
"methods": [
"get",
"post"
]
},
{
"type": "http",
"direction": "out",
"name": "$return"
}
"bindings": [
{
"authLevel": "function",
"type": "httpTrigger",
"direction": "in",
"name": "Request",
"methods": [
"get",
"post"
]
},
{
"type": "http",
"direction": "out",
"name": "Response"
}
]
每個繫結至少有一個類型、一個方向和一個名稱。 在上述範例中,第一個繫結的類型為 httpTrigger
、方向為 in
。 針對 in
方向,name
會指定觸發程序叫用函式時所傳入的輸入參數名稱。
集合中的第二個繫結名為 res
。 此 http
繫結是用來寫入 HTTP 回應的輸出繫結 (out
)。
若要從這個函式寫入至 Azure 儲存體佇列,請新增類型為 queue
、名稱為 msg
的 out
繫結,如下列程式碼所示:
{
"authLevel": "function",
"type": "httpTrigger",
"direction": "in",
"name": "req",
"methods": [
"get",
"post"
]
},
{
"type": "http",
"direction": "out",
"name": "res"
},
{
"type": "queue",
"direction": "out",
"name": "msg",
"queueName": "outqueue",
"connection": "AzureWebJobsStorage"
}
]
}
集合中第二個繫結的類型為 http
、方向為 out
,在此情況下,$return
的特殊 name
表示此繫結會使用函式的傳回值,而不是提供輸入參數。
若要從這個函式寫入至 Azure 儲存體佇列,請新增類型為 queue
、名稱為 msg
的 out
繫結,如下列程式碼所示:
"bindings": [
{
"authLevel": "anonymous",
"type": "httpTrigger",
"direction": "in",
"name": "req",
"methods": [
"get",
"post"
]
},
{
"type": "http",
"direction": "out",
"name": "$return"
},
{
"type": "queue",
"direction": "out",
"name": "msg",
"queueName": "outqueue",
"connection": "AzureWebJobsStorage"
}
]
集合中的第二個繫結名為 res
。 此 http
繫結是用來寫入 HTTP 回應的輸出繫結 (out
)。
若要從這個函式寫入至 Azure 儲存體佇列,請新增類型為 queue
、名稱為 msg
的 out
繫結,如下列程式碼所示:
{
"authLevel": "function",
"type": "httpTrigger",
"direction": "in",
"name": "Request",
"methods": [
"get",
"post"
]
},
{
"type": "http",
"direction": "out",
"name": "Response"
},
{
"type": "queue",
"direction": "out",
"name": "msg",
"queueName": "outqueue",
"connection": "AzureWebJobsStorage"
}
]
}
在此案例下,會將 msg
提供給函式作為輸出引數。 針對 queue
類型,您也必須在 queueName
中指定佇列的名稱,並在 connection
中提供 Azure 儲存體連線 (來自 local.settings.json) 的名稱。
在 C# 專案中,系結會定義為函式方法上的系結屬性。 特定定義取決於您的應用程式是在 C# 類別庫 () 或在隔離進程中執行。
開啟 HttpExample.cs 專案檔,並將下列參數新增至 Run
方法定義:
[Queue("outqueue"),StorageAccount("AzureWebJobsStorage")] ICollector<string> msg,
msg
參數是 ICollector<T>
類型,其代表會在函式完成時寫入輸出繫結的訊息集合。 在此情況下,輸出是名為 outqueue
的儲存體佇列。 儲存體帳戶的連接字串是由 StorageAccountAttribute
設定。 此屬性表示包含儲存體帳戶連接字串的設定,並可以被套用至類別、方法或參數層級。 在此情況下,您可以省略 StorageAccountAttribute
,因為您已經正在使用預設的儲存體帳戶。
Run 方法定義現在應該如下所示︰
[FunctionName("HttpExample")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
[Queue("outqueue"),StorageAccount("AzureWebJobsStorage")] ICollector<string> msg,
ILogger log)
在 Java 專案中,繫結會被定義為函式方法上的繫結註釋。 系統接著會根據這些註釋自動產生 function.json 檔案。
瀏覽至 src/main/java 底下您的函式程式碼位置,開啟 Function java 專案檔案,然後將下列參數新增至 run
方法定義:
@QueueOutput(name = "msg", queueName = "outqueue", connection = "AzureWebJobsStorage") OutputBinding<String> msg
msg
參數是 OutputBinding<T>
類型,其代表會在函式完成時寫入輸出繫結的字串集合。 在此情況下,輸出是名為 outqueue
的儲存體佇列。 儲存體帳戶的連接字串是由 connection
方法設定。 您會傳遞包含儲存體帳戶連接字串的應用程式設定,而不是連接字串本身。
run
方法定義現在應該如下列範例所示︰
@FunctionName("HttpTrigger-Java")
public HttpResponseMessage run(
@HttpTrigger(name = "req", methods = {HttpMethod.GET, HttpMethod.POST}, authLevel = AuthorizationLevel.FUNCTION)
HttpRequestMessage<Optional<String>> request,
@QueueOutput(name = "msg", queueName = "outqueue", connection = "AzureWebJobsStorage")
OutputBinding<String> msg, final ExecutionContext context) {
...
}
新增程式碼以使用輸出繫結
定義佇列系結之後,您現在可以更新函式,以使用系結參數將訊息寫入佇列。
更新 HttpExample\__init__.py 以符合下列程式碼,並將 參數新增 msg
至函式定義和 msg.set(name)
語句底下 if name:
。
import logging
import azure.functions as func
def main(req: func.HttpRequest, msg: func.Out[func.QueueMessage]) -> str:
name = req.params.get('name')
if not name:
try:
req_body = req.get_json()
except ValueError:
pass
else:
name = req_body.get('name')
if name:
msg.set(name)
return func.HttpResponse(f"Hello {name}!")
else:
return func.HttpResponse(
"Please pass a name on the query string or in the request body",
status_code=400
)
msg
參數是 azure.functions.Out class
的執行個體。 其 set
方法會將字串訊息寫入至佇列,在此案例中為傳至 URL 查詢字串中所含函式的名稱。
加入會使用 context.bindings
上的 msg
輸出繫結物件的程式碼來建立佇列訊息。 在 context.res
陳述式前面新增此程式碼。
// Add a message to the Storage queue,
// which is the name passed to the function.
context.bindings.msg = (req.query.name || req.body.name);
此時,您的函式看起來應如下所示:
module.exports = async function (context, req) {
context.log('JavaScript HTTP trigger function processed a request.');
if (req.query.name || (req.body && req.body.name)) {
// Add a message to the Storage queue,
// which is the name passed to the function.
context.bindings.msg = (req.query.name || req.body.name);
context.res = {
// status: 200, /* Defaults to 200 */
body: "Hello " + (req.query.name || req.body.name)
};
}
else {
context.res = {
status: 400,
body: "Please pass a name on the query string or in the request body"
};
}
};
加入會使用 context.bindings
上的 msg
輸出繫結物件的程式碼來建立佇列訊息。 在 context.res
陳述式前面新增此程式碼。
context.bindings.msg = name;
此時,您的函式看起來應如下所示:
import { AzureFunction, Context, HttpRequest } from "@azure/functions"
const httpTrigger: AzureFunction = async function (context: Context, req: HttpRequest): Promise<void> {
context.log('HTTP trigger function processed a request.');
const name = (req.query.name || (req.body && req.body.name));
if (name) {
// Add a message to the storage queue,
// which is the name passed to the function.
context.bindings.msg = name;
// Send a "hello" response.
context.res = {
// status: 200, /* Defaults to 200 */
body: "Hello " + (req.query.name || req.body.name)
};
}
else {
context.res = {
status: 400,
body: "Please pass a name on the query string or in the request body"
};
}
};
export default httpTrigger;
新增使用 Push-OutputBinding
Cmdlet 的程式碼,以使用 msg
輸出繫結將文字寫入至佇列。 在 if
陳述式中設定「確定」狀態之前,請先新增此程式碼。
$outputMsg = $name
Push-OutputBinding -name msg -Value $outputMsg
此時,您的函式看起來應如下所示:
using namespace System.Net
# Input bindings are passed in via param block.
param($Request, $TriggerMetadata)
# Write to the Azure Functions log stream.
Write-Host "PowerShell HTTP trigger function processed a request."
# Interact with query parameters or the body of the request.
$name = $Request.Query.Name
if (-not $name) {
$name = $Request.Body.Name
}
if ($name) {
# Write the $name value to the queue,
# which is the name passed to the function.
$outputMsg = $name
Push-OutputBinding -name msg -Value $outputMsg
$status = [HttpStatusCode]::OK
$body = "Hello $name"
}
else {
$status = [HttpStatusCode]::BadRequest
$body = "Please pass a name on the query string or in the request body."
}
# Associate values to output bindings by calling 'Push-OutputBinding'.
Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
StatusCode = $status
Body = $body
})
加入會使用 msg
輸出繫結物件的程式碼來建立佇列訊息。 在方法傳回之前加入此程式碼。
if (!string.IsNullOrEmpty(name))
{
// Add a message to the output collection.
msg.Add(string.Format("Name passed to the function: {0}", name));
}
此時,您的函式看起來應如下所示:
[FunctionName("HttpExample")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
[Queue("outqueue"),StorageAccount("AzureWebJobsStorage")] ICollector<string> msg,
ILogger log)
{
log.LogInformation("C# HTTP trigger function processed a request.");
string name = req.Query["name"];
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
dynamic data = JsonConvert.DeserializeObject(requestBody);
name = name ?? data?.name;
if (!string.IsNullOrEmpty(name))
{
// Add a message to the output collection.
msg.Add(string.Format("Name passed to the function: {0}", name));
}
return name != null
? (ActionResult)new OkObjectResult($"Hello, {name}")
: new BadRequestObjectResult("Please pass a name on the query string or in the request body");
}
現在,您可以使用新的 msg
參數,從您的函式程式碼寫入輸出繫結。 在成功回應之前新增下列一行程式碼,以將 name
的值新增至 msg
輸出繫結。
msg.setValue(name);
當您使用輸出繫結時,無須使用 Azure 儲存體 SDK 程式碼來進行驗證、取得佇列參考或寫入資料。 Functions 執行階段和佇列輸出繫結會為您進行這些工作。
您的 run
方法現在看起來應該如下列範例所示:
public HttpResponseMessage run(
@HttpTrigger(name = "req", methods = {HttpMethod.GET, HttpMethod.POST}, authLevel = AuthorizationLevel.ANONYMOUS)
HttpRequestMessage<Optional<String>> request,
@QueueOutput(name = "msg", queueName = "outqueue",
connection = "AzureWebJobsStorage") OutputBinding<String> msg,
final ExecutionContext context) {
context.getLogger().info("Java HTTP trigger processed a request.");
// Parse query parameter
String query = request.getQueryParameters().get("name");
String name = request.getBody().orElse(query);
if (name == null) {
return request.createResponseBuilder(HttpStatus.BAD_REQUEST)
.body("Please pass a name on the query string or in the request body").build();
} else {
// Write the name to the message queue.
msg.setValue(name);
return request.createResponseBuilder(HttpStatus.OK).body("Hello, " + name).build();
}
}
更新測試
因為原型也會建立一組測試,所以您需要更新這些測試,以處理 run
方法簽章中的新 msg
參數。
瀏覽至 src/test/java 底下的測試程式碼位置,開啟 Function.java 專案檔案,並以下列程式碼取代 //Invoke
下的程式碼行。
@SuppressWarnings("unchecked")
final OutputBinding<String> msg = (OutputBinding<String>)mock(OutputBinding.class);
final HttpResponseMessage ret = new Function().run(req, msg, context);
更新登錄中的映像
在根資料夾中,再次執行
docker build
,這次會將標記中的版本更新為v1.0.1
。 和之前一樣,以您的 Docker Hub 帳戶識別碼取代<docker_id>
:docker build --tag <docker_id>/azurefunctionsimage:v1.0.1 .
使用
docker push
將已更新的映像推送回存放庫:docker push <docker_id>/azurefunctionsimage:v1.0.1
因為您設定了持續傳遞,所以再次更新登錄中的映像,會自動在 Azure 中更新您的函式應用程式。
檢視 Azure 儲存體佇列中的訊息
在瀏覽器中,使用與之前相同的 URL 來叫用您的函式。 瀏覽器應會顯示與之前相同的回應,因為您未修改該部分的函式程式碼。 不過,新增的程式碼會使用 name
URL 參數,將訊息寫入 outqueue
儲存體佇列。
您可以在Azure 入口網站或Microsoft Azure 儲存體總管中檢視佇列。 您也可以在 Azure CLI 中檢視佇列,如下列步驟所說明:
開啟函式專案的 local.setting.json 檔案,並複製連接字串值。 在終端機或命令視窗中,執行下列命令來建立名為 的
AZURE_STORAGE_CONNECTION_STRING
環境變數,並貼上您的特定連接字串來取代<MY_CONNECTION_STRING>
。 (此環境變數意味著您無須使用--connection-string
引數將連接字串提供給每個後續命令。)export AZURE_STORAGE_CONNECTION_STRING="<MY_CONNECTION_STRING>"
(選擇性) 使用
az storage queue list
命令檢視您帳戶中的儲存體佇列。 此命令的輸出應該會包含名為outqueue
的佇列,這是函式將其第一個訊息寫入至該佇列時所建立的。az storage queue list --output tsv
使用
az storage message get
命令來讀取此佇列中的訊息,這應該是您先前測試函式時所使用的名字。 此命令會讀取並移除佇列中的第一個訊息。echo `echo $(az storage message get --queue-name outqueue -o tsv --query '[].{Message:content}') | base64 --decode`
由於訊息本文會以 base64 編碼儲存,因此必須先將訊息解碼才會顯示。 執行
az storage message get
之後,就會從佇列中移除此訊息。 如果outqueue
中只有一個訊息,則當您第二次執行此命令時,將不會擷取訊息,而是會收到錯誤。
清除資源
如果您想使用您在本教學課程中建立的資源來繼續使用 Azure 函式,您可以保留所有這些資源。 由於您已建立 Azure Functions 的進階方案,因此您會每天持續產生一或兩美元的成本。
若要避免持續產生成本,請刪除 AzureFunctionsContainer-rg
資源群組,以清除該群組中的所有資源:
az group delete --name AzureFunctionsContainer-rg