外部配置儲存模式

將配置資訊從應用程式部署套件移出至集中位置。 此方法提供更簡便的組態資料管理與控制,並能在應用程式與應用實例間共享組態資料。

內容和問題

大多數應用程式執行環境會包含你隨應用程式部署的檔案中的設定資訊。 在某些情況下,你可以編輯這些檔案,在部署應用程式後改變應用程式的行為。 不過,設定變更需要重新部署應用程式。 重新部署常導致無法接受的停機時間及其他行政負擔。

本地設定檔也限制設定僅限於單一應用程式。 在某些情況下,你可能想在多個應用程式間共享設定。 例如資料庫連接字串、UI 主題資訊,以及相關應用程式所使用的佇列與儲存的網址。

管理多個執行中的應用程式實例對本地設定的變更是一大挑戰。 這個挑戰可能導致在部署更新時使用不同的設定。

應用程式與元件的更新也可能需要修改組態結構。 許多設定系統不支援不同版本的設定資訊。

解法

將設定資訊儲存在外部儲存中,並提供一個介面,讓你能快速且有效率地閱讀與更新設定。 外部儲存的類型取決於應用程式的主機與執行環境。 在雲端託管情境中,外部儲存通常是基於雲端的儲存服務或專用的配置服務。 也可能是託管的資料庫或其他自訂系統。

你選擇的設定資訊備份儲存庫應該有一個介面,能提供一致且易於使用的存取。 它應該會以正確打字且結構化的格式呈現資訊。 實作方可能還需要授權使用者存取以保護設定資料。 它可能需要足夠靈活,能儲存多個版本的設定,例如開發、預備和生產,包含每個配置的多個版本。

許多內建配置系統會在應用程式啟動時讀取資料,然後將資料快取到記憶體中,以提供快速存取並減少對應用程式效能的影響。 根據你使用的備份儲存類型和延遲,你可能想在外部設定儲存中實作快取機制。 欲了解更多資訊,請參閱 快取指引。 下圖展示外部組態儲存模式的概述,並附有可選的本地快取。

一張圖示,展示外部組態儲存模式的概覽,並附有可選的本地快取。

問題和考慮

