這是一個非常經典的雲端架構配置任務。要把在 Azure Container 裡的 Python Script 連接到 Azure SQL,我們需要完成「建立」、「開門(網路)」、「授權」這三個核心步驟。
以下是你在 Azure Portal 上的操作流程:
第一階段:建立 Azure SQL 資源
- 進入 Azure Portal: 搜尋 “Azure SQL” 並點選進入。
- 建立資源: 點擊 “Create”。
- 選擇資源類型: 選擇 “SQL Databases”,Resource type 選 “Single database”。
- 基本設定 (Basics):
- Project details: 選擇你的訂閱 (Subscription) 和資源群組 (Resource Group)。
- Database details: 輸入資料庫名稱(例如
mydb)。 - Server: 點擊 “Create new”。
- 輸入 Server 名稱(全域唯一)。
- Authentication method: 建議選擇 “Use both SQL and Azure AD authentication” (現在稱為 Microsoft Entra ID),這樣最彈性。
- 設定一個 Server Admin 帳號密碼。
- 運算與儲存 (Compute + storage): 測試用途建議選 “Serverless” 以節省成本。
- 檢閱 + 建立: 直接點擊 “Review + create”,確認後按下 “Create”。
第二階段:網路防火牆設定(最關鍵)
預設情況下,Azure SQL 是封閉的。你的 Container 要能連進去,必須開啟權限。
- 前往剛建好的 SQL Server 頁面(注意是 Server,不是 Database)。
- 在左側選單找到 “Security” -> “Networking”。
- Public Access 標籤頁:
- Public network access: 確保選擇 “Selected networks”。
- Exceptions: 勾選 “Allow Azure services and resources to access this server”。Note: 這一步非常重要!因為 Container 在 Azure 內部,這勾選後會允許 Azure 內部的流量通過防火牆。
- 按下 “Save”。
第三階段:準備 Python 連線資訊
在 Python script 中,你需要 Connection String。
- 前往 SQL Database 頁面。
- 左側選單點選 “Settings” -> “Connection strings”。
- 切換到 “Python” 頁籤,你會看到類似這樣的格式:
Driver={ODBC Driver 18 for SQL Server};Server=tcp:yourserver.database.windows.net,1433;Database=mydb;Uid=auth_user;Pwd={your_password};Encrypt=yes;TrustServerCertificate=no;Connection Timeout=30;
第四階段:Python Script 撰寫與環境準備
在你的 Dockerfile 和 Python 程式碼中,要注意以下兩點:
1. 安裝 ODBC Driver (Dockerfile)
Azure SQL 通常使用 pyodbc。你的 Container 映像檔(如果是基於 Debian/Ubuntu)必須安裝 Microsoft ODBC Driver。
Dockerfile
# 範例:在 Dockerfile 中安裝驅動
RUN apt-get update && apt-get install -y gnupg2 curl
RUN curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add -
RUN curl https://packages.microsoft.com/config/debian/11/prod.list > /etc/apt/sources.list.d/mssql-release.list
RUN apt-get update && ACCEPT_EULA=Y apt-get install -y msodbcsql18
2. Python 範例程式碼
Python
import pyodbc
# 建議使用環境變數讀取連線資訊
server = 'yourserver.database.windows.net'
database = 'mydb'
username = 'your_admin'
password = 'your_password'
driver= '{ODBC Driver 18 for SQL Server}'
conn_str = f'DRIVER={driver};SERVER={server};PORT=1433;DATABASE={database};UID={username};PWD={password}'
try:
with pyodbc.connect(conn_str) as conn:
with conn.cursor() as cursor:
cursor.execute("SELECT @@version;")
row = cursor.fetchone()
print(f"Connected! SQL Version: {row[0]}")
except Exception as e:
print(f"Error: {e}")
💡 專業小撇步 (Best Practice)
如果你希望更安全,不要在程式碼裡寫帳號密碼,建議在 Azure Portal 上為你的 Container 開啟 “Managed Identity”,然後在 SQL Database 裡授權給該 Identity。這樣你的 Python code 就可以實現「無密碼連線」。
「無密碼連線 (Managed Identity)」的 Python 實作範例
好的,使用 Managed Identity (受控識別) 是 Azure 上最推薦的安全性做法,因為你的程式碼中不需要存放任何資料庫密碼。
以下是實作「無密碼連線」的完整步驟:
第一步:在 Azure Portal 開啟 Container 的受控識別
假設你使用的是 Azure Container Instances (ACI) 或 Azure App Service:
- 在 Portal 找到你的 Container 資源。
- 左側選單點選 “Settings” -> “Identity”。
- 在 “System assigned” 頁籤,將 Status 切換為 “On”,點擊 “Save”。
- 系統會產生一個 “Object (principal) ID”,請先記下這個名稱(通常就是你的 Container 名稱)。
第二步:在 SQL Database 授權給該識別碼
Azure SQL 預設不認識這個 Identity,你需要用 SQL 指令授權給它:
- 回到 Azure SQL Database 頁面。
- 左側選單點選 “Query editor (preview)”。
- 使用你最初建立的 Admin 帳號密碼 登入。
- 執行以下 SQL 指令(將
<identity-name>替換成你的 Container 名稱):
SQL
-- 1. 為受控識別建立一個資料庫使用者
CREATE USER [<identity-name>] FROM EXTERNAL PROVIDER;
-- 2. 賦予權限 (例如 db_datareader 和 db_datawriter)
ALTER ROLE db_datareader ADD MEMBER [<identity-name>];
ALTER ROLE db_datawriter ADD MEMBER [<identity-name>];
-- 如果需要建立資料表權限,可改用 db_ddladmin
第三步:修改 Python 程式碼
你需要安裝 azure-identity 套件來獲取 Access Token。
1. 安裝必要套件:
Bash
pip install azure-identity pyodbc
2. Python 程式碼範例:
Python
import pyodbc
import struct
from azure.identity import DefaultAzureCredential
# 設定連線資訊
server = 'yourserver.database.windows.net'
database = 'mydb'
driver = '{ODBC Driver 18 for SQL Server}'
# 1. 使用 DefaultAzureCredential 自動獲取 Token
# 當程式跑在 Azure Container 時,它會自動抓取 Managed Identity 的身分
credential = DefaultAzureCredential()
token_bytes = credential.get_token("https://database.windows.net/.default").token.encode("utf-16-le")
token_struct = struct.pack(f'<I{len(token_bytes)}s', len(token_bytes), token_bytes)
# 2. 建立連線字串 (注意:這裡不含 UID 和 PWD)
conn_str = f'DRIVER={driver};SERVER={server};PORT=1433;DATABASE={database};Encrypt=yes;TrustServerCertificate=no;'
# 3. 連線並注入 Token
SQL_COPT_SS_ACCESS_TOKEN = 1256 # 固定常數,代表要傳入 Token
try:
conn = pyodbc.connect(conn_str, attrs_before={SQL_COPT_SS_ACCESS_TOKEN: token_struct})
cursor = conn.cursor()
cursor.execute("SELECT SUSER_SNAME();") # 確認目前登入的身分
row = cursor.fetchone()
print(f"成功連線!目前身分:{row[0]}")
except Exception as e:
print(f"連線失敗: {e}")
為什麼要這樣做?
- 安全性:你的 Dockerfile、環境變數、程式碼裡完全沒有密碼。即使程式碼外流,別人也無法連線。
- 維護性:不需要擔心密碼過期(Rotation)的問題。
- 權限控管:你可以隨時在 SQL 裡
DROP USER來收回該 Container 的存取權。
注意:在本地開發 (Local Development) 時,如果你想跑這段程式碼,你需要先在終端機執行 az login 登入你的 Azure 帳號,DefaultAzureCredential 就會自動抓取你本人的身分來進行測試。