Rocky_Linux_9.8_安装_PostgreSQL_16

文章目录


Rocky Linux 9.8 安装 PostgreSQL 16:自定义数据目录 + 远程访问完整记录

内网一台 Rocky 9.8 要装 PostgreSQL 16 给业务系统用。系统盘不大,数据目录定在 /data/app/postgresql,没走默认的 /var/lib/pgsql/16/data

一开始以为只是把 initdb -D 的路径换一下的事,实际动手才发现自定义目录会额外带出两个问题:systemd 的 PGDATA 得覆盖,pg_hba.confpostgresql.conf 也跟着搬了家。下面按实际操作顺序记一遍,中途碰到的报错原文一起贴上。

环境

操作系统 Rocky Linux 9.8 (Blue Onyx)
PostgreSQL 16(PGDG 官方源)
数据目录 /data/app/postgresql/data 是单独挂的数据盘)
端口 5432
客户端服务器 192.168.1.2
SELinux Disabled
firewalld 未启用

Rocky 9.2 到 9.8 在这一套流程里没有差别,命令可以直接照搬,PGDG 仓库那个包选 EL-9 就行,整个 9.x 系列共用。

SELinux 和 firewalld 这两项单独列出来,是因为它们直接决定了后面的步骤能不能省。这台机器上两者都是关着的,所以没踩到;但换一台默认配置的机器,这两处是绕不过去的,第四节会说明。

一、装 PostgreSQL 16

Rocky 9 自带的 appstream 仓库里有 postgresql 模块,但版本停在 13,要 16 得加 PGDG 官方源:

bash 复制代码
dnf -y install https://download.postgresql.org/pub/repos/yum/reporpms/EL-9-x86_64/pgdg-redhat-repo-latest.noarch.rpm

装完先别急着装包,把系统自带的 postgresql 模块禁掉:

bash 复制代码
dnf -qy module disable postgresql

这一步漏掉的话,dnf install 有可能被 module 拦下来,或者给你装出一套来源混杂的包,后面查问题很烦。

然后装服务端和客户端:

bash 复制代码
dnf -y install postgresql16-server postgresql16

PGDG 的包装完之后不会往 /usr/bin 里塞东西,二进制全在 /usr/pgsql-16/bin/ 下面,所以后面 initdbpg_ctl 都得写全路径,别用系统里可能存在的同名命令。

bash 复制代码
ls /usr/pgsql-16/bin/

顺手提一句,postgresql16 这个包不含 contrib 扩展。如果要用 pg_stat_statementspg_trgm 之类的东西,记得把 postgresql16-contrib 一起装上,装完再补也行。

二、建数据目录

bash 复制代码
mkdir -p /data/app/postgresql
chown -R postgres:postgres /data/app/postgresql
chmod 700 /data/app/postgresql

chmod 700 不是可选项。PostgreSQL 启动时会检查数据目录的权限,只要有同组或其他用户的可读权限就直接拒绝启动,日志里只留一句 permission denied,看着像别的问题,实际就是权限给宽了。这个目录里装的是整个数据库的全部内容,收紧就对了。

postgres 这个系统用户在上面装包的时候已经自动创建了,chown 不会报错。

三、初始化数据库

指定 -D 到我们的目录:

bash 复制代码
sudo -u postgres /usr/pgsql-16/bin/initdb -D /data/app/postgresql/

初始化完会打印这么一行:

text 复制代码
成功。您现在可以用下面的命令开启数据库服务器:
/usr/pgsql-16/bin/pg_ctl -D /data/app/postgresql/ -l 日志文件 start

先别照它说的用 pg_ctl 起,我们后面用 systemd 托管。

初始化过程中有两段输出看着像报错,其实都不用管。

第一段:

text 复制代码
initdb: 无法为本地化语言环境"zh_CN.UTF-8"找到合适的文本搜索配置
缺省的文本搜索配置将会被设置到"simple"

这只是说没有配套的中文全文检索配置,跟数据库能不能用完全无关。真要做中文分词检索,一般也是外挂 zhparser 或者 pg_jieba,不会指望自带的。数据类型、字符集、排序规则都不受影响。

第二段:

text 复制代码
initdb: 警告: 为本地连接启用"trust"身份验证

local(Unix socket)连接默认配的是 trust,也就是本机通过 socket 连进来不校验密码,这是 initdb 的默认行为,不是错误。

要注意这里的"本地"指的是 socket,127.0.0.1 那条走的是 TCP,认证方式另算。PG16 默认给的是 scram-sha-256,所以等一下用 -h 127.0.0.1 测试的时候反而会要密码------同一个"本地",两种认证方式,第一次见挺容易懵。

想一开始就收紧,可以在 initdb 时加 --auth-local=scram-sha-256,或者事后再改 pg_hba.conf

