使用參數和變數來增加彈性

已完成

範本的強大之處在於其可重複使用。 您可以使用 Bicep 來撰寫範本,以部署多個環境或資源的複本。

您任職的玩具公司會定期推出新產品,而您必須使用 Bicep 範本來建立每此推出產品時所需要的 Azure 資源。 您必須避免使用固定的資源名稱。 許多種 Azure 資源都需要唯一名稱,在範本中內嵌名稱意味著不能重複使用範本來多次推出產品。 您也必須根據玩具將在哪個市場推出而在不同的位置部署資源,所以您無法在範本中內嵌資源位置。

在此單元中,您將了解參數變數,這兩個 Bicep 功能可讓您的範本富有彈性並可重複使用。 我們也會向您介紹運算式

注意

本單元中的命令僅用於示範概念。 請先不要執行命令。 您很快就會在此練習所學到的內容。

參數和變數

「參數」可讓您帶進範本檔案外面的值。 例如,如果您使用 Azure CLI 或 Azure PowerShell 以手動方式部署範本,系統會要求您提供每個參數的值。 您也可以建立參數檔案,以列出所有要在部署中使用的參數和值。 如果透過自動化程序 (例如部署管線) 來部署範本,則管線可以提供參數值。

變數會在範本內加以定義並設定。 變數可讓您集中儲存重要資訊,供整個範本參考,而不需要複製並貼上。

針對在每個部署之間會有所改變的項目,使用參數通常是最好的辦法,例如:

  • 需要唯一的資源名稱。
  • 部署資源的位置。
  • 會影響資源定價的設定,例如其 SKU、定價層和執行個體計數。
  • 要存取範本中未定義的其他系統所需要有的認證和資訊。

如果您會針對每個部署使用相同的值,但又想要讓某個值可在範本內重複使用,或是想要使用運算式來建立複雜的值,那麼變數通常是不錯的選項。 您也可以針對不需要唯一名稱的資源使用變數。

提示

請務必妥善地為參數和變數命名,以讓範本變得容易閱讀和理解。 請務必使用清楚、具描述能力且一致的名稱。

新增參數

在 Bicep 中,您可以如下所示地定義參數:

param appServiceAppName string

讓我們看看這項定義的每個部分如何運作:

  • param 會告訴 Bicep 您要定義參數。
  • appServiceAppName 是參數的名稱。 如果您以手動方式部署範本,系統可能會要求您輸入值,因此請務必提供清楚且容易理解的名稱。 和資源符號名稱一樣,您也可以透過名稱在範本內參照參數值。
  • string 是參數的類型。 您可以為 Bicep 參數指定數種不同的類型,包括 string (用於文字)、int (用於數字) 以及 bool (用於布林值的 true 或 false 值)。 您也可以使用 arrayobject 類型來傳入更複雜的參數。

提示

請勿嘗試使用太多參數來將範本過度地一般化。 應該盡可能減少商務案例所需的參數。 請記住,如果將來需求變更,您隨時都可以變更範本。

提供預設值

您可以選擇性地為參數提供預設值。 當您指定預設值時,參數會變成選擇性。 部署範本的人員可以按照需要指定某個值,如果他們不需要,Bicep 會使用預設值。

以下是新增預設值的方法:

param appServiceAppName string = 'toy-product-launch-1'

注意

在此範例中,Azure App Service 應用程式名稱有硬式編碼的預設值。 這種做法不好,因為 App Service 應用程式需要唯一的名稱。 您很快就會修正此問題。

在範本中使用參數值

宣告參數之後,便可在範本的其餘部分參照該參數。 讓我們看看如何在資源定義中使用新的參數:

resource appServiceApp 'Microsoft.Web/sites@2023-12-01' = {
  name: appServiceAppName
  location: 'eastus'
  properties: {
    serverFarmId: appServicePlan.id
    httpsOnly: true
  }
}

請注意,範本現在會使用參數值來設定應用程式資源的資源名稱,而不是硬式編碼值。

提示

Visual Studio Code 的 Bicep 延伸模組顯示視覺指標,告知您未遵循建議的做法。 例如,警告您定義的參數沒有用到。 Bicep Linter 在您工作時持續執行這些檢查。