在決定如何實施此模式時,請考慮以下幾點:

  • 選擇提供可接受效能、高可用性且堅固的備份存儲。 確保你能在申請維護和管理過程中備份這些資料。 在雲端託管應用中,應使用雲端儲存機制或專用配置平台服務來滿足這些需求。

  • 設計備份儲存的架構,使其能容納的資訊類型有彈性。 確保它能滿足所有設定需求,例如類型資料、設定集合、多版本設定,以及應用程式所需的其他功能。 架構應該很容易擴展,以支援需求變更時的更多設定。

  • 考慮後備儲存的物理能力、它們與儲存配置資訊的方式之間的關聯,以及對效能的影響。 例如,儲存包含組態資訊的 XML 文件,需要設定介面或應用程式解析該文件以讀取個別設定。 解析會讓你更新設定變得複雜,但快取設定可以幫助抵消讀取速度變慢。

  • 請考慮設定介面如何允許控制設定範圍與繼承。 例如,你可能需要在組織、應用程式和機器層級定義配置範圍。 設定介面可能需要委派對不同範圍的存取控制,並防止或允許個別應用程式覆寫設定。

  • 確保設定介面能以所需格式揭露設定資料,例如類型值、集合、鍵值對及屬性袋。

  • 試想當設定包含錯誤或後台儲存庫中不存在時,設定儲存介面的行為。 你可能需要還原預設設定並記錄錯誤。 同時也要考慮設定鍵或名稱的大小寫區分、如何儲存與處理二進位資料,以及如何處理空值或空字串。

  • 考慮如何保護設定資料,並只讓適當的使用者和應用程式存取。 組態儲存介面通常提供此功能,但你也必須確保使用者和應用程式無法在未經適當權限的情況下直接存取後備儲存庫的資料。 確保讀取與寫入設定資料所需的權限嚴格分離。 也要考慮是否需要加密部分或全部設定,以及如何在配置儲存介面中實作這些加密。

    你也應該開啟審計日誌,記錄誰會讀取或修改設定值,以及這些行為何時發生。 對任何本地的備用設定資料副本,也適用相同的稽核要求。

  • 將不敏感的設定值與秘密值分開。 將例行設定,例如功能旗標和端點,保留在設定中。 將秘密資料,如連線字串、API 金鑰、憑證和密碼,儲存在專門的秘密管理系統中,提供加密與受控存取。

  • 集中儲存的配置,能在執行時改變應用程式行為,是關鍵。 部署、更新並管理它們,使用與部署應用程式碼相同的機制。 例如,您必須透過完整測試與分階段部署方法,執行可能影響多個應用程式的變更,以確保變更適合所有使用此配置的應用程式。 如果管理員編輯設定以更新某個應用程式,可能會對使用相同設定的其他應用程式產生不利影響。 像 Azure 應用程式組態 這類產品透過內建功能(如修訂歷史、點點恢復(PITR)、不可變快照及漸進式推送模式,協助降低此風險。

  • 如果應用程式快取設定資訊,當設定變更時你需要通知該應用程式。 你可以為快取的設定資料實作一個過期政策,讓這些資訊會自動定期更新。 應用程式會看到這些變更並實作它們。

  • 快取的組態資料可以幫助解決外部組態儲存在應用程式執行時遇到的暫時性連線問題,但如果應用程式啟動時外部儲存當機,這種方法通常無法解決問題。 確保你的應用程式部署流程能在組態檔中提供最後已知的組態值,以便在應用程式無法在啟動時取得即時值時使用。

使用此模式的時機

當下列情況時,請使用此模式:

  • 你需要在多個應用程式或實例間共享設定,或強制執行標準設定。

  • 你的標準配置系統並不支援所有必要的設定類型,例如圖片或複雜的資料結構。

  • 你需要一個互補的商店來管理某些設定,同時允許應用程式覆蓋部分或全部集中存儲的值。

  • 你需要簡化多個應用程式的管理,並可透過記錄對設定儲存庫的存取來監控設定使用情況。

在下列情況下,此模式可能不適用:

  • 你的設定很簡單,只針對一個應用程式,且只會在正常的發佈週期中改變。 在這種情況下,外部配置儲存可能會增加不必要的操作複雜度。

工作負載設計

評估如何在工作負載設計中使用外部配置儲存模式,以達成Azure Well-Architected框架支柱所涵蓋的目標與原則。 下表提供此模式如何支援每個要素目標的指引。

支柱 此模式如何支援支柱目標
卓越營運有助於透過標準化流程和團隊凝聚力來提供工作負載品質。 應用程式組態與應用程式程式碼的這種分離支援環境特定的組態,並將版本控制套用至組態值。 外部配置儲存也是管理功能旗標以實施安全部署措施的常見場所。

- OE:10 自動化設計
- OE:11 安全部署做法

如果此模式在一個支柱內部引入取捨,請將它們與其他支柱的目標進行考量。

範例

以下範例說明如何在 Azure 中實作外部設定儲存模式。 第一個範例使用了應用程式設定和用戶端函式庫。 第二個例子則使用自訂的後盾儲存庫,適用於需要專門實作的情境。

應用程式組態

大多數應用程式可以使用 應用程式設定(App Configuration )而非自訂設定商店。 App Configuration 支援鍵值對,你可以將其套用至命名空間。 App Configuration 也支援 不可變的設定快照 ,讓您能檢查、回滾或逐步部署設定變更,而不會有執行實例的風險。

使用 快照參考 ,讓應用程式在執行時無需更改程式碼或重新部署即可在快照間切換。 你可以匯出設定值,這樣如果服務啟動時無法存取,應用程式會附帶一份備份。

在應用程式設定中,鍵與值是 Unicode 字串,每個鍵值對都有可選的元資料,例如基於標籤的變體和內容類型。 使用內容類型來描述應用程式應該如何解讀某個值,例如 JSON 或內建的應用程式設定型態。 App Configuration 也會透過 PITS 保留修訂歷史,幫助你檢視並恢復先前的鍵值對。

為了增強韌性,建議將你的商店配置在支援 可用性區域 的區域,並開啟 地理複製 功能,這樣你就能設定應用程式在區域故障時從最近的副本讀取資料,並在副本端點間切換。 使用 Azure Key Vault references 將秘密保存在 金鑰保存庫 中,並從應用程式設定中引用,而不是直接將憑證儲存在設定儲存庫中。 使用受控身份和 Azure 基於角色的存取控制 (Azure RBAC)取代連接字串,以驗證應用程式到應用程式設定。

對於在 Azure Kubernetes Service (AKS) 中執行的工作負載,App Configuration Kubernetes Provider 可以直接從你的儲存庫產生 ConfigMaps 和 Secrets,無需在工作負載容器中修改程式碼。 你也可以使用 App Configuration 來管理 功能旗標,包括目標性推出和基於變化的實驗,以確保 安全的部署方法。

為了網路隔離,請使用 private endpoints for App Configuration 讓用戶端流量透過 Azure Private Link 保持在私人 IP 位址上。 設定私有存取後,你可以 關閉公開存取 以減少公開端點的暴露。 在地理複製部署中,單一私人端點可覆蓋所有複本,但為了提高區域韌性,你可以為每個複本區域配置私有端點,並相應設定網域名稱系統(DNS)。

這張圖展示了外部配置儲存模式的實作範例,應用程式配置作為中央樞紐,連接多個 Azure 服務與儲存系統。

在圖頂,有一支箭頭從 Azure 函式指向應用程式配置。 在圖表左側,箭頭連接 Azure 容器應用程式 環境與 AKS,並指向 App Configuration。 在圖表的右側,箭頭將 Azure 虛擬機(VM)和 Azure App 服務 連接到 App Configuration。 圖底有一支箭頭從 App Configuration 指向 金鑰保存庫。 該架構展示了 App Configuration 如何作為集中式的配置管理服務,多個 Azure 運算服務都能存取以取得應用程式設定,同時將敏感祕密保存在 金鑰保存庫 中,並透過 App Configuration 進行參考。

用戶端程式庫

用戶端函式庫提供了許多前述功能。 用戶端函式庫與應用程式執行時整合,協助擷取與快取值、值變動時刷新,並在 App Configuration 中處理暫時性中斷。

Runtime 用戶端程式庫 Notes 快速入門
.NET Microsoft.Extensions.Configuration.AzureAppConfiguration Microsoft.Extensions.Configuration 的提供者 .NET 快速入門
ASP.NET Core Microsoft.Azure.AppConfiguration.AspNetCore 新增 ASP.NET Core 的請求驅動刷新中介軟體 ASP.NET Core 快速入門
Azure Functions in .NET Microsoft.Azure.AppConfiguration.Functions.Worker 提供使用Program.cs的孤立工作者模型服務 Azure Functions 快速入門
.NET Framework Microsoft.Configuration.ConfigurationBuilders.AzureAppConfiguration 配置生成器 System.Configuration .NET 框架快速入門
爪哇之春 com.azure.spring > azure-spring-cloud-appconfiguration-config 支援 Spring Framework 存取,透過以下方式 ConfigurationProperties Java Spring 快速入門
Python Azure 應用程式配置提供者 提供動態刷新與 金鑰保存庫 參考支援的提供者函式庫 Python 快速入門
JavaScript 和 Node.js @azure/app-configuration-provider 提供動態刷新與 金鑰保存庫 參考支援的提供者函式庫 JavaScript 快速入門

以下 App 配置同步 GitHub 動作及內建 Azure Pipelines 任務也可用:

自訂後端儲存範例

在 Azure 主機的應用程式中,你可以使用 Azure 儲存體 將設定資訊儲存在外部。 此方法提供韌性與高效能。 預設情況下,儲存裝置在同一資料中心內會複製三次資料。 為了在各地區間實現地理上的冗餘性,你可以設定具有手動故障轉移功能的地理複製。 Azure 資料表儲存體 提供一個鍵值儲存,可以使用彈性的結構來管理這些值。 Azure Blob 儲存體 提供一個階層式、基於容器的儲存裝置,可以將任何類型的資料存放在獨立命名的 blob 中。

當你實作這個模式時,你需要抽象化 Blob 儲存體,並在應用程式中公開你的設定。 你還需要在執行時檢查更新,並決定如何回應這些更新。

以下範例展示了如何使用簡單的組態儲存庫和 Blob 儲存體 來儲存和暴露組態資訊。 BlobSettingsStore 類別會抽象 Blob 儲存體 以儲存配置資訊。 它實作了一個簡單的 ISettingsStore 介面。

public interface ISettingsStore
{
    Task<ETag> GetVersionAsync();
    Task<Dictionary<string, string>> FindAllAsync();
}

此介面定義了存取組態儲存所持有設定的方法,並包含一個版本號,可用來偵測近期的組態設定修改。 類別 BlobSettingsStore 可以利用 ETag blob 的特性來實作版本控制。 ETag這個屬性每次寫入 blob 時都會自動更新。

備註

設計上,這個簡單的示範會將所有設定以字串值而非型別值的形式呈現。

類別 ExternalConfigurationManager 提供對實例 BlobSettingsStore 的包裝器。 應用程式可以使用此類別來取得組態資訊。 此類別可能會使用變更通知機制,如 Microsoft Reactive Extensions,在系統運行時發布組態更新。 同時也實作了 Cache-Aside 模式 ,以提供更好的韌性與效能。

以下範例展示了你如何實作一個 ExternalConfigurationManager 類別。

static void Main(string[] args)
{
    // Start monitoring configuration changes.
    ExternalConfiguration.Instance.StartMonitor();

    // Get a setting.
    var setting = ExternalConfiguration.Instance.GetAppSetting("someSettingKey");
    …
}

下一步