四、SELinux 和防火墙:这次关着,但别默认别人也关

这一节先说结论:本次环境 SELinux 是 Disabled、firewalld 也没启用,所以这两处没遇到过问题,下面的步骤都没有执行。

但为什么还要写?因为如果数据目录留在 /var/lib/pgsql/16/data,SELinux 的上下文是发行版配好的,什么都不用管;一旦挪到 /data/app 下面,就是另一回事了------文件属主是对的,但 SELinux 标签还是默认的 default_t,postgres 进程(postgresql_t)读不了,服务会直接起不来。默认配置的 Rocky 9 上这是大概率会中的一枪。

检查状态:

bash 复制代码
getenforce          # SELinux
systemctl is-active firewalld

getenforce 返回 Enforcing 的话,启动失败时日志里一般是这类信息:

text 复制代码
FATAL:  could not open directory "pg_tblspc": Permission denied

或者 systemd 那边直接给个非零退出码、状态 failed

给自定义目录打 SELinux 上下文:

bash 复制代码
dnf -y install policycoreutils-python-utils

semanage fcontext -a -t postgresql_db_t "/data/app/postgresql(/.*)?"
restorecon -Rv /data/app/postgresql

restorecon 不能省,semanage fcontext 只是写规则,不执行不生效。如果做完还是起不来,把 /data/app 甚至 /data 也按同样方式标一遍,父目录缺 search 权限同样过不去。

临时验证是不是标签问题:

bash 复制代码
setenforce 0

如果 setenforce 0 之后服务立刻就起来了,基本可以确认就是这个原因,回去把上面两步做完,再把 setenforce 1 打开复测一遍。生产环境不建议为了省事永久关掉 SELinux------同一台机器上跑的别的服务也在受它保护。

firewalld 的部分放到第八节,跟着远程访问一起说更顺。

五、交给 systemd 管理

PGDG 的 postgresql-16.service 里写死了 PGDATA=/var/lib/pgsql/16/data,我们要覆盖它。

不要直接改 /usr/lib/systemd/system/postgresql-16.service,包升级的时候会被覆盖回去,用 override:

bash 复制代码
mkdir -p /etc/systemd/system/postgresql-16.service.d

cat > /etc/systemd/system/postgresql-16.service.d/override.conf <<'EOF'
[Service]
Environment=PGDATA=/data/app/postgresql
EOF

让 systemd 重新读一遍配置:

bash 复制代码
systemctl daemon-reload

设置开机自启并启动:

bash 复制代码
systemctl enable --now postgresql-16

看状态:

bash 复制代码
systemctl status postgresql-16

到这一步 Active: active (running) 就基本成了。如果状态是 active 但很快变成 failed,回去看第四节。

六、确认端口和数据目录都对上了

查监听端口:

bash 复制代码
ss -nltp | grep 5432

Rocky 9 最小化安装是不带 netstat 的(net-tools 要单独装),用 ss 更省事。

刚装完只会监听本地:

text 复制代码
LISTEN 0  244  127.0.0.1:5432  0.0.0.0:*  users:(("postgres",pid=xxxx,fd=5))
LISTEN 0  244      [::1]:5432     [::]:*  users:(("postgres",pid=xxxx,fd=5))

说明服务起来了,但还没对外,这是预期的。

确认数据目录是不是真的用上了:

bash 复制代码
sudo -u postgres psql -c "show data_directory;"

返回 /data/app/postgresql 才算对。如果这里还是 /var/lib/pgsql/16/data,说明 override 没生效,回去检查文件路径和 daemon-reload

再瞄一眼进程,确认 -D 参数:

bash 复制代码
ps -ef | grep '[p]ostgres' | head -1

应该能看到类似:

text 复制代码
/usr/pgsql-16/bin/postgres -D /data/app/postgresql

这两条命令看着重复,但其实查的是两件不同的事------前者是 PostgreSQL 自己认为数据目录在哪,后者是进程实际启动时用的参数。真出问题的时候,两者不一致是最常见的情况。

七、给 postgres 设密码

bash 复制代码
sudo -u postgres psql
sql 复制代码
ALTER USER postgres WITH PASSWORD '你的密码';
\q

本机走 TCP 测一下(这一步才会真正校验密码):

bash 复制代码
psql -h 127.0.0.1 -U postgres -d postgres -W

能进去,说明 scram-sha-256 这条链路是通的。

八、开放远程访问

要让别的机器连过来,三件事都得做:监听地址、pg_hba.conf、防火墙。少任何一样都连不上,而且报错长得都不一样,第九节会对照着说。

8.1 改监听地址

bash 复制代码
vi /data/app/postgresql/postgresql.conf

