热衷于分享各种干货知识,大家有想看或者想学的可以评论区留言,秉承着“开源知识来源于互联网,回归于互联网”的理念,分享一些日常工作中能用到或者比较重要的内容,希望大家能够喜欢,不足之处请大家多提宝贵地意见,我们一起提升,守住自己的饭碗。
关注公众号,技术道路不迷路

#!/usr/bin/env python3
"""
Oracle 19c RAC 一键静默安装脚本 (ASM 存储)
要求:
- 两台 CentOS 7.9 节点,root 密码相同
- 安装包已放在 /soft/ 目录下
- 共享磁盘已映射到两个节点(如 /dev/sdb, /dev/sdc ...)
- 本脚本需在节点1上以 root 运行
用法:
python3 install_rac19c_asm.py --参数...
"""
import argparse
import subprocess
import sys
import os
import time
import re
import logging
from pathlib import Path
# ===================== 日志配置 =====================
LOG_DIR = "/soft"
os.makedirs(LOG_DIR, exist_ok=True)
LOG_FILE = f"{LOG_DIR}/rac_asm_{time.strftime('%Y%m%d_%H%M%S')}.log"
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s [%(levelname)s] %(message)s',
handlers=[
logging.FileHandler(LOG_FILE),
logging.StreamHandler(sys.stdout)
]
)
logger = logging.getLogger(__name__)
# ===================== 工具函数 =====================
defrun_local(cmd, check=True, timeout=600, exit_on_fail=True):
"""执行本地命令,返回 CompletedProcess"""
logger.info(f"[LOCAL] {cmd}")
try:
res = subprocess.run(cmd, shell=True, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, text=True, timeout=timeout)
if res.stdout:
logger.info(res.stdout.strip())
if res.stderr:
logger.debug(res.stderr.strip())
if check and res.returncode != 0and exit_on_fail:
logger.error(f"命令失败 (rc={res.returncode}): {cmd}")
sys.exit(1)
return res
except subprocess.TimeoutExpired:
if exit_on_fail:
logger.error(f"命令超时: {cmd}")
sys.exit(1)
returnNone
defssh_exec(host, cmd, user='root', timeout=300, check=True):
"""通过 SSH 执行远程命令(需要免密)"""
ssh_cmd = f"ssh -o StrictHostKeyChecking=no -o ConnectTimeout=10 {user}@{host} '{cmd}'"
logger.info(f"[SSH:{host}] {cmd}")
try:
res = subprocess.run(ssh_cmd, shell=True, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, text=True, timeout=timeout)
if res.stdout:
logger.info(res.stdout.strip())
if res.stderr:
logger.debug(res.stderr.strip())
if check and res.returncode != 0:
logger.error(f"远程命令失败: {ssh_cmd}")
sys.exit(1)
return res
except subprocess.TimeoutExpired:
logger.error(f"SSH命令超时: {ssh_cmd}")
sys.exit(1)
defscp_put(local_path, remote_host, remote_path, user='root'):
"""复制文件到远程"""
cmd = f"scp -o StrictHostKeyChecking=no {local_path}{user}@{remote_host}:{remote_path}"
run_local(cmd)
defwrite_file(path, content):
withopen(path, 'w') as f:
f.write(content)
defappend_file(path, content):
withopen(path, 'a') as f:
f.write(content)
defsetup_ssh_key():
"""为 root 生成密钥(如果不存在)"""
key_file = "/root/.ssh/id_rsa"
ifnot os.path.exists(key_file):
run_local("ssh-keygen -t rsa -N '' -f /root/.ssh/id_rsa -q")
defensure_ssh_access(host):
"""确保能够免密连接到远程主机,如无法则提示手动配置"""
res = ssh_exec(host, "hostname", check=False)
if res.returncode != 0:
logger.error(f"无法免密 SSH 到 {host},请执行以下命令后重试:")
logger.error(f"ssh-copy-id root@{host}")
sys.exit(1)
logger.info(f"SSH 免密到 {host} 验证成功。")
# ===================== 参数解析 =====================
defparse_args():
parser = argparse.ArgumentParser(description="Oracle 19c RAC ASM 一键安装")
# 网络
parser.add_argument('--pub1', required=True, help='节点1 公共 IP')
parser.add_argument('--pub2', required=True, help='节点2 公共 IP')
parser.add_argument('--priv1', required=True, help='节点1 私有 IP')
parser.add_argument('--priv2', required=True, help='节点2 私有 IP')
parser.add_argument('--vip1', required=True, help='节点1 VIP')
parser.add_argument('--vip2', required=True, help='节点2 VIP')
parser.add_argument('--scan', required=True, help='SCAN IP (单个,将自动生成 3 个)')
parser.add_argument('--pub_if', required=True, help='公共网卡名称')
parser.add_argument('--priv_if', required=True, help='私有网卡名称')
parser.add_argument('--prefix', required=True, help='主机名前缀,如 rac')
# 密码
parser.add_argument('--root_pw', required=True, help='root 密码(用于初始配置用户密码)')
parser.add_argument('--ora_pw', required=True, help='Oracle 密码(grid/oracle 用户及 DB)')
# 数据库
parser.add_argument('--sid', required=True, help='Oracle SID')
parser.add_argument('--cdb', default='false', help='是否创建 CDB (true/false)')
parser.add_argument('--pdb', default='pdb1', help='PDB 名称')
parser.add_argument('--charset', default='ZHS16GBK', help='数据库字符集')
parser.add_argument('--ncharset', default='AL16UTF16', help='国家字符集')
# YUM
parser.add_argument('--yum', required=True, help='YUM 源 (/dev/cdrom 或 ISO 路径)')
# ASM 磁盘
parser.add_argument('--ocr_disks', required=True, help='OCR 磁盘,逗号分隔,如 /dev/sdb,/dev/sdc,/dev/sdd')
parser.add_argument('--data_disks', required=True, help='DATA 磁盘,逗号分隔,如 /dev/sde,/dev/sdf')
parser.add_argument('--ocr_red', default='EXTERNAL', help='OCR 冗余策略 (EXTERNAL/NORMAL/HIGH)')
parser.add_argument('--data_red', default='EXTERNAL', help='DATA 冗余策略')
return parser.parse_args()
# ===================== 安装步骤 =====================
defstep1_local_system_config(args):
"""节点1 基础配置"""
logger.info("步骤1: 配置本地节点系统")
node1 = f"{args.prefix}db1"
node2 = f"{args.prefix}db2"
scan_name = f"{args.prefix}db-scan"
# 主机名
run_local(f"hostnamectl set-hostname {node1}")
# /etc/hosts
hosts = f"""
{args.pub1}{node1}{node1}.local
{args.pub2}{node2}{node2}.local
{args.priv1}{node1}-priv
{args.priv2}{node2}-priv
{args.vip1}{node1}-vip {node1}-vip.local
{args.vip2}{node2}-vip {node2}-vip.local
{args.scan}{scan_name}{scan_name}.local
"""
append_file("/etc/hosts", hosts)
# 防火墙、SELinux
run_local("systemctl stop firewalld; systemctl disable firewalld")
run_local("sed -i 's/^SELINUX=.*/SELINUX=disabled/' /etc/selinux/config")
run_local("setenforce 0", check=False)
# 创建组和用户
groups = [
("oinstall", 1000), ("dba", 1001), ("oper", 1002),
("asmadmin", 1003), ("asmoper", 1004), ("asmdba", 1005)
]
for name, gid in groups:
run_local(f"groupadd -g {gid}{name}", check=False)
run_local("useradd -u 1000 -g oinstall -G dba,oper,asmdba oracle", check=False)
run_local("useradd -u 1001 -g oinstall -G dba,asmadmin,asmdba,asmoper grid", check=False)
run_local(f"echo '{args.ora_pw}' | passwd --stdin oracle")
run_local(f"echo '{args.ora_pw}' | passwd --stdin grid")
# 目录
for d in ["/u01/app/grid", "/u01/app/19.3.0/grid", "/u01/app/oracle",
"/u01/app/oracle/product/19.3.0/dbhome_1", "/u01/app/oraInventory", "/soft"]:
os.makedirs(d, exist_ok=True)
run_local("chown -R grid:oinstall /u01")
run_local("chown -R oracle:oinstall /u01/app/oracle")
run_local("chown -R oracle:oinstall /soft")
run_local("chmod -R 775 /u01 /soft")
# 内核参数
sysctl = """
fs.aio-max-nr = 1048576
fs.file-max = 6815744
kernel.sem = 250 32000 100 128
net.ipv4.ip_local_port_range = 9000 65500
net.core.rmem_default = 262144
net.core.rmem_max = 4194304
net.core.wmem_default = 262144
net.core.wmem_max = 1048576
kernel.shmall = 2097152
kernel.shmmax = 6871947673
kernel.shmmni = 4096
vm.nr_hugepages = 2800
"""
append_file("/etc/sysctl.conf", sysctl)
run_local("sysctl -p")
# 资源限制
limits = """
grid soft nproc 16384
grid hard nproc 16384
grid soft nofile 10240
grid hard nofile 65536
grid soft stack 10240
grid hard stack 32768
grid soft memlock unlimited
grid hard memlock unlimited
oracle soft nproc 16384
oracle hard nproc 16384
oracle soft nofile 10240
oracle hard nofile 65536
oracle soft stack 10240
oracle hard stack 32768
oracle soft memlock unlimited
oracle hard memlock unlimited
"""
append_file("/etc/security/limits.conf", limits)
append_file("/etc/pam.d/login", "session required pam_limits.so")
# 透明大页
run_local("echo never > /sys/kernel/mm/transparent_hugepage/enabled", check=False)
run_local("echo never > /sys/kernel/mm/transparent_hugepage/defrag", check=False)
# 兼容 RedHat 内核
run_local("test -f /sys/kernel/mm/redhat_transparent_hugepage/enabled && echo never > /sys/kernel/mm/redhat_transparent_hugepage/enabled", check=False)
run_local("test -f /sys/kernel/mm/redhat_transparent_hugepage/defrag && echo never > /sys/kernel/mm/redhat_transparent_hugepage/defrag", check=False)
# NOZEROCONF, RemoveIPC
append_file("/etc/sysconfig/network", "NOZEROCONF=yes")
run_local("sed -i 's/^#RemoveIPC=.*/RemoveIPC=no/' /etc/systemd/logind.conf")
run_local("systemctl daemon-reload; systemctl restart systemd-logind")
# 环境变量
oracle_env = f"""
export ORACLE_SID={args.sid}1
export ORACLE_BASE=/u01/app/oracle
export ORACLE_HOME=/u01/app/oracle/product/19.3.0/dbhome_1
export PATH=$ORACLE_HOME/bin:/usr/sbin:$PATH
export TZ=Asia/Shanghai
export NLS_DATE_FORMAT='yyyy-mm-dd HH24:MI:SS'
export NLS_LANG=AMERICAN_AMERICA.UTF8
umask 022
"""
append_file("/home/oracle/.bash_profile", oracle_env)
grid_env = f"""
export ORACLE_SID=+ASM1
export ORACLE_BASE=/u01/app/grid
export ORACLE_HOME=/u01/app/19.3.0/grid
export PATH=$ORACLE_HOME/bin:$PATH
export TZ=Asia/Shanghai
umask 022
"""
append_file("/home/grid/.bash_profile", grid_env)
defstep2_remote_system_config(args):
"""节点2 基础配置(通过远程脚本执行)"""
logger.info("步骤2: 配置远程节点系统")
node1 = f"{args.prefix}db1"
node2 = f"{args.prefix}db2"
scan_name = f"{args.prefix}db-scan"
script = f"""#!/bin/bash
set -e
hostnamectl set-hostname {node2}
cat >> /etc/hosts << 'EOF'
{args.pub1}{node1}{node1}.local
{args.pub2}{node2}{node2}.local
{args.priv1}{node1}-priv
{args.priv2}{node2}-priv
{args.vip1}{node1}-vip
{args.vip2}{node2}-vip
{args.scan}{scan_name}{scan_name}.local
EOF
systemctl stop firewalld; systemctl disable firewalld
sed -i 's/^SELINUX=.*/SELINUX=disabled/' /etc/selinux/config
setenforce 0 || true
# 组和用户
groupadd -g 1000 oinstall 2>/dev/null || true
groupadd -g 1001 dba 2>/dev/null || true
groupadd -g 1002 oper 2>/dev/null || true
groupadd -g 1003 asmadmin 2>/dev/null || true
groupadd -g 1004 asmoper 2>/dev/null || true
groupadd -g 1005 asmdba 2>/dev/null || true
useradd -u 1000 -g oinstall -G dba,oper,asmdba oracle 2>/dev/null || true
useradd -u 1001 -g oinstall -G dba,asmadmin,asmdba,asmoper grid 2>/dev/null || true
echo '{args.ora_pw}' | passwd --stdin oracle
echo '{args.ora_pw}' | passwd --stdin grid
mkdir -p /u01/app/grid /u01/app/19.3.0/grid /u01/app/oracle /u01/app/oracle/product/19.3.0/dbhome_1 /u01/app/oraInventory /soft
chown -R grid:oinstall /u01
chown -R oracle:oinstall /u01/app/oracle
chown -R oracle:oinstall /soft
chmod -R 775 /u01 /soft
# sysctl
cat >> /etc/sysctl.conf << 'SYSCTL'
fs.aio-max-nr = 1048576
fs.file-max = 6815744
kernel.sem = 250 32000 100 128
net.ipv4.ip_local_port_range = 9000 65500
net.core.rmem_default = 262144
net.core.rmem_max = 4194304
net.core.wmem_default = 262144
net.core.wmem_max = 1048576
kernel.shmall = 2097152
kernel.shmmax = 6871947673
kernel.shmmni = 4096
vm.nr_hugepages = 2800
SYSCTL
sysctl -p
# limits
cat >> /etc/security/limits.conf << 'LIMITS'
grid soft nproc 16384
grid hard nproc 16384
grid soft nofile 10240
grid hard nofile 65536
grid soft stack 10240
grid hard stack 32768
grid soft memlock unlimited
grid hard memlock unlimited
oracle soft nproc 16384
oracle hard nproc 16384
oracle soft nofile 10240
oracle hard nofile 65536
oracle soft stack 10240
oracle hard stack 32768
oracle soft memlock unlimited
oracle hard memlock unlimited
LIMITS
echo 'session required pam_limits.so' >> /etc/pam.d/login
# 透明大页
echo never > /sys/kernel/mm/transparent_hugepage/enabled || true
echo never > /sys/kernel/mm/transparent_hugepage/defrag || true
test -f /sys/kernel/mm/redhat_transparent_hugepage/enabled && echo never > /sys/kernel/mm/redhat_transparent_hugepage/enabled || true
test -f /sys/kernel/mm/redhat_transparent_hugepage/defrag && echo never > /sys/kernel/mm/redhat_transparent_hugepage/defrag || true
echo 'NOZEROCONF=yes' >> /etc/sysconfig/network
sed -i 's/^#RemoveIPC=.*/RemoveIPC=no/' /etc/systemd/logind.conf
systemctl daemon-reload; systemctl restart systemd-logind
# 环境变量
cat >> /home/oracle/.bash_profile << 'ORAEOF'
export ORACLE_SID={args.sid}2
export ORACLE_BASE=/u01/app/oracle
export ORACLE_HOME=/u01/app/oracle/product/19.3.0/dbhome_1
export PATH=$ORACLE_HOME/bin:/usr/sbin:$PATH
export TZ=Asia/Shanghai
umask 022
ORAEOF
cat >> /home/grid/.bash_profile << 'GRIDEOF'
export ORACLE_SID=+ASM2
export ORACLE_BASE=/u01/app/grid
export ORACLE_HOME=/u01/app/19.3.0/grid
export PATH=$ORACLE_HOME/bin:$PATH
export TZ=Asia/Shanghai
umask 022
GRIDEOF
"""
script_path = "/tmp/node2_config.sh"
write_file(script_path, script)
scp_put(script_path, node2, script_path)
ssh_exec(node2, f"bash {script_path}")
defstep3_install_deps(args):
"""配置 YUM 并安装依赖包(两个节点)"""
logger.info("步骤3: 安装依赖包")
node2 = f"{args.prefix}db2"
yum_path = args.yum
if yum_path == "/dev/cdrom":
mount_cmd = "mount /dev/cdrom /mnt"
else:
mount_cmd = f"mount -o loop {yum_path} /mnt"
# 本地
run_local(mount_cmd)
run_local("rm -rf /etc/yum.repos.d/*")
repo = """[local]
name=local
baseurl=file:///mnt
enabled=1
gpgcheck=0
"""
write_file("/etc/yum.repos.d/local.repo", repo)
run_local("yum clean all; yum makecache")
pkgs = "gcc compat-gcc-34 elfutils-libelf-devel compat-libstdc++-33 elfutils-libelf gcc-c++ glibc-headers libaio libaio-devel libgcc libstdc++ libstdc++-devel make ksh sysstat unixODBC compat-libcap1 libXp device-mapper-multipath libXi libXtst xorg-x11-utils unzip zip smartmontools net-tools lrzsz vim dstat libnsl policycoreutils-python bc tree nfs-utils expect psmisc"
run_local(f"yum install -y {pkgs}")
run_local("umount /mnt")
# 远程
script = f"""#!/bin/bash
{mount_cmd}
rm -rf /etc/yum.repos.d/*
cat > /etc/yum.repos.d/local.repo << 'EOF'
[local]
name=local
baseurl=file:///mnt
enabled=1
gpgcheck=0
EOF
yum clean all; yum makecache
yum install -y {pkgs}
umount /mnt
"""
script_path = "/tmp/node2_deps.sh"
write_file(script_path, script)
scp_put(script_path, node2, script_path)
ssh_exec(node2, f"bash {script_path}")
defstep4_ssh_keys(args):
"""配置 root/grid/oracle SSH 互信"""
logger.info("步骤4: 配置 SSH 互信")
node1 = f"{args.prefix}db1"
node2 = f"{args.prefix}db2"
# root 已处理过,这里再确认
setup_ssh_key()
# grid
run_local("su - grid -c 'ssh-keygen -t rsa -N \"\" -f ~/.ssh/id_rsa -q'")
run_local(f"su - grid -c 'ssh-copy-id -o StrictHostKeyChecking=no {node1}'")
run_local(f"su - grid -c 'ssh-copy-id -o StrictHostKeyChecking=no {node2}'")
# oracle
run_local("su - oracle -c 'ssh-keygen -t rsa -N \"\" -f ~/.ssh/id_rsa -q'")
run_local(f"su - oracle -c 'ssh-copy-id -o StrictHostKeyChecking=no {node1}'")
run_local(f"su - oracle -c 'ssh-copy-id -o StrictHostKeyChecking=no {node2}'")
defstep5_unzip_and_cvu(args):
"""解压安装包并安装 cvuqdisk"""
logger.info("步骤5: 解压安装包")
grid_zip = "/soft/LINUX.X64_193000_grid_home.zip"
db_zip = "/soft/LINUX.X64_193000_db_home.zip"
ifnot (os.path.exists(grid_zip) and os.path.exists(db_zip)):
logger.error("安装包缺失,请将 grid 和 db 的 zip 放在 /soft/")
sys.exit(1)
run_local("su - grid -c 'unzip -o /soft/LINUX.X64_193000_grid_home.zip -d /u01/app/19.3.0/grid/'")
run_local("su - oracle -c 'unzip -o /soft/LINUX.X64_193000_db_home.zip -d /u01/app/oracle/product/19.3.0/dbhome_1/'")
# cvuqdisk
cvu_rpm = "/u01/app/19.3.0/grid/cv/rpm/cvuqdisk-1.0.10-1.rpm"
run_local(f"rpm -ivh {cvu_rpm}")
node2 = f"{args.prefix}db2"
scp_put(cvu_rpm, node2, "/tmp/cvuqdisk.rpm")
ssh_exec(node2, "rpm -ivh /tmp/cvuqdisk.rpm")
defstep6_multipath_udev(args):
"""配置多路径和 UDEV 规则(两个节点)"""
logger.info("步骤6: 配置多路径和 UDEV")
node2 = f"{args.prefix}db2"
ocr_disks = args.ocr_disks.split(',')
data_disks = args.data_disks.split(',')
defget_wwid(disk):
res = run_local(f"/usr/lib/udev/scsi_id --whitelisted --replace-whitespace --device={disk}")
return res.stdout.strip()
# 生成 multipath.conf
conf = "multipaths {\n"
idx = 1
for d in ocr_disks:
wwid = get_wwid(d)
conf += f"\tmultipath {{\n\t\twwid {wwid}\n\t\talias ocr{idx}\n\t\tpath_grouping_policy failover\n\t}}\n"
idx += 1
idx = 1
for d in data_disks:
wwid = get_wwid(d)
conf += f"\tmultipath {{\n\t\twwid {wwid}\n\t\talias data{idx}\n\t\tpath_grouping_policy failover\n\t}}\n"
idx += 1
conf += "}\n"
write_file("/etc/multipath.conf", conf)
run_local("systemctl restart multipathd; systemctl enable multipathd")
# UDEV 规则
disks_list = run_local("ls /dev/mapper/ | egrep 'ocr|data'").stdout.strip().split()
rules = []
for disk in disks_list:
dm_uuid = run_local(f"udevadm info --query=all --name=/dev/mapper/{disk} | grep -i dm_uuid | awk -F= '{{print $2}}'").stdout.strip()
rules.append(f'KERNEL=="dm-*",ENV{{DM_UUID}}=="{dm_uuid}",SYMLINK+="oracleasm/disks/{disk}",OWNER="grid",GROUP="asmadmin",MODE="0660"')
write_file("/etc/udev/rules.d/99-oracle-asmdevices.rules", "\n".join(rules))
run_local("udevadm control --reload-rules; udevadm trigger; sleep 3")
run_local("ls -l /dev/oracleasm/disks/")
# 同步到节点2
scp_put("/etc/multipath.conf", node2, "/etc/multipath.conf")
scp_put("/etc/udev/rules.d/99-oracle-asmdevices.rules", node2, "/etc/udev/rules.d/")
ssh_exec(node2, "systemctl restart multipathd; systemctl enable multipathd")
ssh_exec(node2, "udevadm control --reload-rules; udevadm trigger; sleep 3")
ssh_exec(node2, "ls -l /dev/oracleasm/disks/")
defstep7_init_disks(args):
"""初始化 ASM 磁盘"""
logger.info("步骤7: 初始化 ASM 磁盘(写入 0)")
disks = run_local("ls /dev/oracleasm/disks/*").stdout.strip().split()
for d in disks:
run_local(f"dd if=/dev/zero of={d} bs=1024k count=1")
defstep8_install_grid(args):
"""安装 Grid Infrastructure"""
logger.info("步骤8: 安装 Grid Infrastructure")
node1 = f"{args.prefix}db1"
node2 = f"{args.prefix}db2"
scan_name = f"{args.prefix}db-scan"
pub_net = args.pub_if
priv_net = args.priv_if
pub_sub = '.'.join(args.pub1.split('.')[:3]) + '.0'
priv_sub = '.'.join(args.priv1.split('.')[:3]) + '.0'
ocr_disk_list = ",".join([f"/dev/oracleasm/disks/ocr{i}"for i inrange(1, len(args.ocr_disks.split(','))+1)])
rsp = f"""oracle.install.responseFileVersion=/oracle/install/rspfmt_crsinstall_response_schema_v19.0.0
INVENTORY_LOCATION=/u01/app/oraInventory
SELECTED_LANGUAGES=en,en_GB
oracle.install.option=CRS_CONFIG
ORACLE_BASE=/u01/app/grid
oracle.install.asm.OSDBA=asmdba
oracle.install.asm.OSASM=asmadmin
oracle.install.asm.OSOPER=asmoper
oracle.install.crs.config.scanType=LOCAL_SCAN
oracle.install.crs.config.gpnp.scanName={scan_name}
oracle.install.crs.config.gpnp.scanPort=1521
oracle.install.crs.config.clusterName={args.prefix}-cluster
oracle.install.crs.config.gpnp.configureGNS=false
oracle.install.crs.config.autoConfigureClusterNodeVIP=false
oracle.install.crs.config.clusterNodes={node1}:{node1}-vip,{node2}:{node2}-vip
oracle.install.crs.config.networkInterfaceList={pub_net}:{pub_sub}:1,{priv_net}:{priv_sub}:5
oracle.install.crs.config.storageOption=ASM_STORAGE
oracle.install.crs.config.useIPMI=false
oracle.install.asm.SYSASMPassword={args.ora_pw}
oracle.install.asm.diskGroup.name=OCR_VOT
oracle.install.asm.diskGroup.redundancy={args.ocr_red}
oracle.install.asm.diskGroup.AUSize=4
oracle.install.asm.diskGroup.disks={ocr_disk_list}
oracle.install.asm.diskGroup.diskDiscoveryString=/dev/oracleasm/disks/*
oracle.install.asm.monitorPassword={args.ora_pw}
oracle.install.asm.configureAFD=false
oracle.install.crs.configureRHPS=false
"""
write_file("/soft/grid.rsp", rsp)
run_local("chown grid:oinstall /soft/grid.rsp; chmod 660 /soft/grid.rsp")
# 同步时间(可选)
run_local(f"ssh {node2} 'date -s \"$(date +\"%Y%m%d %H:%M:%S\")\"'", check=False)
# 安装
run_local("su - grid -c '/u01/app/19.3.0/grid/gridSetup.sh -silent -ignorePrereqFailure -responseFile /soft/grid.rsp'")
# root 脚本
run_local("/u01/app/oraInventory/orainstRoot.sh")
ssh_exec(node2, "/u01/app/oraInventory/orainstRoot.sh")
# root.sh 在节点1执行并等待(后台可能会启动 ohasd)
run_local("/u01/app/19.3.0/grid/root.sh")
# 节点2 的 root.sh 稍微等待
time.sleep(5)
ssh_exec(node2, "/u01/app/19.3.0/grid/root.sh")
# 执行 config tools
run_local("su - grid -c '/u01/app/19.3.0/grid/gridSetup.sh -executeConfigTools -silent -responseFile /soft/grid.rsp'")
run_local("su - grid -c 'crsctl stat res -t'")
defstep9_create_data_diskgroup(args):
"""创建 DATA 磁盘组"""
logger.info("步骤9: 创建 DATA 磁盘组")
data_disks = ",".join([f"/dev/oracleasm/disks/data{i}"for i inrange(1, len(args.data_disks.split(','))+1)])
cmd = f"su - grid -c 'asmca -silent -createDiskGroup -diskGroupName DATA -diskList {data_disks} -redundancy {args.data_red} -au_size 4 -compatible.asm 19.0 -compatible.rdbms 19.0'"
run_local(cmd)
defstep10_install_db_software(args):
"""安装 Oracle 数据库软件"""
logger.info("步骤10: 安装 DB 软件")
rsp = f"""oracle.install.responseFileVersion=/oracle/install/rspfmt_dbinstall_response_schema_v19.0.0
oracle.install.option=INSTALL_DB_SWONLY
UNIX_GROUP_NAME=oinstall
INVENTORY_LOCATION=/u01/app/oraInventory
SELECTED_LANGUAGES=en,en_GB
ORACLE_HOME=/u01/app/oracle/product/19.3.0/dbhome_1
ORACLE_BASE=/u01/app/oracle
oracle.install.db.InstallEdition=EE
oracle.install.db.OSDBA_GROUP=dba
oracle.install.db.OSOPER_GROUP=oper
oracle.install.db.OSBACKUPDBA_GROUP=dba
oracle.install.db.OSDGDBA_GROUP=dba
oracle.install.db.OSKMDBA_GROUP=dba
oracle.install.db.OSRACDBA_GROUP=dba
oracle.install.db.CLUSTER_NODES={args.prefix}db1,{args.prefix}db2
oracle.install.db.isRACOneInstall=false
SECURITY_UPDATES_VIA_MYORACLESUPPORT=false
"""
write_file("/soft/db_install.rsp", rsp)
run_local("chown oracle:oinstall /soft/db_install.rsp; chmod 660 /soft/db_install.rsp")
run_local("su - oracle -c '/u01/app/oracle/product/19.3.0/dbhome_1/runInstaller -silent -ignorePrereqFailure -responseFile /soft/db_install.rsp'")
run_local("/u01/app/oracle/product/19.3.0/dbhome_1/root.sh")
ssh_exec(f"{args.prefix}db2", "/u01/app/oracle/product/19.3.0/dbhome_1/root.sh")
defstep11_create_database(args):
"""DBCA 创建数据库"""
logger.info("步骤11: 创建数据库")
cdb_flag = args.cdb.lower()
pdb_block = ""
if cdb_flag == "true":
pdb_block = f"""createAsContainerDatabase=true
numberOfPDBs=1
pdbName={args.pdb}
pdbAdminPassword={args.ora_pw}
"""
else:
pdb_block = "createAsContainerDatabase=false"
rsp = f"""responseFileVersion=/oracle/assistants/rspfmt_dbca_response_schema_v12.2.0
gdbName={args.sid}
sid={args.sid}
databaseConfigType=RAC
{pdb_block}
nodelist={args.prefix}db1,{args.prefix}db2
templateName=/u01/app/oracle/product/19.3.0/dbhome_1/assistants/dbca/templates/General_Purpose.dbc
sysPassword={args.ora_pw}
systemPassword={args.ora_pw}
datafileDestination=+DATA
recoveryAreaDestination=+DATA
storageType=ASM
diskGroupName=+DATA
asmsnmpPassword={args.ora_pw}
recoveryGroupName=+DATA
characterSet={args.charset}
nationalCharacterSet={args.ncharset}
memoryPercentage=70
automaticMemoryManagement=false
databaseType=MULTIPURPOSE
"""
write_file("/soft/dbca.rsp", rsp)
run_local("chown oracle:oinstall /soft/dbca.rsp; chmod 660 /soft/dbca.rsp")
run_local("su - oracle -c '/u01/app/oracle/product/19.3.0/dbhome_1/bin/dbca -silent -ignorePrereqFailure -createDatabase -responseFile /soft/dbca.rsp'")
logger.info(f"数据库 {args.sid} 创建完成。")
# ===================== 主流程 =====================
defmain():
if os.geteuid() != 0:
logger.error("请使用 root 用户运行")
sys.exit(1)
args = parse_args()
node2 = f"{args.prefix}db2"
logger.info("====== Oracle 19c RAC (ASM) 一键安装开始 ======")
# 0. 检查 SSH 免密
setup_ssh_key()
ensure_ssh_access(node2)
# 1. 系统配置
step1_local_system_config(args)
step2_remote_system_config(args)
# 2. 依赖包
step3_install_deps(args)
# 3. SSH 互信
step4_ssh_keys(args)
# 4. 解压安装包
step5_unzip_and_cvu(args)
# 5. 存储配置
step6_multipath_udev(args)
step7_init_disks(args)
# 6. Grid 安装
step8_install_grid(args)
# 7. 创建 DATA 磁盘组
step9_create_data_diskgroup(args)
# 8. 数据库软件
step10_install_db_software(args)
# 9. DBCA 建库
step11_create_database(args)
logger.info("====== Oracle 19c RAC 安装成功!======")
run_local("su - grid -c 'crsctl stat res -t'")
if __name__ == "__main__":
main()使用方法
1. 将脚本保存为 install_rac_asm.py,赋予执行权限。2. 在 rac1 上执行前,确保已配置 root SSH 免密到 rac2: ssh-keygen -t rsa -N "" -f ~/.ssh/id_rsa
ssh-copy-id root@<rac2_ip>3. 准备安装介质: • LINUX.X64_193000_grid_home.zip和LINUX.X64_193000_db_home.zip放到/soft/。4. 运行命令(示例): python3 install_rac_asm.py \
--pub1=192.168.5.1 --pub2=192.168.5.2 \
--priv1=192.168.6.1 --priv2=192.168.6.2 \
--vip1=192.168.5.3 --vip2=192.168.5.4 \
--scan=192.168.5.5 \
--pub_if=eth0 --priv_if=eth1 \
--prefix=rac \
--root_pw=YourRootPass \
--ora_pw=Oracle123 \
--sid=orcl \
--cdb=false --charset=ZHS16GBK --ncharset=AL16UTF16 \
--yum=/dev/cdrom \
--ocr_disks=/dev/sdb,/dev/sdc,/dev/sdd \
--data_disks=/dev/sde,/dev/sdf \
--ocr_red=EXTERNAL --data_red=EXTERNAL
脚本特性
• 完全使用 ASM,自动配置 multipath、UDEV、ASM 磁盘组。 • 无需 expect/sshpass,依赖 SSH 密钥。 • 所有步骤完整:从系统调优到 DBCA 建库。 • 日志清晰,便于排错。
该脚本由Ai生成,使用前请自测,未进行测试。
文中的概念来源于互联网,如有侵权,请联系我删除。
欢迎关注公众号:小周的数据库进阶之路,一起交流AI、数据库、中间件和云计算等技术。如果觉得读完本文有收获,可以转发给其他朋友,大家一起学习进步!感兴趣的朋友可以加我微信,拉您进群与业界的大佬们一起交流学习。
夜雨聆风