
這三者雖然都跟「儲存資料」或「設定」有關,但在雲端架構中扮演的角色完全不同。
- Storage Account 是放「檔案」
- App Service 設定是放「靜態環境變數」
- App Configuration 則是放「動態、跨服務的配置中心」
1. 三者的核心差異表
| 特性 | App Service (appsettings) | Azure App Configuration | Storage Account (Blob) |
| 主要用途 | 存放單一 Web App 的環境變數。 | 集中管理多個服務的設定。 | 存放非結構化資料(圖片、影片、日誌)。 |
| 生效方式 | 修改後 Web App 會重啟。 | 支援 熱更新 (Hot Reload),不需重啟。 | 需透過 SDK 讀取檔案內容。 |
| 適用規模 | 單一小專案。 | 中大型微服務架構、多環境管理。 | 大量靜態檔案或大數據儲存。 |
| 功能重點 | 簡單、直接整合在部署流程。 | 版本控制、標籤 (Label)、功能開關 (Feature Flag)。 | 高擴展性、低成本儲存。 |
2. 詳細分析
Azure App Service (webapp config appsettings)
這是最基礎的作法。你在 Azure Portal 的「環境變數」中設定的內容,會以環境變數的形式注入到你的程式(如 .NET 的 IConfiguration)。
- 優點: 設定簡單,與 App Service 綁定,安全性高(可參考 Key Vault)。
- 缺點: 每次改動設定,Web App 就會重新啟動(Restart),這在正式環境可能會造成短暫的服務中斷。
Azure App Configuration
這是專門為微服務或複雜專案設計的配置中心。
- 集中化: 如果你有 10 個 Web App 都共用同一個資料庫連線字串,你不需要去 10 個地方改,只要在 App Configuration 改一次就好。
- 功能開關 (Feature Flags): 你可以在不重新部署程式的情況下,在 Portal 上點一下就開啟或關閉某個功能。
- 標籤管理: 可以針對不同環境(如
Development,Production)使用同一個 Key,但給予不同的標籤值。
Storage Account
這通常不建議用來存放一般的「應用程式設定值」。
- 用途: 如果你的設定是一個超大的 JSON 檔案或是程式碼需要讀取的配置表(例如:全台門市清單、稅率換算表),且這些資料不會頻繁變動,才會放在這裡。
- 存取: 程式必須透過
BlobServiceClient去下載並解析檔案,這比讀取環境變數慢且複雜。
3. 實戰建議:我該選哪一個?
- 如果你只有一個 Web App,且設定很少改:直接用 App Service 的環境變數 即可。
- 如果你有多個服務(Function, Web App, Container)且需要頻繁切換功能開關:請使用 Azure App Configuration,這能讓你管理起來輕鬆很多。
- 如果你的「設定」本身是一個大檔案(如 10MB 的規則庫):請放在 Storage Account,並在 App Configuration 中紀錄該檔案的 URL。
小撇步: 無論用哪一個,如果是敏感資訊(密碼、金鑰),請一律存在 Azure Key Vault,然後在 App Configuration 或 App Service 中引用它。
在 Python (特別是使用 Flask 或 Django 等 Web 框架) 中實作 Azure App Configuration 的動態刷新,核心機制是利用 SDK 提供的 on_refresh_callback 或定期檢查 Sentinel Key (哨兵鍵)。
與 .NET 的強型別注入不同,Python 需要手動調用 refresh() 方法來檢查配置是否變動。
1. 核心觀念:Sentinel Key (哨兵鍵)
為了效能,我們不會每次請求都去檢查所有設定。我們會定義一個名為 Sentinel 的 Key,當這個 Key 的值改變時,SDK 才會去拉取所有更新。
2. Python 程式碼實作 (以 Flask 為例)
首先,確保安裝必要的套件:
Bash
pip install azure-appconfiguration-provider flask
範例程式碼:
Python
import os
from flask import Flask
from azure.appconfiguration.provider import load_configuration, SentinelKey
app = Flask(__name__)
# 1. 連線字串 (建議放在環境變數中)
CONNECTION_STRING = os.environ.get("AZURE_APPCONFIG_CONNECTION_STRING")
# 2. 設定哨兵鍵 (當此 Key 變動時,觸發刷新)
select_key = SentinelKey("Sentinel", label="dev")
# 3. 載入配置並設定刷新機制
# refresh_on: 監控的鍵
# refresh_interval: 檢查間隔 (秒),這段時間內呼叫 refresh() 不會真的連網
config = load_configuration(
connection_string=CONNECTION_STRING,
refresh_on=[select_key],
refresh_interval=30
)
@app.route("/")
def index():
# 4. 每次請求或定期執行 refresh()
# SDK 會判斷是否超過 refresh_interval,若超過且 Sentinel 變動,則更新 config
config.refresh()
# 讀取設定值
message = config.get("GreetingMessage", "Hello World!")
return f"<h1>{message}</h1>"
if __name__ == "__main__":
app.run()
3. 實作細節說明
refresh_interval: 這非常重要。如果設為 30 秒,那麼在 30 秒內無論你呼叫幾次config.refresh(),它都不會去連線 Azure,以節省 API 呼叫成本與效能。- 非同步支援: 如果你使用的是
FastAPI,可以使用load_configuration的非同步版本(需安裝azure-appconfiguration-provider的非同步依賴)。 - 設定層級:
- 在 Azure Portal 修改
GreetingMessage後,必須同時去更新Sentinel的值(例如把 1.0 改成 1.1)。 - SDK 偵測到
Sentinel變了,才會一次把GreetingMessage也同步過來。
- 在 Azure Portal 修改
4. 為什麼在 Python 中不推薦「全自動」刷新?
在 .NET 中有 Middleware 可以自動處理,但在 Python 中,由於其 WSGI/ASGI 的運行機制,通常建議:
- 手動觸發: 在 Web Framework 的
before_request鉤子中呼叫refresh()。 - 背景任務: 使用
threading.Timer定期在背景執行refresh(),這樣不會阻塞使用者的請求。
接下來的建議
寫一個背景線程 (Background Thread) 的版本,讓 refresh() 在後台自動執行,而不影響 Web 請求的響應速度
