摘要
别再拿物理机那套玩达梦高可用了。本文记一次生产级 K8s 部署达梦数据守护集群的完整过程,从镜像改造、StatefulSet 编排,到主备自动切换验证,全部配置直接复制可用。文章提供关键配置文件对比表、避坑总结,助你一步到位落地容器化信创数据库高可用。
📌 政务选金仓,金融选达梦;MySQL 迁移选金仓,Oracle 迁移选达梦。
1. 背景与总体架构
达梦数据守护集群(DM Data Watch)对标 Oracle Data Guard,支持实时主备、自动故障切换。将其搬到 K8s 上,可以实现:
-
主备实例自动编排、IP 无状态化
-
数据持久化到 PVC,节点漂移不丢数据
-
守护进程与确认监视器容器化,统一管理
整体部署形态:
-
两个 StatefulSet 分别管理主库、备库(也可用同一个 StatefulSet 做双副本,但我推荐分开便于配置差异化)
-
持久化存储:达梦数据文件、归档日志、守护进程日志均使用 PVC
-
服务暴露:主库通过 ClusterIP Service 固定访问入口,备库提供只读服务
-
达梦监视器(Monitor)作为独立 Deployment 持续监控集群状态
✅ 本次环境:K8s 1.28 + 达梦 DM8.1 (8.1.2.192) + NFS 存储类
2. 环境与镜像准备
2.1 基础环境信息
| 组件 | 版本/规格 |
|---|---|
| Kubernetes | v1.28.2 |
| 达梦数据库 | DM8.1.2.192 (Docker) |
| 存储类 | nfs-client (ReadWriteOnce) |
| 镜像仓库 | harbor.dm.local |
2.2 达梦容器镜像定制
官方镜像可直接用,但需要打入配置脚本。我基于 dm8:dm8_20230808_rev197567_x86_rh6_64_ent 构建新镜像,增加:
-
初始化脚本
init.sh,用于根据 Pod 名称自动渲染配置文件 -
所需工具:
dminit,dmwatcher,dmmonitor
Dockerfile 关键片段:
dockerfile
FROM dm8:dm8_20230808
COPY dm_init.sh /usr/local/dmdbms/bin/
COPY dm_svc.conf /etc/dm_svc.conf
RUN chmod +x /usr/local/dmdbms/bin/dm_init.sh
ENTRYPOINT ["/usr/local/dmdbms/bin/dm_init.sh"]
dm_init.sh 逻辑:判断 Pod 名称末尾 -0 则按主库配置,-1 则按备库配置。
💡 避坑: 达梦容器内默认用户为
dmdba,启动脚本必须切到此用户,否则会因权限报错。
3. 主库 StatefulSet 部署
3.1 配置文件准备
我们使用 ConfigMap 挂载主库的参数文件,方便修改。
主库 dm.ini 关键参数(与备库不同之处已标出):
ini
INSTANCE_NAME = DMW_01 # 实例名,主备不同
PORT_NUM = 5236 # 数据库端口
MAL_INI = 1
ARCH_INI = 1
ALTER_MODE_STATUS = 0
ENABLE_OFFLINE_TS = 2
RLOG_SEND_APPLY_MON = 64
DW_PORT = 52141 # 守护进程 TCP 端口
由于篇幅,完整文件可通过 ConfigMap 注入。
dmmal.ini(MAL 通信配置,主备共用):
ini
[MAL_INST1]
MAL_INST_NAME = DMW_01
MAL_HOST = dm-primary-0.dm-primary-svc # 主库 StatefulSet Pod 域名
MAL_PORT = 61141
MAL_INST_HOST = dm-primary-0.dm-primary-svc
MAL_INST_PORT = 5236
[MAL_INST2]
MAL_INST_NAME = DMW_02
MAL_HOST = dm-standby-0.dm-standby-svc
MAL_PORT = 61142
MAL_INST_HOST = dm-standby-0.dm-standby-svc
MAL_INST_PORT = 5237
dmarch.ini(归档配置):
ini
[ARCHIVE_LOCAL1]
ARCH_TYPE = LOCAL
ARCH_DEST = /dm/data/arch
ARCH_FILE_SIZE = 2048
ARCH_SPACE_LIMIT = 51200
[ARCHIVE_REALTIME1]
ARCH_TYPE = REALTIME
ARCH_DEST = DMW_02 # 备库实例名
dmwatcher.ini(守护进程配置):
ini
[DMW_01]
DW_TYPE = GLOBAL
DW_MODE = MANUAL # 首次手动切换
DW_ERROR_TIME = 10
INST_RECOVER_TIME = 60
INST_ERROR_TIME = 20
INST_OGUID = 453331
INST_INI = /dm/data/DAMENG/dm.ini
INST_AUTO_RESTART = 1
INST_STARTUP_CMD = /usr/local/dmdbms/bin/dmserver
RLOG_SEND_THRESHOLD = 0
RLOG_APPLY_THRESHOLD = 0
⚠️ 注意:
INST_OGUID主备必须一致,且不为 0。
3.2 StatefulSet YAML(主库)
yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: dm-primary
spec:
serviceName: dm-primary-svc
replicas: 1
selector:
matchLabels:
app: dm-primary
template:
metadata:
labels:
app: dm-primary
spec:
containers:
- name: dm-primary
image: harbor.dm.local/dm8:datawatch
ports:
- containerPort: 5236
name: db
- containerPort: 52141
name: dw
- containerPort: 61141
name: mal
env:
- name: ROLE
value: PRIMARY
- name: INSTANCE_NAME
value: DMW_01
volumeMounts:
- name: data
mountPath: /dm/data
- name: config
mountPath: /dm/config
volumes:
- name: config
configMap:
name: dm-primary-config
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 100Gi
storageClassName: nfs-client
配套 Headless Service:
yaml
apiVersion: v1
kind: Service
metadata:
name: dm-primary-svc
spec:
clusterIP: None
ports:
- port: 5236
name: db
- port: 52141
name: dw
selector:
app: dm-primary
👉 初始化主库(在容器启动脚本中判断 ROLE=PRIMARY 时执行):
cd /dm/data
dminit PATH=/dm/data DB_NAME=DAMENG INSTANCE_NAME=DMW_01 \
PAGE_SIZE=32 EXTENT_SIZE=32 CASE_SENSITIVE=1 \
CHARSET=1 PORT_NUM=5236
# 启动数据库一次,开启归档
dmserver /dm/data/DAMENG/dm.ini mount
然后通过 SQL 设置 OGUID、开启守护:
sql
SP_SET_PARA_VALUE(1, 'ALTER_MODE_STATUS', 1);
ALTER DATABASE MOUNT;
ALTER DATABASE ARCHIVELOG;
ALTER DATABASE ADD ARCHIVELOG 'DEST=DMW_02,TYPE=REALTIME';
ALTER DATABASE OPEN FORCE;
SP_SET_OGUID(453331);
ALTER DATABASE SET STANDBY BY REAL;
4. 备库部署与守护进程配置
备库采用独立的 StatefulSet dm-standby,结构与主库类似,但副本数为 1,配置文件不同。
备库关键参数差异化对照表:
| 参数 | 主库 | 备库 |
|---|---|---|
| INSTANCE_NAME | DMW_01 | DMW_02 |
| PORT_NUM | 5236 | 5237 |
| DW_PORT | 52141 | 52142 |
| MAL_INST_PORT (通信端口) | 5236 | 5237 |
备库 dmwatcher.ini 中 INST_OGUID 同样为 453331。
备库初始化: 不需要执行 dminit,而是从主库备份还原。简化流程:先在主库全量备份,再在备库恢复并配置 standby。自动化脚本可实现在备库启动时,远程拉取备份并还原。
🛑 避坑: 务必备库数据库版本与主库完全一致,否则 MAL 通信会失败。
启动备库后执行:
sql
SP_SET_PARA_VALUE(1, 'ALTER_MODE_STATUS', 1);
ALTER DATABASE MOUNT;
SP_SET_OGUID(453331);
ALTER DATABASE SET STANDBY BY REAL;
ALTER DATABASE OPEN FORCE;
5. 确认监视器与自动切换验证
部署一个独立 Deployment 运行 dmmonitor,持续观察集群。
dmmonitor 配置(dmmonitor.ini):
sql
ini
MON_DW_CONFIRM = 1
MON_LOG_PATH = /dm/monitor/log
MON_DW_IP = dm-primary-svc:52141,dm-standby-svc:52142
使用命令启动:
sql
bash
dmmonitor /dm/monitor/dmmonitor.ini
验证自动切换:
-
模拟主库宕机:
kubectl delete pod dm-primary-0 -
观察监视器输出,备库应在
INST_ERROR_TIME后自动切换为 PRIMARY -
旧主恢复后自动成为新备库
✅ 切换成功的关键:MAL 网络互通、OGUID 一致、守护进程配置无误。
6. SpringBoot3 连接配置(含 dm_svc.conf)
达梦数据守护集群对外服务地址可以通过 dm_svc.conf 配置服务名,实现自动读写分离和故障切换。
dm_svc.conf:
sql
TIME_ZONE=(480)
LANGUAGE=(cn)
DMSERVER=(dm://dm-primary-svc:5236?rwSeparate=true&rwPercent=70)
在 SpringBoot3 的 application.yml 中:
sql
spring:
datasource:
url: jdbc:dm://dm-primary-svc:5236?schema=DAMENG&compatibleMode=oracle
username: SYSDBA
password: Dameng@123
driver-class-name: dm.jdbc.driver.DmDriver
💡 提示: 连接串直接指向主库 Service,当发生切换,应用通过 dm_svc.conf 可重新解析主库地址。
7. 生产避坑清单
| 坑点 | 现象 | 解决方案 |
|---|---|---|
dmmal.ini 中主机名写错 |
MAL 链路无法建立,守护进程不断重启 | 使用 ping 测试 Pod 域名,确保 DNS 解析正确 |
| 主备实例名大小写不一致 | 归档失败,SQL 报错 | 达梦实例名大小写敏感,保持完全一致 |
PVC 存储类不支持 ReadWriteOnce |
备库节点漂移后无法挂载数据卷 | 使用共享存储或本地卷 ReadWriteOnce 确保绑定节点 |
| 容器资源 limit 不足 | 数据库在高峰时 OOMKilled | 建议内存 limit >= 4Gi,并设置 MEMORY_POOL、BUFFER 参数 |
忘记设置 INST_OGUID |
守护进程启动报 OGUID invalid |
主备都必须执行 SP_SET_OGUID |
🛑 致命错误: 一定要测试主库宕机场景,确保确认监视器能正常将备库提升为主,否则高可用形同虚设。
📢 专注 SpringBoot3 + 人大金仓 + 达梦信创实战,关注不迷路
这篇文章从镜像构建到 K8s 部署、再到 SpringBoot 连接,一套完整的达梦数据守护集群容器化落地模板全部给你了。你可以直接 fork 我的配置文件,稍作修改就上生产。
🔥 政务选金仓,金融选达梦;MySQL 迁移选金仓,Oracle 迁移选达梦。