内网服务器装Oracle,我把踩过的坑都写在里面了
刚接手一批内网生产服务器的时候,我差点被"离线安装Oracle"这件事整崩溃。网上的教程九成都是在线安装——yum装依赖、wget拉安装包、联网跑root脚本,看着很顺滑,但搁在不通外网的机房环境里,这些操作全部作废。你只能靠自己手里那几张ISO、一堆rpm包,以及最原始的命令行工具,把Oracle数据库从零到一地装起来,还要保证监听能起、实例能建、应用能连。
这篇博文就是把我这几次离线安装Oracle的完整思路、操作步骤和踩过的坑整理出来。无论你是要装单机版做测试,还是给生产环境搭一套内网数据库,这套流程都可以直接参考。我会重点讲离线场景下最麻烦的依赖收集、静默安装参数、监听故障这几个环节,你照着走基本能顺利落地。
1. 动手前必须想明白的三件事
1.1 你的离线环境到底"离线"到什么程度
很多人在网上提问"离线怎么装Oracle",但"离线"的标准其实不太一样。我遇到过三种情况:
第一种,服务器本身没有外网,但同机房的跳板机、运维终端能上网。这种情况最好办,你可以从跳板机上把需要的rpm包下载好,再通过内网传过去。
第二种,所有机器都完全内网隔离,但公司自己搭了内网Yum源、镜像仓库。这种情况依赖包可以直接从内网源拉,Oracle介质也能从公司文件服务器拿。
第三种,纯物理隔离,什么都没有,只有一组安装光盘和Oracle安装包。这种情况下所有依赖只能从光盘里翻,Oracle还得确认是完整包,而不是需要联网下载的瘦身版。
不同"离线"程度对应的准备工作完全不同。建议你动手前先把网络拓扑和介质清单摸清楚,别一上来就闷头找依赖。我就吃过这个亏——有一次没确认介质完整性,带着一个只有基础安装文件的Oracle包去了现场,装到一半报缺少组件,来回折腾了两天才把包补齐。
1.2 依赖问题才是离线安装的真正难点
在线装Oracle,一条yum install oracle-database-preinstall就把系统参数、依赖包全解决了。离线环境里你没法享受这种待遇,只能手动处理两件事:rpm依赖包和内核参数。
Oracle 11g/12c/19c 对操作系统的依赖包还算稳定,翻来覆去就是 libaio、glibc、libnsl、compat-libcap1、compat-libstdc++、elfutils-libelf、ksh 这几类。但问题在于:不同Linux发行版、不同版本对这些包的名字和版本要求有差异,CentOS 7、CentOS 8、Ubuntu、麒麟系统之间,包名和依赖树完全是两回事。
我建议你在有网络的机器上先准备好两样东西:一个是Oracle官方文档里对应操作系统版本的依赖包清单,一个是依赖包的rpm文件本身。到现场之后不要盲目安装,先用 rpm 的查询命令逐个比对,缺哪个装哪个,避免把整个系统依赖搞乱。
1.3 安装策略:图形界面还是静默安装
离线环境很少有完整的图形桌面,即便有,Oracle安装程序用X11转发也经常出问题。我实践下来最稳的方案是静默安装,利用Oracle自带的 responseFile 应答文件和-silent参数,全程命令行操作,不需要X窗口。
但静默安装对参数的准确性要求很高,路径写错一个字符就得重新来。所以我的建议是:在同等环境(比如本机虚拟机)先走一遍完整安装,找到最合适的应答文件参数组合,再到目标服务器执行。这相当于把试错成本放在可控环境里,生产服务器只做一次成型。
另外要提前规划好安装用户、目录结构和监听端口。Oracle要求不能用root直接安装,必须创建专属用户(比如 oracle),安装目录的属主、权限、空间都要提前确认。我见过有人把所有东西都装到/根分区下,结果到最后空间不足,只能全盘重来。
2. 离线依赖包收集:三条路线的优缺点对比
2.1 路线一:在联网机器上用 yumdownloader 批量拉取
如果你有一台可以上网、且操作系统版本与目标机基本一致的机器,这是效率最高的一条路。核心思路是:先用 yum 模拟安装时解析出所有依赖,再用 yumdownloader 把rpm包全部下载下来。
# 在联网机器上执行 # 安装 yum-utils 工具包 yum install -y yum-utils # 创建一个空目录,用于下载所有依赖 mkdir -p /root/oracle-rpms cd /root/oracle-rpms # 下载 oracle-database-preinstall 及其全部依赖 yumdownloader --resolve --destdir=/root/oracle-rpms oracle-database-preinstall # 如果你的Oracle版本没有对应的preinstall包,也可以用 yumdownloader 拉取核心依赖 yumdownloader --resolve --destdir=/root/oracle-rpms \ binutils compat-libcap1 compat-libstdc++-33 gcc gcc-c++ glibc glibc-devel ksh \ libaio libaio-devel libgcc libstdc++ libstdc++-devel libXext libXtst \ libX11 libXau libXi make sysstat unixODBC unixODBC-devel--resolve选项会自动把依赖树里的所有rpm都拉下来,非常省事。下载完成后把这些rpm文件打包传到内网机器,执行rpm -Uvh *.rpm即可。
这条路线的坑在于:如果目标服务器是多网卡、做了bond或者配置了特殊网络策略的机器,依赖包版本可能在个别环境下不一致。所以安装完后一定要对照上一节的清单逐个核对。
2.2 路线二:从系统安装光盘里找rpm
如果连联网机器都没有,但手上有操作系统安装光盘(或ISO镜像),也可以从光盘里翻出大部分依赖包。CentOS/RHEL 的光盘里自带Packages目录,几千个rpm包躺在里面,Oracle需要的那些基础依赖大多能从这里找到。
# 挂载光盘或ISO镜像 mount -o loop /path/to/CentOS-7-x86_64-DVD-2009.iso /mnt/cdrom # 进到包目录 cd /mnt/cdrom/Packages # 查找是否包含目标包 ls | grep -E "^libaio|^glibc-devel|^compat-libstdc++"用光盘做依赖源的优点是完全断网可用,缺点是版本可能偏旧,且部分包(如 compat-libcap1、compat-libstdc++-33)在较新版本的光盘里可能已经不再带了。这种时候你需要去别的配套光盘(比如扩展包光盘)或者找旧版本的系统光盘来补缺。
2.3 路线三:借助createrepo搭建本地Yum源
依赖文件收集齐了之后,统一把它们做成一个本地Yum源是一个很好的习惯,不建议直接用rpm -ivh逐个安装。因为依赖包之间互相有依赖关系,手工程序容易装了A发现缺B,装了B又说要和A冲突。
用 createrepo 做一个离线Yum源,然后在目标机上指向该源,让 yum 自动解析依赖,出错概率会低得多。
# 在装有依赖rpm的目录下生成元数据 yum install -y createrepo createrepo /root/oracle-rpms # 编写 repo 配置文件 cat > /etc/yum.repos.d/oracle-local.repo <<'EOF' [oracle-local] name=Oracle Local Dependencies baseurl=file:///root/oracle-rpms enabled=1 gpgcheck=0 EOF # 清理缓存并测试 yum clean all yum makecache yum install -y oracle-database-preinstall这一步做完,依赖问题基本就解决了。本地Yum源还有另一个好处:后续如果还需要装别的软件(比如unzip、vim),只要把对应rpm丢进这个目录刷新一下repos,就能继续用yum管理,不用每次都在网上现找。
2.4 依赖包收集的"查漏补缺"技巧
哪怕你下载了全套依赖,到现场还是可能漏一两个。这时候不要急着瞎装,先用系统自带的 rpm 校验工具检查缺什么:
# 检查某个包是否已安装 rpm -q libaio libaio-devel glibc-devel compat-libstdc++-33 # 用 rpm 验证待安装包的依赖是否全部满足 rpm -Uvh --test oracle-database-preinstall-*.rpm--test参数非常有用,它只做模拟安装,不会真正改动系统,却能准确列出缺少的依赖。看到"error: Failed dependencies"之后,按提示补齐对应rpm,再来一遍--test,直到没有任何报错再真正执行。
3. 静默安装的全过程:从应答文件到数据库实例
3.1 内核参数、用户和目录是必须先做的前置工作
Oracle安装对系统参数有硬性要求,这些参数如果不提前设好,安装程序会在前检测阶段直报错,甚至无法继续。以下是我整理的一个常用配置基线,适用于CentOS 7/8 类环境:
# /etc/sysctl.conf 追加以下内容 cat >> /etc/sysctl.conf <<'EOF' fs.file-max = 6815744 kernel.sem = 250 32000 100 128 kernel.shmmni = 4096 kernel.shmall = 1073741824 kernel.shmmax = 4398046511104 net.core.rmem_default = 262144 net.core.rmem_max = 4194304 net.core.wmem_default = 262144 net.core.wmem_max = 1048576 fs.aio-max-nr = 1048576 net.ipv4.ip_local_port_range = 9000 65500 EOF # 使参数生效 sysctl -p同时还需要创建 oracle 用户、用户组和安装目录:
groupadd oinstall groupadd dba useradd -g oinstall -G dba oracle mkdir -p /u01/app/oracle chown -R oracle:oinstall /u01/app/oracle chmod -R 775 /u01/app/oracle对于/etc/security/limits.conf,也要加上oracle用户的资源限制。尤其要关注 nproc 和 nofile 这两项,很多数据库连接数上不去、进程数上限不够导致实例启动失败,就是这两个参数没设置好。
3.2 应答文件:静默安装的灵魂
Oracle安装包解压后,在database/response/目录下能找到三个模板文件:db_install.rsp、dbca.rsp、netca.rsp。静默安装前,你需要把db_install.rsp复制出来并修改关键字段。
cp /path/to/database/response/db_install.rsp /home/oracle/db_install.rsp chown oracle:oinstall /home/oracle/db_install.rsp chmod 755 /home/oracle/db_install.rsp重点修改以下几项:
# 安装类型:只装数据库软件 oracle.install.option=INSTALL_DB_SWONLY # 版本和目录 UNIX_GROUP_NAME=oinstall INVENTORY_LOCATION=/u01/app/oraInventory ORACLE_HOME=/u01/app/oracle/product/11.2.0/dbhome_1 ORACLE_BASE=/u01/app/oracle # 数据库版本 oracle.install.db.InstallEdition=EE oracle.install.db.DBA_GROUP=dba oracle.install.db.OPER_GROUP=dba需要注意INVENTORY_LOCATION这个路径。Oracle会用它记录所有安装组件的清单,如果该目录属主不对,安装时会直接报权限错误。另外ORACLE_HOME的路径层级是有规范的,不能随便取名,否则后面的工具脚本可能因为路径层级不匹配而找不到某些配置。
3.3 执行安装:runInstaller 的常用参数
全部准备就绪后,用 oracle 用户执行安装命令:
su - oracle cd /path/to/database ./runInstaller -silent -responseFile /home/oracle/db_install.rsp \ -ignorePrereqFailure \ -showProgress`-si这个参数的作用是:当某些非关键的前置检测不过时,不阻断安装进程。但切记它只能跳过非关键项,如果是内核参数、依赖缺失这类硬性条件不满足,跳过之后安装过程中照样会失败。
安装过程中建议打开另一个终端,实时观察日志输出。Oracle会把日志写到$ORACLE_BASE/cfgtoollogs/dbua/以及/tmp/installActions*.log。如果等了很久没有进展,或者日志卡在某个百分比不动,多半是某个可执行文件权限不对、或者临时目录满了。
安装完成后,Oracle提示需要以root身份执行两个脚本:oraInventory目录下生成的orainstRoot.sh,以及$ORACLE_HOME下的root.sh。这一步绝对不能偷懒。我曾经试过不执行 root.sh 继续建库,结果监听配置、权限相关的操作全出现异常,最后查来查去发现就是这里漏了。
3.4 用netca和dbca静默配置监听与建库
软件装完后,接着用 netca 和 dbca 创建监听和数据库实例,这两个工具同样支持静默模式。
配置监听:
$ORACLE_HOME/bin/netca /silent \ -responseFile $ORACLE_HOME/network/install/netca.rsp监听默认端口是1521,如果你所在的内网环境里1521被其他服务占用,可以在$ORACLE_HOME/network/admin/listener.ora里手动改端口。改完之后用lsnrctl start启动,然后用lsnrctl status确认监听状态。
创建数据库实例:
$ORACLE_HOME/bin/dbca -silent \ -createDatabase \ -templateName General_Purpose.dbc \ -gdbName orcl \ -sid orcl \ -sysPassword SysPassword123 \ -systemPassword SystemPassword123 \ -storageType FS \ -datafileDestination /u01/app/oracle/oradata \ -recoveryAreaDestination /u01/app/oracle/flash_recovery_area \ -characterEventSet AL32UTF8 \ -memoryPercentage 30 \ -emConfiguration NONE这里有几个参数值得说两句。-characterSet AL32UTF8建议在首次建库时就明确指定,如果建完之后再改字符集,很容易出现数据乱码和ORA-12712之类的报错。-memoryPercentage 30是根据服务器内存情况分配SGA+PGA占比,生产环境建议你根据业务量调优,而不是直接用默认值。-emConfiguration NONE是关掉Enterprise Manager,内网环境没必要开,还能省掉相关进程资源。
dbca建库耗时不短,日志在$ORACLE_HOME/cfgtoollogs/dbca/orcl/下。看到"Database creation complete"基本就成了。
4. 监听起不来、ORA报错:离线安装后的典型故障排查
4.1 监听服务无法启动的完整排查链路
这是离线安装后最常见的故障,热搜里也有"oracle监听服务无法启动"这么一个长期霸榜的条目。我自己在安装现场至少遇到过三次,每次原因都不太一样。这里把排查链路完整写出来。
第一步,先用状态命令确认监听到底卡在哪:
lsnrctl status lsnrctl start如果lsnrctl start报TNS-12541: TNS:no listener或者TNS-12560: TNS:protocol adapter error,第一反应先看端口占用:
netstat -tlnp | grep 1521端口没被占用的话,接下来看 hosts 和 listener.ora 配置。Oracle监听对这个文件里的主机名或IP非常敏感。我也犯过这样的错——安装时服务器的hostname带了一个奇怪的短域名,listener.ora里代码自动生成的host就是那个短域名,结果监听死活起不来。解决方法是直接把 listener.ora 里的 HOST 改为服务器实际分配的IP地址,然后重启监听。
第二步,如果监听进程虽然起来了,但lsnrctl status显示 "The listener supports no services",这说明数据库实例没有向监听注册。多数原因是实例还没完全启动,或者local_listener参数没配对。执行以下SQL:
ALTER SYSTEM SET local_listener='(ADDRESS=(PROTOCOL=TCP)(HOST=192.168.1.10)(PORT=1521))' SCOPE=BOTH; ALTER SYSTEM REGISTER;再把服务手工注册一下,监听状态里就能看到对应的服务名了。
第三步,用tnsping验证网络层通不通。如果tnsping能通但应用连接还是报错,重点检查tnsnames.ora里的服务名是否和lsnrctl status里显示的服务名完全一致。
4.2 ORA-12514和ORA-01034的快速定位思路
ORA-12514(TNS: listener does not currently know of service requested in connect descriptor)这个报错出现的频率非常高。大部分人第一时间去改 tnsnames.ora,但其实绝大多数情况问题出在实例没有注册到监听。
我的排查思路是:先执行lsnrctl services,看监听识别到的服务名列表。如果列表为空,回到4.1的注册流程;如果列表里有和连接串不一致的名字,把 tnsnames.ora 里的 SERVICE_NAME 改成监听实际注册的那个名字。
ORA-01034(ORACLE not available)则是实例层面的问题。建议按以下顺序排查:先ps -ef|grep smon确认实例是否存活;再sqlplus / as sysdba进去看数据库状态;状态显示MOUNTED但没OPEN,用alter database open打开。如果连 STARTUP 都做了还是不行,看看$ORACLE_HOME/dbs里的参数文件、密码文件是否存在,权限是不是oracle用户。离线环境最容易出现的问题就是密码文件缺失,因为初始化脚本没跑全。
4.3 12c之后的卸载残留问题
热搜里有一条"12c删除不干净+oracle",这个问题值得单独提一下。12c和更高版本的Oracle引入多租户架构(CDB/PDB),卸载时的残留文件比11g更多,常见的有三类:
第一类,/etc/oratab里残留的实例启动项。卸载后这个文件不会自动清理,导致重启机器时Oracle尝试去启动已经不存在的实例,报错但不影响系统运行,很烦人。手动编辑该文件删掉对应行即可。
第二类,$ORACLE_BASE/cfgtoollogs和$ORACLE_HOME下遗留的日志、跟踪文件。Oracle官方其实提供了deinstall命令,但很多人不知道,仍然手动删目录。手动删也问题不大,关键是删除顺序:先删数据库(dbca -silent -deleteDatabase),再删监听(netca -silent -deconfigure),最后删软件(deinstall)。顺序反了,后面步骤会拿不到实例信息,只能硬删。
第三类,/etc/oraInst.loc文件。它记录了Inventory的位置,如果不删,重装Oracle时安装器会认为系统里已有旧版本,导致无法安装。重新安装前记得把它和对应的 Inventory 目录一起清掉。
4.4 离线环境下打补丁的注意事项
生产环境装完Oracle后,打补丁是绕不开的一步,尤其是11.2.0.4这类经典版本,补丁集经常要打到最新的PSU。在线环境可以用 OPatch 自动从网络下载,但离线环境必须手工把补丁包传到服务器上。
打补丁前先确认两件事:
# 确认OPatch版本是否满足补丁要求 $ORACLE_HOME/OPatch/opatch version # 确认当前补丁基线 $ORACLE_HOME/OPatch/opatch lsinventory补丁包通常是一个zip文件,里面有patch目录和README.txt。严格按照README里的顺序执行:第一步通常是在sqlplus里执行alter system set ""_use_single_log_writer""=true之类的预检查操作,第二步是opatch apply,第三步是跑数据字典升级脚本catupgrd.sql或者catbundle.sql。
我踩过的坑是:打完补丁没有跑数据字典脚本,结果应用一上来就报 ORA-00600,后来才反应过来是数据字典版本和二进制版本不匹配。所以打完补丁后,务必在日志里确认二进制补丁和SQL补丁两步都执行成功,缺一个都不行。
5. 国产系统环境下的离线安装补充
5.1 与CentOS差异巨大的发行版要先做兼容性验证
热搜词里有"linux国产",随着国内自主操作系统的普及,在统信UOS、麒麟、龙蜥、欧拉这些系统上装Oracle的需求已经越来越多了。国产系统虽然大多基于Linux内核,但包管理器、glibc版本、系统目录结构都有不同程度的改动,不能拿CentOS的经验直接套。
例如在麒麟V10上,compat-libstdc++-33这个包名可能不存在,替代的方案是安装当前系统的libstdc++.so.6兼容版本,或者直接做一个软链接指向已有库。又比如某些国产系统默认没有/u01这样的挂载点规划,文件系统目录结构更靠近/data,需要你在应答文件里修改所有路径。
我的建议是:去现场之前先在相同版本的国产系统虚拟机里做一次完整的安装演练。这一步能发现八成以上的兼容性问题,省去在现场反复试错的痛苦。
5.2 重新打包安装目录的复制部署方案
如果目标机器数量比较多(比如一堆内网测试服务器都要装Oracle),一台一台静默安装的效率会很低。另一个思路是:找一台环境完全一致的机器,装好Oracle并打好补丁,然后打包整个$ORACLE_HOME、$ORACLE_BASE,再拷贝到其他机器上做解压部署。
这个方案有几个前置条件:一是所有机器操作系统版本、内核参数完全一致;二是解压后必须重新执行 root.sh 和 orainstRoot.sh;三是要重新配置监听和实例名,不能直接用原机器的。虽然稍显粗暴,但操作熟练之后,单台机器的部署时间能从两小时压缩到二十分钟以内。
5.3 把准备工作脚本化,省掉重复劳动
离线安装的整个流程里,有大量重复性的准备工作:创建用户、改内核参数、配置limits、解压安装包。我习惯把这些操作整理成一个初始化脚本,在每台机器上先执行一遍。
#!/bin/bash # oracle_preinstall.sh # 创建用户和目录 groupadd -f oinstall groupadd -f dba id oracle >/dev/null 2>&1 || useradd -g oinstall -G dba oracle mkdir -p /u01/app/oracle chown -R oracle:oinstall /u01/app/oracle # 内核参数 cat >> /etc/sysctl.conf <<'EOF' fs.file-max = 6815744 kernel.sem = 250 32000 100 128 kernel.shmmni = 4096 kernel.shmall = 1073741824 kernel.shmmax = 4398046511104 net.core.rmem_default = 262144 net.core.rmem_max = 4194304 net.core.wmem_default = 262144 net.core.wmem_max = 1048576 fs.aio-max-nr = 1048576 net.ipv4.ip_local_port_range = 9000 65500 EOF sysctl -p # 资源限制 cat >> /etc/security/limits.conf <<'EOF' oracle soft nproc 2047 oracle hard nproc 16384 oracle soft nofile 1024 oracle hard nofile 65536 oracle soft stack 10240 oracle hard stack 32768 EOF echo "Oracle preinstall configuration completed."每次到新环境,先跑一遍这个脚本,再进入Oracle安装流程,能大幅度降低低级错误的出现概率。
6. 我的一点个人经验总结
离线安装Oracle这件事,本质上考验的不是你对Oracle命令的熟练程度,而是你对环境差异的预判能力。看再多的教程,都不如自己完整地走过一遍从依赖收集到建库的流程。我在前几次安装时也踩了不少坑,但有一个很深的体会:凡是遇到离奇的报错,先别急着搜索解决方案,而是按顺序检查基础环境——文件权限、目录属主、hosts配置、内核参数——十次里有八次问题都出在这些"低级"环节。
如果你准备在近期做离线安装,我的建议是先在虚拟机里完整跑一遍,把依赖包清单、应答文件参数、初始化脚本都在虚拟机里验证好。到生产环境时,你会发现自己手里的材料已经足够应付绝大多数情况了。后面如果再遇到比较有代表性的故障,我还会继续整理分享。