Oracle RAC 21.3 双节点集群 Docker Desktop 部署指南
本文提供一份在 Windows + Docker Desktop(WSL2 后端)上部署 Oracle RAC 21.3 的完整可执行步骤:先部署单节点集群(racnode1),再实测扩展第二个节点(racnode2),最终得到真实可用的双节点 RAC 集群(Grid Infrastructure 21.3 + 数据库 ORCLCDB,ORCLCDB1/ORCLCDB2 双实例,GV$ 视图、Cache Fusion、DLM 全部可用)。
一、环境要求
| 项 | 要求 |
|---|---|
| 操作系统 | Windows 10/11 桌面版 |
| 容器引擎 | Docker Desktop(WSL2 后端) |
| 物理内存 | 建议 32GB(单节点阶段容器内可见 15G;双节点阶段建议将 WSL 内存调到 24GB) |
| RAC 镜像 | registry.cn-hangzhou.aliyuncs.com/hd2020/ka:rac21.3.0(阿里云镜像仓库) |
| 部署形态 | 单节点 RAC(racnode1)起步 → 扩展为双节点集群(racnode1 + racnode2) |
二、准备 ASM 磁盘(3 × 10GB)
RAC 的 OCR、Voting Disk 与数据库文件都存放在 ASM 磁盘组。先准备 3 个 10GB 的磁盘镜像文件(以D:\RAC\oradata\为例):
D:\RAC\oradata\asm_disk01.img D:\RAC\oradata\asm_disk02.img D:\RAC\oradata\asm_disk03.img在宿主机的docker-desktopWSL distro 中将镜像文件绑定为 loop 设备(容器内无法执行losetup):
wsl -d docker-desktop -u root -- sh -c "losetup /dev/loop2 /mnt/host/d/RAC/oradata/asm_disk01.img" wsl -d docker-desktop -u root -- sh -c "losetup /dev/loop3 /mnt/host/d/RAC/oradata/asm_disk02.img" wsl -d docker-desktop -u root -- sh -c "losetup /dev/loop4 /mnt/host/d/RAC/oradata/asm_disk03.img"绑定完成后容器内即可看到/dev/loop2、/dev/loop3、/dev/loop4三个块设备。该绑定在宿主机侧持久生效,容器重启、重建都不受影响。
三、创建 Docker 网络
RAC 需要两套网络:公共网络(PUBLIC/SCAN/VIP)与私有互连网络(PRIVATE,节点间 Cache Fusion 通信):
docker network create rac_pub1_nw --subnet 172.16.1.0/24 docker network create rac_priv1_nw --subnet 192.168.17.0/24四、启动容器(完整 docker run)
docker run -d --name racnode1 --hostname racnode1 --privileged --shm-size=4g \ --network rac_pub1_nw --ip 172.16.1.100 \ -e OP_TYPE=INSTALL \ -e ASM_DISCOVERY_DIR=/dev \ -e ASM_DEVICE_LIST=/dev/loop2,/dev/loop3,/dev/loop4 \ -e PUBLIC_IP=172.16.1.100 \ -e PRIV_IP=192.168.17.100 \ -e PRIV_HOSTNAME=racnode1-priv \ -e NODE_VIP=172.16.1.130 \ -e VIP_HOSTNAME=racnode1-vip \ -e SCAN_IP=172.16.1.230 \ -e SCAN_NAME=racnodec1-scan \ -e DOMAIN=example.com \ -v "D:\RAC\oradata\asm_disk01.img:/oradata/asm_disk01.img" \ -v "D:\RAC\oradata\asm_disk02.img:/oradata/asm_disk02.img" \ -v "D:\RAC\oradata\asm_disk03.img:/oradata/asm_disk03.img" \ -v "D:\RAC\custom_entrypoint.sh:/custom_entrypoint.sh" \ --entrypoint /custom_entrypoint.sh \ registry.cn-hangzhou.aliyuncs.com/hd2020/ka:rac21.3.0 # 追加私有网络第二网卡 docker network connect rac_priv1_nw racnode1 --ip 192.168.17.100关键参数说明
| 参数 | 值 | 说明 |
|---|---|---|
--hostname | racnode1 | 必须显式指定节点名,否则集群配置节点名错乱 |
--privileged | - | RAC 需要操作块设备、挂载等系统能力 |
--shm-size | 4g | Oracle 需要较大共享内存(默认 64MB 不够) |
-e PRIV_HOSTNAME | racnode1-priv | 必须通过-e传入(镜像启动程序会重建配置文件,手动改文件无效) |
-e PUBLIC_IP | 172.16.1.100 | 容器 eth0 |
-e PRIV_IP | 192.168.17.100 | 容器 eth1 私有互连 |
-e NODE_VIP | 172.16.1.130 | 节点虚拟 IP(racnode1-vip) |
-e SCAN_IP | 172.16.1.230 | SCAN IP(racnodec1-scan,单 IP) |
-e ASM_DEVICE_LIST | /dev/loop2,/dev/loop3,/dev/loop4 | ASM 磁盘设备 |
-e DOMAIN | example.com | 域名 |
注意:本镜像的内核环境(WSL2)不支持 CPU CFS 带宽控制,
不要加--cpus
参数
,否则容器无法启动。
自定义 entrypoint(可选)
D:\RAC\custom_entrypoint.sh内容示例(loop 设备由宿主侧绑定,容器内只需启动镜像自带的安装程序):
#!/bin/bash # loop 设备已在宿主 WSL 侧绑定,这里无需 losetup chown grid:asmadmin /dev/loop2 /dev/loop3 /dev/loop4 2>/dev/null || true chmod 660 /dev/loop2 /dev/loop3 /dev/loop4 2>/dev/null || true exec /usr/sbin/oracleinit五、等待自动安装(约 1 小时)
容器启动后镜像自带的configGrid.sh会自动执行完整安装,无需人工干预:
Pre-Grid Setup(系统准备) → 生成 OS 随机密码 → 网络检查(eth0 public / eth1 private) → SSH 互信设置(grid / oracle 用户) → CVU 预检查 → gridSetup.sh(Grid 软件配置) → root.sh → rootcrs.pl(19 步,配置 CRS 集群) → 集群状态检查 → DBCA 创建 RAC 数据库 ORCLCDB → ORACLE RAC DATABASE IS READY TO USE!观察安装进度:
docker logs -f racnode1成功标志—— 容器日志出现:
#################################### ORACLE RAC DATABASE IS READY TO USE! ####################################以及 rootcrs 日志中的:
CLSRSC-325: Configure Oracle Grid Infrastructure for a Cluster ... succeeded DBCA_PROGRESS : 100% Database creation complete. Global Database Name:ORCLCDB安装中段可能出现
PROC-26 Insufficient quorum to open OCR devices
的告警,这是 OCR 初始化过程中的正常中间状态,安装程序会自动继续,最终 OCR 会落在+DATA
磁盘组并通过完整性检查,
无需干预
。
六、验证部署
6.1 CRS 集群栈
docker exec racnode1 bash -c "export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/u01/app/21.3.0/grid/bin; crsctl check crs" CRS-4638: Oracle High Availability Services is online CRS-4537: Cluster Ready Services is online CRS-4529: Cluster Synchronization Services is online CRS-4533: Event Manager is online6.2 OCR(集群注册表)
docker exec racnode1 bash -c "export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/u01/app/21.3.0/grid/bin; ocrcheck" Status of Oracle Cluster Registry is as follows : Version : 4 Total space (kbytes) : 901284 Device/File Name : +DATA Device/File integrity check succeeded6.3 RAC 数据库(GV$ 视图)
docker exec -u oracle racnode1 bash -c \ "export ORACLE_HOME=/u01/app/oracle/product/21.3.0/dbhome_1; export ORACLE_SID=ORCLCDB1; \ sqlplus -s / as sysdba <<'EOF' select instance_name, status, host_name from v$instance; select name, open_mode from v$database; select inst_id, instance_name, status, host_name from gv$instance; EOF" INSTANCE_NAME STATUS HOST_NAME ORCLCDB1 OPEN racnode1 NAME OPEN_MODE ORCLCDB READ WRITE INST_ID INSTANCE_NAME STATUS HOST_NAME 1 ORCLCDB1 OPEN racnode1GV$ 视图可查 = 集群数据库模式确认(单节点 RAC,inst_id=1)。
6.4 进程与监听器
# 数据库实例进程 ora_pmon_ORCLCDB1 # 监听器(数据库 + SCAN + ASM) tnslsnr LISTENER / LISTENER_SCAN1 / ASMNET1LSNR_ASM七、连接信息
| 项 | 值 |
|---|---|
| 数据库名 | ORCLCDB |
| 实例名 | ORCLCDB1(SID) |
| 集群节点 | racnode1 |
| ASM 实例 | +ASM1 |
| ASM 磁盘组 | DATA(3 × 10GB) |
| 管理员登录 | docker exec -u oracle racnode1 bash -c "export ORACLE_HOME=/u01/app/oracle/product/21.3.0/dbhome_1; export ORACLE_SID=ORCLCDB1; sqlplus / as sysdba" |
| 监听端口 | 1521(LISTENER)/ 1521(SCAN) |
八、扩展第二节点 racnode2(双节点集群实战)
单节点 RAC 验证通过后,按下述步骤扩展第二个节点,形成真正意义上的双节点 RAC 集群(Cache Fusion / DLM 双实例运行)。以下每一步都在 Docker Desktop + WSL2 环境实测成功。
8.1 前提条件
| 项 | 要求 |
|---|---|
| 宿主内存 | 建议 ≥ 32GB(双节点各 4-8GB 实际占用,另加监控栈) |
| 共享 ASM 磁盘 | 沿用单节点的 loop2/3/4(racnode2 与 racnode1 共享同一组 ASM 磁盘,这是 RAC 的基本要求) |
| 网络 | rac_pub1_nw/rac_priv1_nw已创建,racnode2 接入同一网段 |
| 内存调优(可选) | 修改C:\Users\<user>\.wslconfig为memory=24GB、processors=6,重启 Docker Desktop 生效 |
8.2 创建 racnode2 容器(ADDNODE 模式)
镜像入口支持OP_TYPE=ADDNODE,容器启动后自动执行AddNode.sh,把新节点加入现有集群:
docker run -d --name racnode2 --hostname racnode2 --privileged --shm-size=4g \ --network rac_pub1_nw --ip 172.16.1.101 \ -e OP_TYPE=ADDNODE \ -e PUBLIC_HOSTNAME=racnode2 \ -e PUBLIC_IP=172.16.1.101 \ -e PRIV_HOSTNAME=racnode2-priv \ -e PRIV_IP=192.168.17.101 \ -e NODE_VIP=172.16.1.131 \ -e VIP_HOSTNAME=racnode2-vip \ -e SCAN_NAME=racnodec1-scan \ -e SCAN_IP=172.16.1.230 \ -e DOMAIN=example.com \ -e EXISTING_CLS_NODES=racnode1 \ -e ASM_DEVICE_LIST=/dev/loop2,/dev/loop3,/dev/loop4 \ -e ASM_DISCOVERY_DIR=/dev \ -v "D:\RAC\custom_entrypoint.sh:/custom_entrypoint.sh" \ -v "D:\RAC\oradata\asm_disk01.img:/oradata/asm_disk01.img" \ -v "D:\RAC\oradata\asm_disk02.img:/oradata/asm_disk02.img" \ -v "D:\RAC\oradata\asm_disk03.img:/oradata/asm_disk03.img" \ --entrypoint /custom_entrypoint.sh \ registry.cn-hangzhou.aliyuncs.com/hd2020/ka:rac21.3.0 # 追加私有网络第二网卡(eth1) docker network connect --ip 192.168.17.101 rac_priv1_nw racnode2与 racnode1 的关键差异:
| 参数 | 值 | 说明 |
|---|---|---|
OP_TYPE | ADDNODE | 以 “加入现有集群” 模式运行(racnode1 是INSTALL) |
EXISTING_CLS_NODES | racnode1 | 告诉 AddNode 流程现有节点是谁 |
ASM_DEVICE_LIST | /dev/loop2,/dev/loop3,/dev/loop4 | 与 racnode1共享同一组ASM 磁盘 |
| 新 IP 规划 | PUBLIC 172.16.1.101 / PRIV 192.168.17.101 / VIP 172.16.1.131 | 每节点独立 |
8.3 重建 SSH 互信(必做,镜像出厂密钥不匹配)
ADDNODE 流程第一步是 SSH 互信(grid /oracle 双用户、双向)。实测镜像出厂公钥不匹配,setupSSH会报SSH check failed for the grid@racnode1 ... permission denied。需要手动重建authorized_keys:
# 1. 提取双方公钥到宿主机临时目录 docker cp racnode1:/home/grid/.ssh/id_rsa.pub /tmp/n1.pub docker cp racnode2:/home/grid/.ssh/id_rsa.pub /tmp/n2.pub docker cp racnode1:/home/oracle/.ssh/id_rsa.pub /tmp/o1.pub docker cp racnode2:/home/oracle/.ssh/id_rsa.pub /tmp/o2.pub # 2. 拷入对方容器 docker cp /tmp/n2.pub racnode1:/tmp/n2.pub docker cp /tmp/n1.pub racnode2:/tmp/n1.pub docker cp /tmp/o2.pub racnode1:/tmp/o2.pub docker cp /tmp/o1.pub racnode2:/tmp/o1.pub # 3. 重建 grid 用户互信(docker exec 默认用户就是 grid,可直接写) docker exec racnode1 bash -c 'cat /tmp/n2.pub /home/grid/.ssh/id_rsa.pub > /home/grid/.ssh/authorized_keys; chown grid:oinstall /home/grid/.ssh/authorized_keys; chmod 600 /home/grid/.ssh/authorized_keys' docker exec racnode2 bash -c 'cat /tmp/n1.pub /home/grid/.ssh/id_rsa.pub > /home/grid/.ssh/authorized_keys; chown grid:oinstall /home/grid/.ssh/authorized_keys; chmod 600 /home/grid/.ssh/authorized_keys' # 4. 重建 oracle 用户互信(必须 -u root,否则 700 权限目录进不去) docker exec -u root racnode1 bash -c 'cat /tmp/o2.pub /home/oracle/.ssh/id_rsa.pub > /home/oracle/.ssh/authorized_keys; chown oracle:oinstall /home/oracle/.ssh/authorized_keys; chmod 600 /home/oracle/.ssh/authorized_keys' docker exec -u root racnode2 bash -c 'cat /tmp/o1.pub /home/oracle/.ssh/id_rsa.pub > /home/oracle/.ssh/authorized_keys; chown oracle:oinstall /home/oracle/.ssh/authorized_keys; chmod 600 /home/oracle/.ssh/authorized_keys' # 5. 验证双向互信(grid / oracle 都要,全部输出 OK) docker exec racnode2 bash -c 'ssh -o BatchMode=yes grid@racnode1 echo OK' docker exec racnode1 bash -c 'ssh -o BatchMode=yes grid@racnode2 echo OK' docker exec -u oracle racnode2 bash -c 'ssh -o BatchMode=yes oracle@racnode1 echo OK' docker exec -u oracle racnode1 bash -c 'ssh -o BatchMode=yes oracle@racnode2 echo OK'全部 OK 后重启 racnode2,重新执行 ADDNODE:
docker restart racnode2日志观察点(docker logs -f racnode2):
SSH check fine for the racnode1 / racnode2 # 互信通过 Running GridSetup.sh on racnode1 ... # Grid 节点添加 Node Addition performed # Grid addNode 完成 Running root.sh on node racnode2 # root.sh 执行8.4 三个必踩的坑及修复
坑 1:共享 loop 设备属主被重置 → racnode1 的 ASM 掉盘 → CRSD PANIC
docker restart racnode2(以及容器重建)会把共享的/dev/loop2-4设备节点重建为属主root:disk。racnode1 的 ASM 实例(grid 用户)读不到磁盘 → DATA 磁盘组卸载 → OCR 打不开 → CRSD 崩溃退出(CRSD00111 ... PROC-26)。
修复(每次重启 racnode2 后立即执行):
# 恢复共享设备属主(在 racnode1 内) docker exec -u root racnode1 chown grid:asmadmin /dev/loop2 /dev/loop3 /dev/loop4 docker exec -u root racnode1 chmod 660 /dev/loop2 /dev/loop3 /dev/loop4 # 重挂 DATA 磁盘组 docker exec -u grid racnode1 bash -lc 'export ORACLE_HOME=/u01/app/21.3.0/grid; export ORACLE_SID=+ASM1; sqlplus -s / as sysasm <<EOF alter diskgroup all mount; select name, state from v$asm_diskgroup_stat; EOF' # 若 CRSD 已崩溃则重启它 docker exec -u root racnode1 /u01/app/21.3.0/grid/bin/crsctl start crsd docker exec -u grid racnode1 /u01/app/21.3.0/grid/bin/crsctl check crs # 应全 online坑 2:racnode2 重启后接口顺序颠倒(eth0 变成 private)
Docker Desktop 重启容器后网络接口可能重排,出现 eth0=private、eth1=public。GPNPD 报CRS-42216 No interfaces are configured ... available interface definitions are [eth0...192.168.17.0][eth1...172.16.1.0]并反复崩溃重启。
修复:disconnect 两个网络,按「先 public 后 private」重连,再重启容器:
docker network disconnect rac_pub1_nw racnode2 docker network disconnect rac_priv1_nw racnode2 docker network connect --ip 172.16.1.101 rac_pub1_nw racnode2 # 先接 public docker network connect --ip 192.168.17.101 rac_priv1_nw racnode2 # 再接 private docker restart racnode2验证接口顺序(eth0 必须 = public IP):
docker exec racnode2 ip -4 addr show # 期望: # 2: eth0 ... inet 172.16.1.101/24 # 3: eth1 ... inet 192.168.17.101/24坑 3:racnode1 的 CRS 在 addNode 期间短暂不可用
AddNode /root.sh 会触发 CRS 滚动重启,期间crsctl check crs可能报通信失败(CRS-4535 等),属正常窗口期,等 1-2 分钟自动恢复,重新crsctl check crs全 online 即可继续。
8.5 补齐 ADDNODE 中断的收尾步骤
若 ADDNODE 日志停在CRSD Check failed!,但 racnode2 的/u01/app/21.3.0/grid/bin/crsctl已存在(Grid 已装好、root.sh 已跑),说明只是后续步骤被中断,手动补齐即可:
# 1. ASM 扩展到全部节点(拉起 +ASM2) docker exec -u grid racnode1 /u01/app/21.3.0/grid/bin/srvctl modify asm -count ALL # 2. 补齐 racnode2 的 VIP(nodeapps) docker exec -u root racnode1 /u01/app/21.3.0/grid/bin/srvctl add nodeapps -n racnode2 -A 172.16.1.131/255.255.255.0/eth0 docker exec -u grid racnode2 /u01/app/21.3.0/grid/bin/srvctl start nodeapps -n racnode2 # 3. 启动 racnode2 本地监听 docker exec -u grid racnode2 /u01/app/21.3.0/grid/bin/srvctl start listener -n racnode2 # 4. 数据库实例扩展(创建 ORCLCDB2) docker exec -u oracle racnode1 bash -lc 'export ORACLE_HOME=/u01/app/oracle/product/21.3.0/dbhome_1; export PATH=$ORACLE_HOME/bin:$PATH; dbca -addInstance -silent -nodeName racnode2 -gdbName ORCLCDB'dbca 输出Instance "ORCLCDB2" added successfully on node "racnode2"即成功。
8.6 验证双节点集群
# 集群节点 docker exec -u grid racnode1 /u01/app/21.3.0/grid/bin/olsnodes -n # racnode1 1 # racnode2 2 # 双实例数据库(GV$ 视图) docker exec -u oracle racnode1 bash -lc 'export ORACLE_HOME=/u01/app/oracle/product/21.3.0/dbhome_1; export ORACLE_SID=ORCLCDB1; sqlplus -s / as sysdba <<EOF select inst_id, instance_name, status from gv$instance order by 1; EOF' # INST_ID INSTANCE_NAME STATUS # 1 ORCLCDB1 OPEN # 2 ORCLCDB2 OPEN # 集群资源全景(orclcdb.db / ora.DATA.dg / ora.asm 应双节点 ONLINE) docker exec -u grid racnode1 /u01/app/21.3.0/grid/bin/crsctl stat res -t8.7 双节点连接与监控
| 项 | 值 |
|---|---|
| 集群节点 | racnode1 / racnode2 |
| 实例 | ORCLCDB1(racnode1)/ ORCLCDB2(racnode2) |
| SCAN 连接 | 172.16.1.230:1521/ORCLCDB(自动负载均衡到双实例) |
| 监听 | 各节点 1521 + SCAN Listener |
注意:扩容后节点监听改绑定 VIP,原先直连节点公共 IP(如
172.16.1.100:1521
)的方式会失效。外部连接统一走
SCAN IP
。监控程序(Prometheus exporter /python-oracledb)把连接串改为 SCAN 地址后,即可自动看到双实例(GV$ 指标带 inst_id 标签,Cache Fusion / DLM 指标随之出现)。
部署完成后即可连接数据库进行业务验证。如对本文档有任何疑问,欢迎评论区交流~