新增變數

您可以如下所示地定義變數:

var appServicePlanName = 'toy-product-launch-plan'

變數的定義方式類似參數,但有一些差異:

  • 使用 var 關鍵字來告訴 Bicep 您要宣告的是變數。
  • 您必須為變數提供值。
  • 變數不需要類型。 Bicep 可以根據您所設定的值來決定類型。

運算式

撰寫範本時,通常不建議將值硬式編碼,甚至連在參數中指定也不建議。 相反地,您會想要在範本執行時再探索值。 例如,或許可以將範本中的所有資源部署至單一 Azure 區域,亦即已建立資源群組的區域。 或者,可根據公司採用的特定命名策略,自動為資源建立唯一名稱。

Bicep 中的運算式是威力強大的功能,可協助您處理各種有趣的案例。 讓我們看看您可以在 Bicep 範本中使用運算式的幾個地方。

資源位置

當您在撰寫和部署範本時,您通常不會想要個別指定每個資源的位置。 相反地,您可能有一個簡單的商務規則指出:預設將所有資源部署至建立資源群組的同一個位置

在 Bicep 中,您可以建立名為 location 的參數,然後使用運算式來設定值:

param location string = resourceGroup().location

看一下該參數的預設值。 使用名為 resourceGroup()函式,針對要部署範本的資源群組,可讓您存取其相關資訊。 在此範例中,範本會使用 location 屬性。 通常以此方法將資源部署至資源群組所在的同一個 Azure 區域。

如果有人要部署此範本,其可能會選擇覆寫此處的預設值,並使用不同的位置。

注意

Azure 中的某些資源只能部署至特定位置。 您可能需要不同的參數來設定這些資源的位置。

您現在可以在範本內使用資源位置參數,如下所示:

resource appServiceApp 'Microsoft.Web/sites@2023-12-01' = {
  name: appServiceAppName
  location: location
  properties: {
    serverFarmId: appServicePlan.id
    httpsOnly: true
  }
}

資源名稱

許多 Azure 資源都需要唯一的名稱。 在您的案例中,您有兩個需要唯一名稱的資源:儲存體帳戶和 App Service 應用程式。 要求將這些值設定為參數會讓其他人難以使用該範本,因為他們需要找出其他人未用過的名稱。

Bicep 有另一個名為 uniqueString() 的函式可在您建立資源名稱時派上用場。 使用此函式時,您必須提供種子值,其在不同的部署上應該不同,但對相同資源的所有部署則必須一致。

如果您選擇良好的種子值,則每次部署相同的資源集時,都可以取得相同的名稱,但只要使用相同的範本部署不同的資源集,您就會得到不同的名稱。 讓我們看看要如何使用 uniqueString() 函式:

param storageAccountName string = uniqueString(resourceGroup().id)

這個參數的預設值會再次使用 resourceGroup() 函式,就和您在設定資源位置時所做的一樣。 不過,這次您會得到資源群組的識別碼。 資源群組識別碼的樣貌如下:

/subscriptions/aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e/resourceGroups/MyResourceGroup

資源群組識別碼包含 Azure 訂用帳戶識別碼 (aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e) 和資源群組名稱 (MyResourceGroup)。 資源群組識別碼通常適合作為資源名稱的候選種子值,原因如下:

  • 每次您部署相同的資源時,資源都會進入相同的資源群組。 uniqueString() 函式每次都傳回相同的值。
  • 如果部署至 Azure 訂用帳戶中的兩個不同資源群組,因為資源群組名稱不同,resourceGroup().id 值也會不同。 uniqueString() 函式給予每一組資源的值都不同。
  • 如果您部署至兩個不同的 Azure 訂用帳戶,即使您使用相同的資源群組名稱resourceGroup().id 值仍會不同,因為 Azure 訂用帳戶識別碼將會不同。 同樣地,uniqueString() 函式給予每一組資源的值都不同。

提示

使用範本運算式來建立資源名稱通常是不錯的做法。 許多 Azure 資源類型都有關於允許的字元和其名稱長度的規則。 在範本中內嵌資源名稱建立,表示使用該範本的任何人都不必自己記得遵循這些規則。

合併的字串

