前言
在 Kubernetes 上運行有狀態的資料庫工作負載一直是具有挑戰性的議題。這篇文章記錄如何在 Kubernetes 叢集上部署 SQL Server Always On Availability Group(AG),實現資料庫層級的高可用性和讀取擴展(Read Scale-Out)。
整體架構是部署 3 個 SQL Server 實例:1 個 Primary(讀寫)和 2 個 Secondary(唯讀副本),其中一個副本採用同步提交模式,另一個採用非同步提交模式。
Always On Availability Group 簡介
SQL Server Always On AG 提供了資料庫層級的高可用性和容錯能力。在 SQL Server 2017 之後,引入了 Read Scale Availability Group,可以不依賴叢集管理器(如 WSFC 或 Pacemaker)獨立部署。
同步模式
| 模式 | 行為 | 適用場景 |
|---|---|---|
| 同步提交(Synchronous) | Primary 的交易會等待 Secondary 確認 log 已寫入後才完成提交 | 需要零資料遺失的場景 |
| 非同步提交(Asynchronous) | Primary 提交後不等待 Secondary 確認 | 跨地域部署、可接受少量資料遺失的場景 |
持久化儲存配置
在 Kubernetes 上部署有狀態工作負載,首先需要配置儲存。需要建立以下資源:
StorageClass
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
name: sqlserver-sc-csi
annotations:
storageclass.kubernetes.io/is-default-class: "true"
provisioner: YOUR_CSI_PROVISIONER
parameters:
datastoreurl: "YOUR_DATASTORE_URL"
PersistentVolumeClaim(為每個實例各建立一個)
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: mssql-primary
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 8Gi
storageClassName: sqlserver-sc-csi
分別建立 mssql-primary、mssql-secondary1、mssql-secondary2 三個 PVC。
Secret
kubectl create secret generic mssql-secret \
--from-literal=SA_PASSWORD="********"
部署 SQL Server 實例
Primary SQL Server
以 Kubernetes Deployment 部署,關鍵配置要點:
apiVersion: apps/v1
kind: Deployment
metadata:
name: mssqlag-primary-deployment
spec:
replicas: 1
selector:
matchLabels:
app: mssql-primary
strategy:
type: Recreate # SQL Server 需要獨佔檔案鎖,必須先停舊再建新
template:
spec:
terminationGracePeriodSeconds: 10
securityContext:
fsGroup: 10001
hostname: mssql-primary # 設定固定主機名
containers:
- name: mssql-primary
image: mcr.microsoft.com/mssql/server:2019-CU15-ubuntu-20.04
env:
- name: ACCEPT_EULA
value: "Y"
- name: MSSQL_ENABLE_HADR
value: "1"
- name: MSSQL_AGENT_ENABLED
value: "true"
- name: MSSQL_SA_PASSWORD
valueFrom:
secretKeyRef:
name: mssql-secret
key: SA_PASSWORD
volumeMounts:
- name: mssqldb
mountPath: /var/opt/mssql
volumes:
- name: mssqldb
persistentVolumeClaim:
claimName: mssql-primary
幾個重要的設計決策:
strategy.type: Recreate:SQL Server 對資料檔案持有排他鎖,滾動更新會導致新 Pod 啟動失敗securityContext.fsGroup:設定檔案系統的群組 IDhostname:確保 SQL Server 實例有固定的伺服器名稱
同樣為兩個 Secondary 副本建立類似的 Deployment,並各自建立 LoadBalancer 類型的 Service 暴露 1433(SQL)和 5022(AG Endpoint)端口。
配置 Availability Group
Primary 端配置
在 Primary SQL Server 上依序執行以下操作:
- 建立測試資料庫並設定為 Full Recovery 模式
- 執行完整備份
- 建立 AG 登入帳戶
- 建立 Master Key 和憑證
- 建立 AG Endpoint(端口 5022,使用憑證驗證)
- 建立 Availability Group,指定 Primary 和 Secondary 副本
- 將資料庫加入 AG
複製憑證到 Secondary
透過 kubectl cp 將 Primary 產生的憑證和金鑰複製到 Secondary 實例:
# 取得 Pod 名稱
podagp=$(kubectl get pods -l app=mssql-primary -o json | jq -r '.items[0].metadata.name')
podags1=$(kubectl get pods -l app=mssql-secondary1 -o json | jq -r '.items[0].metadata.name')
# 從 Primary 複製到本地,再複製到 Secondary
kubectl cp $podagp:var/opt/mssql/ag_certificate.cert ag_certificate.cert
kubectl cp $podagp:var/opt/mssql/ag_certificate.key ag_certificate.key
kubectl cp ag_certificate.cert $podags1:var/opt/mssql
kubectl cp ag_certificate.key $podags1:var/opt/mssql
Secondary 端配置
在每個 Secondary 副本上:
- 建立 AG 登入帳戶(密碼須與 Primary 一致)
- 使用從 Primary 複製的憑證建立本地憑證
- 建立 AG Endpoint
- 加入 Availability Group
部署要點與注意事項
- Strategy 必須設為 Recreate:SQL Server 的資料檔案有排他鎖,RollingUpdate 會導致新舊 Pod 衝突
- hostname 必須固定:AG 配置中使用主機名稱來識別副本,如果不設定 hostname,Pod 重啟後名稱會變化
- 憑證管理:AG 端點間的通訊使用憑證驗證,需確保所有副本使用相同的憑證
- 密碼安全:所有敏感資訊都應該透過 Kubernetes Secret 管理,不要直接寫在 YAML 中
- 儲存效能:SQL Server 對 I/O 效能敏感,建議使用 SSD 等級的儲存
個人觀點
在 Kubernetes 上運行 SQL Server AG 確實可行,但相較於雲端託管的資料庫服務(如 Azure SQL、AWS RDS),維運複雜度會高很多。我建議在以下場景考慮這種部署方式:
- 需要完全控制資料庫環境的企業
- 混合雲架構中需要統一管理的場景
- 開發/測試環境中模擬生產環境的 HA 配置
對於大多數生產場景,如果雲端廠商有提供對應的託管服務,通常是更省心的選擇。

發佈留言