在 Azure Container 連接到 Azure SQL 步驟

這是一個非常經典的雲端架構配置任務。要把在 Azure Container 裡的 Python Script 連接到 Azure SQL,我們需要完成「建立」、「開門(網路)」、「授權」這三個核心步驟。

以下是你在 Azure Portal 上的操作流程:


第一階段:建立 Azure SQL 資源

  1. 進入 Azure Portal: 搜尋 “Azure SQL” 並點選進入。
  2. 建立資源: 點擊 “Create”
  3. 選擇資源類型: 選擇 “SQL Databases”,Resource type 選 “Single database”
  4. 基本設定 (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 帳號密碼。
  5. 運算與儲存 (Compute + storage): 測試用途建議選 “Serverless” 以節省成本。
  6. 檢閱 + 建立: 直接點擊 “Review + create”,確認後按下 “Create”

第二階段:網路防火牆設定(最關鍵)

預設情況下,Azure SQL 是封閉的。你的 Container 要能連進去,必須開啟權限。

  1. 前往剛建好的 SQL Server 頁面(注意是 Server,不是 Database)。
  2. 在左側選單找到 “Security” -> “Networking”
  3. Public Access 標籤頁:
    • Public network access: 確保選擇 “Selected networks”
    • Exceptions: 勾選 “Allow Azure services and resources to access this server”Note: 這一步非常重要!因為 Container 在 Azure 內部,這勾選後會允許 Azure 內部的流量通過防火牆。
  4. 按下 “Save”

第三階段:準備 Python 連線資訊

在 Python script 中,你需要 Connection String

  1. 前往 SQL Database 頁面。
  2. 左側選單點選 “Settings” -> “Connection strings”
  3. 切換到 “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:

  1. 在 Portal 找到你的 Container 資源。
  2. 左側選單點選 “Settings” -> “Identity”
  3. “System assigned” 頁籤,將 Status 切換為 “On”,點擊 “Save”
  4. 系統會產生一個 “Object (principal) ID”,請先記下這個名稱(通常就是你的 Container 名稱)。

第二步:在 SQL Database 授權給該識別碼

Azure SQL 預設不認識這個 Identity,你需要用 SQL 指令授權給它:

  1. 回到 Azure SQL Database 頁面。
  2. 左側選單點選 “Query editor (preview)”
  3. 使用你最初建立的 Admin 帳號密碼 登入。
  4. 執行以下 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}")

為什麼要這樣做?

  1. 安全性:你的 Dockerfile、環境變數、程式碼裡完全沒有密碼。即使程式碼外流,別人也無法連線。
  2. 維護性:不需要擔心密碼過期(Rotation)的問題。
  3. 權限控管:你可以隨時在 SQL 裡 DROP USER 來收回該 Container 的存取權。

注意:在本地開發 (Local Development) 時,如果你想跑這段程式碼,你需要先在終端機執行 az login 登入你的 Azure 帳號,DefaultAzureCredential 就會自動抓取你本人的身分來進行測試。

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *