☰
CentOS 7 离线安装 PostgreSQL 12:依赖打包、初始化和远程访问全攻略
2026/10/14 2:18:21 网站建设 项目流程

最近手头一个内部数据平台项目,数据库服务器托管在客户的内网区,机器别说公网 IP,连系统的软件源都走的是受限镜像,很多在线安装的常规操作根本没法执行。项目组原计划用 Docker 镜像直接导入,结果环境不允许容器运行时,同时又赶上软件供应链审查,所有安装物必须可追溯、可离线交付。最后又回到了最土但最靠谱的方案:在一台联网准备机上把 PostgreSQL 12 的 RPM 包及其全部依赖拉下来,再通过内部传输通道拷进目标机,rpm 一把装上。如果你也正在被 CentOS 7 离线安装 postgresql12 这件事折腾,这篇内容基本完整覆盖了我这次实操的链路,从打包含清单到初始化、远程访问配置,再到最后那些只有踩过才知道的坑,一次讲清楚。

先说结论:离线安装 PostgreSQL 12 本身并不复杂,复杂的是“离线”两个字带来的依赖闭环、环境差异和权限控制问题。整条链路里的细节一旦遗漏,轻则启动失败,重则装完连不上。这篇就把准备机上怎么拉包、目标机上怎么装、装完怎么配、配完怎么验证,以及我实际踩过的三个坑全部梳理出来,希望能让后来的人少走点弯路。

1. 为什么最终选了离线 RPM 包,而不是源码编译

1.1 内网环境下的三种软件分发方式对比

在没有外网的 CentOS 7 服务器上装软件,常见无非三种思路:源码编译、RPM 离线包、内网搭建本地 yum 仓库镜像。这三种方式我这次都实际评估过,最终选了离线 RPM 包,原因很直接。

先看源码编译。PostgreSQL 源码编译在 CentOS 7 上是有完整步骤可循的,configure、make、make install 一条龙。但源码编译有两个很现实的问题:第一,编译依赖太多,gcc、make、readline-devel、zlib-devel 这些开发工具链在最小化安装的机器上往往一个都没有,离线环境下补齐这些依赖本身就回到“依赖闭环”的难题上;第二,编译安装的 PostgreSQL 不走系统包管理,后续要装扩展、做版本升级、用 pg_upgrade 迁移,都要手动处理路径和权限,维护成本高。对生产环境来说,这种“野生”安装方式出事之后排查成本很大。

再看内网 yum 仓库镜像。这种方式确实体面,把外网的 PGDG 源同步到内网服务器,目标机直接 yum install。但搭建仓库镜像需要额外的存储和同步机制,而且很多内网环境不允许随便开放额外服务,审批流程长。对单机或两三台数据库服务器的场景来说,属于“杀鸡用牛刀”。

离线 RPM 包正好打在中间:依赖关系通过 rpm 包自带的 metadata 解决,安装行为受系统包管理器管控,后续升级用 yum 指向本地目录即可,完全符合供应链审查要求的“可追溯”原则。这也是大多数内网数据库部署最终会走的路。

1.2 为什么选 PostgreSQL 12 而不是更高的版本

PostgreSQL 社区目前活跃版本早就到了 15、16,但很多业务系统之所以还在用 12,往往不是不想升级,而是有客观约束。我这次遇到的情况就是客户的应用层代码连接串、驱动版本、SQL 写法都基于 PG 12 验证过,DBA 团队的日常巡检脚本也更熟悉 12 的体系,贸然升到 13 以上,行为变化带来的回归测试成本他们不愿意承担。

从功能层面看,PG 12 已经具备了并行查询增强、分区表改进、JSON 路径查询等关键能力,对大多数政务和金融场景完全够用。加上 PGDG 仓库里仍然保留 postgresql12 这一组安装包,这也意味着官方社区对 12 的维护周期还在延续,安全补丁跟得上。技术选型这件事上,稳定性和生态适配往往比“用最新版”更重要。

2. 在联网准备机上把安装包一次拉齐

2.1 准备机的源配置与版本核对

离线安装的第一步,其实是找一台“干净”的联网机器。这里的“干净”指的是系统版本和目标机保持一致,最好是同样的 CentOS 7 大版本,x86_64 架构更不能差。原因很简单:RPM 包编译时依赖的 glibc 版本、库文件路径都和系统版本强相关,你在 CentOS 8 上拉下来的二进制包,拿到 CentOS 7 上装大概率会直接报GLIBC_2.28 not found之类的问题。

准备机确定之后,先加上 PostgreSQL 官方维护的 PGDG 仓库。之所以坚持用官方源而不是第三方源,是因为官方仓库的包签名、版本编号、依赖声明都经过了完整的发布流程,离线安装包里带签名信息,目标机上可以用rpm -K校验包裹来源,这在供应链审查的时候非常加分。

yum install -y yum-utils yum install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repo-latest.noarch.rpm yum makecache fast

装完源之后先核对一下可用的包版本,确保真的能拉到 12 系列。不要凭感觉直接下载,万一源配置有问题,拉下来的可能是 13 或 14,后面全部白干。

yum list available | grep postgresql12

输出里会看到postgresql12-server.x86_64等包名,确认存在之后再做下一步。

2.2 用 yumdownloader 一次性拿齐依赖包

打包含最推荐的方式是yumdownloader --resolve。这条命令会像 yum 安装时一样解析依赖,把目标包及其所有未安装的依赖包全部下载到指定目录。相比手动一个个找依赖,这个方案能省掉大量时间,而且依赖版本是经过源仓库元数据计算的,不会出现“拉了大版本但不匹配小版本”的问题。

mkdir -p /opt/pg12rpms cd /opt/pg12rpms yumdownloader --resolve --destdir=/opt/pg12rpms postgresql12-server postgresql12 postgresql12-contrib

这里我习惯把postgresql12-contrib也一并拉下来。contrib 包里包含了很多常用扩展模块,比如pg_stat_statements、postgres_fdw、uuid-ossp等等,业务侧一旦要启用这些功能,离线下没有这个包就只能再折腾一轮。多拉一个包的传输成本几乎可以忽略,但能避免二次进场。

下载完成之后,目录下会出现一堆 RPM,除了 postgresql12 的包之外,还有 libicu、libxslt、perl 等系统依赖包。看到这些就对了,它们就是目标机上必需的最小依赖集合。列个表更直观:

包名作用是否必需
postgresql12-libsPG 客户端库,所有工具的基础依赖必需
postgresql12psql 等命令行工具必需
postgresql12-server数据库服务端二进制必需
postgresql12-contrib扩展模块集合强烈建议
libicuUnicode 支持库依赖自动带入
libxsltXML 处理库依赖自动带入
perl系统自带的脚本语言,部分辅助程序依赖依赖自动带入

2.3 传输到目标机之前的两项自检

包拉齐之后不要急着传,先做两件小事。第一是校验包的完整性和签名,用rpm -K检查。PGDG 官方包的签名公钥会在安装源 RPM 时自动导入,所以在准备机上校验通常直接返回 OK。