注意路径,不是 /var/lib/pgsql/16/data/postgresql.conf,自定义数据目录之后配置文件也跟着搬家了。

找到这一行:

ini 复制代码
#listen_addresses = 'localhost'

改成:

ini 复制代码
listen_addresses = '*'

如果这台机器有多块网卡,只希望业务网卡被监听,那就写具体 IP,比 '*' 更保险。

8.2 配 pg_hba.conf

同样在 /data/app/postgresql/ 下面:

bash 复制代码
vi /data/app/postgresql/pg_hba.conf

只放通 192.168.1.2 这一台:

ini 复制代码
host    all    postgres    192.168.1.2/32    scram-sha-256

要放整个网段:

ini 复制代码
host    all    postgres    192.168.1.0/24    scram-sha-256

能写 /32 就别写 /24。这条规则是放行语义,范围开多大,库就暴露多大。要是客户端网段不固定、随手写了 0.0.0.0/0,那基本等于把 5432 挂出去了。

另外,pg_hba.conf 的匹配规则是从上往下、第一条命中就生效 ,所以别随手把它塞在文件末尾,最好紧跟在已有的 host 规则后面,顺序自己心里有数。

8.3 放行防火墙

这台机器 firewalld 没启用,所以这一步跳过了。如果目标机器是默认配置(firewalld 开着),就算 PostgreSQL 已经监听在 0.0.0.0:5432,客户端那边还是 Connection timed out

只给业务服务器放行:

bash 复制代码
firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.1.2/32" port protocol="tcp" port="5432" accept'
firewall-cmd --reload
firewall-cmd --list-all

嫌 rich rule 麻烦,也可以 firewall-cmd --permanent --add-port=5432/tcp,但那是无差别放通,内网里也不建议。

8.4 让配置生效

改了 postgresql.conf 里的 listen_addresses必须重启 ;只改 pg_hba.conf 的话重载就够了:

bash 复制代码
systemctl reload postgresql-16

重载也可以走 SQL:

bash 复制代码
sudo -u postgres psql -c "SELECT pg_reload_conf();"

两个都改了就直接:

bash 复制代码
systemctl restart postgresql-16

九、客户端测试,以及三种报错怎么区分

在 192.168.1.2 上:

bash 复制代码
psql -h 192.168.1.x -U postgres -d postgres -W

报错 A:

text 复制代码
致命错误: 没有用于主机 "192.168.1.2", 用户 "postgres",
数据库 "postgres", no encryption 的 pg_hba.conf 记录

看到这句其实是个好消息------数据库已经收到你的连接请求了。防火墙、listen_addresses 都没问题,纯粹是 pg_hba.conf 里没有匹配的规则。

顺便注意里面的 no encryption。PG16 的客户端默认会去协商 SSL,服务端没配 SSL 就回落成明文,日志里就带上这个标记。host 类型的规则同时匹配加密和非加密连接,所以不会因此不匹配;但如果写成 hostssl,明文连接永远命不中,就会一直报这句------这是个挺隐蔽的坑。

补上对应的 host 行,systemctl reload postgresql-16,再连即可。

报错 B:

text 复制代码
could not connect to server: Connection timed out

这个跟 pg_hba.conf 一点关系都没有,连接根本没到数据库。回去查两件事:firewalld 有没有放行 5432、listen_addresses 是不是还停在 localhost

报错 C:

text 复制代码
FATAL:  password authentication failed for user "postgres"

规则匹配上了,是密码或者认证方式的问题。pg_hba.conf 里写的是 scram-sha-256,但密码是用 md5 方式存的老密码,或者密码本身输错了,都会是这一条。

这三种报错分别对应网络层、HBA 层、认证层,定位的时候先看是哪一个,能省不少时间。

十、业务程序别用 postgres 超级用户

postgres 是超级用户,业务程序拿它连库,等于给了应用侧删库跑路的能力。建个业务用户和业务库:

bash 复制代码
sudo -u postgres psql
sql 复制代码
CREATE USER appuser WITH PASSWORD '业务用户密码';
CREATE DATABASE appdb OWNER appuser ENCODING 'UTF8';
\q

应用侧拿到这些信息就够了:

text 复制代码
host:192.168.1.x
port:5432
db:  appdb
user:appuser

再在 pg_hba.conf 里给它单独一条,只允许业务服务器连业务库:

ini 复制代码
host    appdb    appuser    192.168.1.2/32    scram-sha-256

这样就算 appuser 的密码泄了,也连不上 postgres 库,更动不了别的库。数据库名和用户名都写具体值,比 all all 保险得多。

bash 复制代码
systemctl reload postgresql-16

十一、几个常用参数

装完默认配置能跑,但有几个值是明显偏保守的。以 8GB 内存的机器为例,按下面这套调一下基本够用:

ini 复制代码
max_connections = 200
shared_buffers = 2GB
work_mem = 8MB
maintenance_work_mem = 512MB
effective_cache_size = 6GB
参数 默认值 建议取值 说明
max_connections 100 200 按应用连接池的上限给,不是越大越好,每个连接都有固定开销
shared_buffers 128MB 物理内存的 25% 左右 改完必须重启
work_mem 4MB 8~16MB 注意这是每个排序/哈希操作能用的内存,不是全局,给太大容易 OOM
maintenance_work_mem 64MB 256~512MB 建索引、VACUUM 时用,改完重载即可
effective_cache_size 4GB 物理内存的 50%~75% 只是给优化器的估算值,不实际占内存

改完看情况重启或者重载:

bash 复制代码
systemctl restart postgresql-16

这块不用一次调到位,上业务之后看实际情况再动更靠谱。

十二、日常会用到的几条命令

服务状态和开机自启:

bash 复制代码
systemctl status postgresql-16
systemctl is-enabled postgresql-16

端口:

bash 复制代码
ss -nltp | grep 5432

日志,启动失败的原因都在这儿:

bash 复制代码
journalctl -u postgresql-16 -n 100 --no-pager

实时跟:

bash 复制代码
journalctl -u postgresql-16 -f

几个常用查询:

bash 复制代码
sudo -u postgres psql -c "show data_directory;"      # 数据目录
sudo -u postgres psql -c "show listen_addresses;"    # 监听地址
sudo -u postgres psql -c "select version();"         # 版本
sudo -u postgres psql -l                             # 库列表

十三、最终的文件布局

数据目录:

text 复制代码
/data/app/postgresql/
├── base/
├── global/
├── pg_wal/
├── pg_tblspc/
├── postgresql.conf
├── pg_hba.conf
└── ...

systemd override:

text 复制代码
/etc/systemd/system/postgresql-16.service.d/override.conf

内容:

ini 复制代码
[Service]
Environment=PGDATA=/data/app/postgresql

十四、验收顺序

改完配置之后建议按这个顺序过一遍,出问题好定位:

bash 复制代码
systemctl status postgresql-16
ss -nltp | grep 5432
sudo -u postgres psql -c "show data_directory;"
sudo -u postgres psql -c "select version();"

如果开了远程访问,在客户端上再加一步:

bash 复制代码
psql -h 192.168.1.x -U appuser -d appdb -W

这几条都正常,就说明安装、初始化、自定义数据目录、开机自启、远程访问这一整套都通了。

十五、几个容易踩的坑

  1. 忘了 dnf -qy module disable postgresql,装出来的包版本不对。
  2. 数据目录权限给成 755,PostgreSQL 直接拒绝启动,日志只有一句 permission denied。
  3. 只改了 systemd 的 override 但忘了 daemon-reloadPGDATA 没生效,数据跑到默认目录去了。
  4. pg_hba.conf 里写成 hostssl,明文连接永远匹配不上,一直报 no encryption 那条。
  5. SELinux 处于 Enforcing 且数据目录在 /data 下------本次环境已关闭没验证到,但默认配置的机器上大概率会中。
  6. firewalld 没放行 5432------本次同样未启用,默认配置的机器要留意。
  7. /data 如果是单独挂的盘,记得写进 /etc/fstab,不然下次重启机器 PGDATA 直接是空的,这个代价最大。
相关推荐
foolishlee4 小时前
SCRAM-SHA-256
数据库·算法·postgresql
IvorySQL16 小时前
IvorySQL 5.6 发布:PG 18.6 内核升级,沙盒即开即用
数据库·人工智能·postgresql
腾科IT教育17 小时前
PGCM考试详解:认证价值、含金量及与PGCA、PGCE区别
postgresql·pg·pgcm考试·pgca考试·pgce考试
Zhu75817 小时前
docker环境快速部署postgresql数据库18及以上版本
postgresql·容器
l1t1 天前
DeepSeek总结的 pgColumnar 1.0-alpha4 发布说明
数据库·postgresql
Logintern091 天前
“以一致的顺序获取锁“是预防死锁最核心、最有效的手段
python·postgresql·锁机制
风哥2号2 天前
数据库教程FGMT51‑PostgreSQL实例管理与参数文件
数据库·postgresql
lusklusklusk2 天前
Oracle索引组织表,SQLServer聚集索引,Mysql Innodb表的数据行不是在磁盘上像排队一样严格连续地存放
mysql·postgresql·oracle·sqlserver
redfred2 天前
Outline 部署教程:4 万 Star 自托管知识库,免费替代 Notion(Windows 源码部署完整指南)
postgresql·开源软件·notion