如果 uniqueString() 函式只用來設定資源名稱,雖然可能得到唯一名稱,但沒有意義。 好的資源名稱也應該有描述能力,能夠清楚說明資源的用途。 您通常可以藉由將有意義的字組或字串與唯一值相結合,來建立名稱。 如此一來,您就會擁有既有意義是唯一的資源名稱。

Bicep 有一個稱為字串插補的功能可讓您合併字串。 讓我們看看其運作方式:

param storageAccountName string = 'toylaunch${uniqueString(resourceGroup().id)}'

storageAccountName 參數的預設值現在有兩個部分:

  • toylaunch 是硬式編碼的字串,可協助任何人在查看 Azure 中已部署的資源時,能夠了解此儲存體帳戶的用途。
  • ${uniqueString(resourceGroup().id)} 可指示 Bicep 評估 uniqueString(resourceGroup().id) 函式的輸出,然後串連成字串。

提示

有時 uniqueString() 函式會建立開頭為數字的字串。 某些 Azure 資源 (例如儲存體帳戶) 不允許名稱開頭為數字。 這表示使用字串插補來建立資源名稱 (如上述範例所示) 會是不錯的做法。

選取資源的 SKU

您小組內的其他成員非常滿意您到目前為止所建置的 Bicep 程式碼。 您已決定使用範本來部署資源,以支援所有新玩具的推出。

有一位同事建議您在每次產品推出之前建立非生產環境,以協助行銷小組測試網站,之後再開放給客戶。 不過,您想要確保您們不會在非生產環境上面支出太多費用,因此您一起決定一些原則:

  • 在生產環境中,儲存體帳戶以 Standard_GRS (異地備援儲存體) SKU 部署,復原能力較高。 App Service 方案以 P2v3 SKU 部署,效能較高。
  • 在非生產環境中,儲存體帳戶將會部署在 Standard_LRS (本地備援儲存體) SKU。 App Service 方案將會部署在免費的 F1 SKU。

實作這些商務需求的其中一種方式是使用參數來指定每個 SKU。 但是,將每個 SKU 指定為參數可能會變得難以管理,尤其是當您的範本較大時。 另一個選項是使用參數、變數和運算式的組合,將商務規則內嵌到範本中。

首先,您可以指定參數來指出部署適用於生產還是非生產環境:

@allowed([
  'nonprod'
  'prod'
])
param environmentType string

請注意,此程式碼會使用一些新的語法來指定 environmentType 參數的允許值清單。 除非提供上述其中一個值,否則 Bicep 不會讓任何人部署範本。

接下來,您可以建立變數來根據環境決定要用於儲存體帳戶和 App Service 方案的 SKU:

var storageAccountSkuName = (environmentType == 'prod') ? 'Standard_GRS' : 'Standard_LRS'
var appServicePlanSkuName = (environmentType == 'prod') ? 'P2V3' : 'F1'

也請注意這裡的一些新語法。 讓我們將其拆解:

  • (environmentType == 'prod') 會評估為布林值 (true 或 false) 值,視允許用於 environmentType 參數的值而定。
  • ? 稱為三元運算子,其會評估 if/then 陳述式。 如果運算式為 true,則會使用 ? 運算子後面的值。 如果運算式評估為 false,則會使用冒號 (:) 後面的值。

我們可以將這些規則轉譯為:

  • 針對 storageAccountSkuName 變數,如果 environmentType 參數設定為 prod,則使用 Standard_GRS SKU。 否則,會使用 Standard_LRS SKU。
  • 針對 appServicePlanSkuName 變數,如果 environmentType 參數設定為 prod,則使用 P2V3 SKU 和 PremiumV3 階層。 否則,會使用 F1 SKU。

提示

當您建立和這個範例一樣有多個部分的運算式時,最好使用變數而不是直接將運算式內嵌至資源屬性。 這可讓範本變得更容易閱讀和理解,因為其會透過邏輯避免資源定義變得雜亂。

當您在範本中使用參數、變數和運算式時,您可以重複使用範本並且快速部署新的資源集。 例如,每當行銷部門要求您為下次推出的玩具部署新網站時,您會為部署的每個環境提供新的參數值,這樣就準備妥當了!