rpm -K /opt/pg12rpms/*.rpm | grep -v OK

没有任何非 OK 输出说明包裹完整。第二件事是把整个目录压缩归档,记录下软件清单和版本号,方便后续审计。实际操作中我还会在压缩包旁边写一个 README,把准备机的系统版本、内核版本、拉取时间、用的哪个源都写清楚。

cd /opt tar czf pg12rpms.tar.gz pg12rpms/

传输方式就按现场条件来,U 盘、内网共享、堡垒机的文件通道都可以。传输完成后在目标机上重新解压,注意文件权限不要被 Windows 中转搞乱,解压后看一眼所有文件仍然是 -rw-r--r--,后续安装才能正常读取。

3. 目标机上的安装与初始化

3.1 目标机器装包前最重要的预检查

目标机拿到压缩包解压之后,先别急着 rpm。预检查这一步在离线场景下极其重要:确认磁盘剩余空间不少于 5GB(安装本身用得不多,但数据目录和以后备份要留余地),确认系统没有装过旧版 PostgreSQL 的服务端,确认 /etc/yum.repos.d/ 下没有乱七八糟的坏源干扰 rpm 命令执行。

df -h cat /etc/redhat-release uname -m rpm -qa | grep -i postgresql

如果rpm -qa | grep postgresql能查到系统自带的 PostgreSQL 9.2 客户端,不需要卸载它。CentOS 7 自带的那套是 9.2 版本,二进制在 /usr/bin 下,和 PGDG 安装到 /usr/pgsql-12/bin 下的 12 完全独立,两者并不冲突。只要确保系统自带的 postgresql 服务没有占用 5432 端口就行。

3.2 rpm 安装顺序:依赖优先,服务包殿后

在离线目录里直接用通配符安装是最快的,rpm 会扫描同目录下所有的包做依赖解析,自动把 libs 排在前面。我实际执行的时候更习惯分两步:先把目录里所有包按依赖关系一次性 rpm -ivh,如果报缺依赖再单独处理。

cd /opt/pg12rpms rpm -ivh *.rpm

这一步最常见的报错是libpq.so.5()(64bit) is needed by ...,表示某个包依赖 libpq 库,但目录里可能漏了postgresql12-libs。解决方式就是回到准备机上确认到底有没有下载这个包,而不是在目标机上用--nodeps --force强行安装。强行安装一时爽,后面 psql 起不来的时候排查起来真是欲哭无泪。

装完之后验证一下:rpm -qa | grep postgresql12应该能看到 libs、server、contrib 几个包。命令psql --version如果提示找不到,说明 postgresql12 主包没装上或者 PATH 里没 /usr/pgsql-12/bin,这会在后面“踩坑”部分细说。

3.3 初始化数据目录与服务启动

RPM 包装完系统会自动创建 postgres 系统用户和 /var/lib/pgsql/12 目录,但数据目录还需要手动初始化。PGDG 提供了一键脚本/usr/pgsql-12/bin/postgresql-12-setup initdb,本质是封装了 initdb 并且把目录属主调整到 postgres 用户。

/usr/pgsql-12/bin/postgresql-12-setup initdb

这一步如果报can not be run as root,别慌,说明你用的是 root 执行,但 initdb 出于安全设计不允许 root 直接初始化。用脚本时确保脚本内部切换到了 postgres 用户,如果手动执行 initdb 就用下面的方式:

mkdir -p /var/lib/pgsql/12/data chown postgres:postgres /var/lib/pgsql/12/data sudo -u postgres /usr/pgsql-12/bin/initdb -D /var/lib/pgsql/12/data --locale=en_US.UTF-8 --encoding=UTF8

这里我强烈建议在 initdb 时显式指定--locale=en_US.UTF-8 --encoding=UTF8,不要依赖系统默认 locale。最小化安装的 CentOS 7 经常只装了英文 locale,或者系统 locale 是 POSIX,默认初始化出来的数据库排序规则会很奇怪,后续做中文字段排序、索引构建都可能受到隐性影响。

初始化成功之后启动服务并设置开机自启:

systemctl enable postgresql-12 systemctl start postgresql-12

注意服务名是postgresql-12,不是postgresql,这个区别对 CentOS 7 老手来说也容易翻车,后面会专门讲。

启动确认用systemctl status postgresql-12,看到 active (running) 就说明数据库进程起来了。再补一刀ss -lntp | grep 5432,能看到 postmaster 在监听,基本可以说安装链路是通的。

4. 远程访问配置:不止改监听地址这么简单

4.1 数据配置文件两个必须动的参数

服务起跑之后先验证本地连接,默认配置下用 postgres 系统用户登录:

sudo -u postgres psql -c "select version();"

能返回 PostgreSQL 12.x 版本号,说明服务端正常。接下来就是远程访问配置,这步是离线安装完成后业务方最关心的部分,也是配置项最多、最容易出问题的地方。

编辑/var/lib/pgsql/12/data/postgresql.conf,至少改两个参数。第一个是listen_addresses,默认被注释掉,等价于只监听 localhost。改成'*'表示监听所有网卡,如果你的机器有多块网卡且只想暴露业务网卡,可以写成具体的 IP 地址:

listen_addresses = '*'

第二个是port,默认 5432,一般不需要改,除非端口被占用或安全策略要求换端口。改了端口的话,后面所有连接串、防火墙规则都要跟着变,能不动就不动。

改完配置文件后需要重启服务才能生效:

systemctl restart postgresql-12

4.2 pg_hba.conf 认证规则的顺序与加密方式

监听地址配置好后,真正拦人的是/var/lib/pgsql/12/data/pg_hba.conf。这个文件按从上到下的顺序匹配,第一条命中的规则生效,所以新增的远程访问规则不要放在文件最后,更稳妥的做法是放在host all all 127.0.0.1/32之前,或者直接放在 IPv4 段前面。

host all all 0.0.0.0/0 md5 host all all ::/0 md5

这里有个细节必须提醒:PostgreSQL 12 在初始化时默认的加密方式是 md5,如果你在 pg_hba.conf 里直接写scram-sha-256,但数据库里现有用户的密码存储格式还是 md5,认证会直接失败,报错往往是password authentication failed for user “xxx”。想用 scram 的话有两个步骤:先在 postgresql.conf 里设置password_encryption = 'scram-sha-256',然后重新设置一次用户密码,让密码字段升级成 SCRAM 格式。对于刚开始部署的环境,直接用 md5 最省事,因为 PG 12 默认就是这个。

配置改完同样要重启服务或者pg_ctl reload。reload 对 pg_hba.conf 和 postgresql.conf 都生效,不需要重启,用起来很方便:

systemctl reload postgresql-12

4.3 设置业务密码并验证远程连通性

远程访问至少需要一个非空密码的登录账号。开发阶段我习惯先用超级用户 postgres 设置一个强密码,验证链路通;正式上线前再按最小权限原则建一个专用业务账号。设置密码用 psql 执行:

sudo -u postgres psql -c "ALTER USER postgres PASSWORD 'Str0ng-P@ssw0rd-2024';"

然后从另一台机器上用客户端工具连一下:

psql -h 目标机IP -p 5432 -U postgres -d postgres

如果这一步卡住不动或者报could not connect to server,大概率不是数据库的问题,而是下一节要说的防火墙和 SELinux。

4.4 防火墙与 SELinux 的收尾配置

CentOS 7 默认开启 firewalld,即使你人在内网,规则没放行照样连不上。添加规则并重载:

firewall-cmd --permanent --add-port=5432/tcp firewall-cmd --reload

验证规则是否生效:

firewall-cmd --list-ports

SELinux 是另一个隐形拦路虎。CentOS 7 默认 enforcing 模式下,PostgreSQL 进程默认只能在本机监听,允许网络访问需要打开对应布尔开关:

getsebool -a | grep postgresql setsebool -P postgresql_can_network on

-P参数表示持久化配置,重启依然生效。做完这一步再用远程客户端连接,绝大多数连接失败问题都能解决。

5. 我踩过的三个坑:从“装好”到“稳定跑”

5.1 服务名对不上:PGDG 包与系统自带 PostgreSQL 的服务差异

这个坑我见得太多了,包括我自己第一次装 PGDG 的 PostgreSQL 也踩了。CentOS 7 自带的 postgresql 9.2 的 systemd 服务名是postgresql.service,而 PGDG 仓库安装的 PostgreSQL 12 服务名是postgresql-12.service。很多人在装完 12 之后顺手执行systemctl start postgresql,结果看到系统自带 9.2 那个服务起来了,又因为数据目录和监听端口跟 12 完全不是一套,于是陷入“我到底启动的是哪个数据库”的困惑。

解决办法就是统一用systemctl start postgresql-12,并且用ss -lntp | grep 5432看监听进程的二进制路径,确认是/usr/pgsql-12/bin/postgres。另外,如果机器上同时装了两套,建议把系统自带的 9.2 服务 disable 掉,避免开机自启抢占端口。

systemctl disable postgresql

5.2 客户端无法连接:最容易漏掉的四层排查链路

远程连接失败时,我建议按下面的链路排查,而不是直接怀疑数据库配置错了。每层都可能拦截,但很多新手只盯着 pg_hba.conf 改来改去,忽略了防火墙和 SELinux。

第一层,网络是否通。在客户端上用ping 目标机IP或者telnet 目标机IP 5432看端口通不通。不通先查防火墙规则和网络环境,不要碰数据库配置。

第二层,监听地址是否真的生效。在目标机上执行ss -lntp | grep 5432,如果看到监听的地址是*:5432就没问题;如果是127.0.0.1:5432,说明 postgresql.conf 里 listen_addresses 没改或者改了没重载。

第三层,防火墙。上面提到的 firewalld 规则没加上,端口就是不通。这一步在内网环境尤其隐蔽,因为有些内网交换机层面有安全策略,光看本机防火墙也未必能找到根因,要配合网络团队排查。

第四层,pg_hba.conf 的认证方式。连接如果出现password authentication failed,检查客户端连接时用户名、密码、加密方式三者是否一致。很多人会把密码记错,还有一个容易被忽略的是 pg_hba.conf 规则顺序,前面的规则先匹配,如果有一条早于你的业务规则把请求给拒了,后面加再多规则也没用。

5.3 root 用户执行 psql 提示角色不存在

最后一个坑特别常见,几乎每个用 root 登录服务器的新手都会遇到。psql 默认用当前系统用户名连接数据库,root 用户执行 psql 时,实际是在尝试以数据库角色 root 登录,而 PostgreSQL 里根本没有这个角色,于是报psql: error: FATAL: role "root" does not exist。

这不是数据库装坏了,只是连接参数没指定。正确的做法是切到 postgres 系统用户再连:

sudo -u postgres psql

或者显式指定用户名:

psql -U postgres -h 127.0.0.1

如果 initdb 后没有设置 postgres 用户密码,走 TCP 连接依然会报认证失败,这时候回到 postgres 系统用户本地连接里补一条 ALTER USER 语句即可。

最后再分享一个小技巧:这次整个流程走通之后,我把所有命令按顺序整理成了一个安装脚本,放在压缩包里一起交付,每个关键步骤后面都加了set -e和注释说明依赖关系。下次再遇到同样型号的 CentOS 7 机器,解压、执行、初始化、验证四步走完,半小时内就能拉起一套 PostgreSQL 12。离线安装这事的本质,就是把环境差异搞清楚、依赖闭环堵死,剩下的无非是耐心。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询