PostgreSQL 12.0 Linux 源码编译安装与生产环境部署指南

发布时间:2026/10/2 3:27:06
PostgreSQL 12.0 Linux 源码编译安装与生产环境部署指南 最近又要在新环境上部署数据库我把这几年反复操作过的 PostgreSQL 12.0 在 Linux 上的安装流程完整梳理了一遍。很多朋友来问的第一句话都是“PostgreSQL 下载哪个版本合适”我的答案很直接除非你有功能强需求否则 12.0 是目前企业级环境里最稳、资料最全、坑几乎都被踩平的选择。这篇东西就是一份能直接照着操作的部署手册从编译参数、目录规划、initdb 初始化到 systemd 托管、远程访问配置、常见报错排查全部按真实生产环境的操作顺序写清楚。无论你是刚接触 PostgreSQL 的运维新人还是准备在公司内网搭一套测试库的开发者按这个流程走一遍基本不会翻车。1. 安装前想明白这四件事1.1 为什么选 PostgreSQL 12.0 而不是最新版PostgreSQL 的版本迭代节奏是每年一个大版本16、17 早就出来了但这不影响 12.0 在存量项目里的统治力。先说 12.0 到底带来了什么引自官方 Release Notes12.0 引入了 SQL/JSON 路径查询、分区表性能大幅优化、REINDEX CONCURRENTLY在线重建索引、pg_stat_progress_*系列视图让大操作可观测。这些能力对业务系统来说非常实用而且 12.x 是整个 PostgreSQL 历史上口碑最好的一条稳定线。很多云厂商的 RDS 产品在 2023 年前后仍默认提供 12.x 版本社区插件生态也大多适配到这个版本。选择 12.0 的另一个理由是排障资料足够多。版本太新遇到一个奇怪的 bug在搜索引擎里可能只有官方邮件列表里的几条讨论12.0 的报错、配置案例、优化方案论坛和博客里一抓一大把。生产环境最怕的不是功能不够而是出了问题没人能帮你定位。不过我也得说一句公道话如果是全新项目没有历史包袱直接上 16/17 也没毛病只是整个生态的兼容性需要你额外评估。这篇博文既然标题是 12.0那我们就把 12.0 吃透。1.2 三种安装方式怎么选PostgreSQL 在 Linux 下的安装方式大致有三条路线。第一种是发行版自带仓库安装比如 CentOS 7.9 用yum install postgresql-server。优点是一条命令装完缺点是版本普遍偏老。CentOS 7 自带的是 9.2老到你连scram-sha-256认证都用不了根本不适合现代业务。第二种是官方二进制包或 PGDG 仓库。PostgreSQL 官方提供了apt和yum的软件源能装到指定大版本。这种方案比编译省事也不需要你花半小时去configure、make。但它的安装目录、配置文件路径比较分散对于喜欢“一切尽在掌握”的运维来说反而少了点直观感。第三种是源码编译安装。这也是本篇文章采用的主方式。源码编译可以让你精确控制安装路径、编译参数、数据目录安装完整个 PostgreSQL 都集中在一个前缀目录下后续升级、卸载、迁移都非常清晰。缺点是编译过程需要依赖包齐全机器上必须有 gcc、make 等工具链。我的个人经验是生产环境用源码编译最踏实因为你能看到每一步在干什么。还有一种绕不开的方式是 Docker 安装。docker run -d -p 5432:5432 postgres:12.0五分钟就能跑起来一个实例。但容器化部署在生产库上要额外处理数据持久化、网络性能、日志采集等问题不适合作为唯一的方案来推荐。它更适合本地开发联调或者快速做版本对比实验。1.3 目录规划是后面所有操作的地基不要随手把数据目录放在安装目录下面。我最常推荐的布局是软件安装目录/usr/local/pgsql数据目录/data/pgsql/dataWAL 日志目录/data/pgsql/pg_wal运行日志目录/data/pgsql/log备份目录/data/pgsql/backup为什么数据目录要单独拎出来第一/data通常是单独挂载的数据盘读写性能和容量都和内网系统盘分开数据库 IO 压力不会拖垮操作系统第二以后要做磁盘扩容、迁移、快照备份直接操作/data/pgsql一个目录就行不需要去安装目录里刨数据文件第三如果哪天需要重装系统格式化系统盘不影响数据盘恢复成本低很多。还有一点要提前想清楚PostgreSQL 的服务进程绝不能以 root 身份运行。所以我们需要一个专有的操作系统用户一般叫postgres。所有数据文件的属主和属组都必须是它否则启动时会直接报权限错误。1.4 端口和环境变量的约定默认端口 5432这个没什么好说的。但如果机器上已经跑了一个 PostgreSQL 或者别的服务占用了 5432你再强行装就麻烦了。建议初始化之前先检查ss -lntp | grep 5432 ss -lntp | grep :5432没输出才是正常的。如果发现端口被占要么改 PostgreSQL 的编译默认端口要么等下改postgresql.conf的port参数。我习惯保持默认 5432因为后续接监控系统、备份工具时不用额外定制配置。环境变量建议统一追加到/etc/profile.d/postgres.sh内容如下export PATH/usr/local/pgsql/bin:$PATH export LD_LIBRARY_PATH/usr/local/pgsql/lib:$LD_LIBRARY_PATH export PGHOST/tmp export PGDATA/data/pgsql/data单独建一个 profile 文件而不是直接改/etc/profile这样系统更新或者重装时一目了然删掉一个文件就能清理干净。2. 环境准备这几个依赖缺一不可2.1 操作系统版本确认我主要基于 CentOS 7.9 和 Ubuntu 20.04 来写。先说怎么确认系统版本cat /etc/os-release uname -r内核版本要 3.10 以上CentOS 7.9 默认内核是 3.10满足要求。内存建议至少 2G磁盘剩余空间至少 10G这只是一个底线真实生产环境根据数据量放量。如果你手头是一台云主机直接用df -h和free -h检查一遍再继续。还要检查系统是否已经存在老版本的 PostgreSQLrpm -qa | grep -i postgres dpkg -l | grep -i postgres如果有残留包最好先卸载或者确认路径否则后面 initialize 时容易混。2.2 编译依赖一次性装齐源码编译最烦的一件事就是 make 到一半报xxx.h: No such file or directory。这是典型的依赖头文件缺失。PostgreSQL 的源码编译依赖 gcc、make、readline、zlib、openssl部分功能还需要 perl、python、libxml2、libxslt。CentOS 7.9 下执行yum install -y gcc make readline-devel zlib-devel openssl-devel \ perl-devel python3-devel libxml2-devel libxslt-devel flex bisonUbuntu 下是apt update apt install -y gcc make libreadline-dev zlib1g-dev libssl-dev \ libperl-dev python3-dev libxml2-dev libxslt1-dev flex bison有人会问少装几个行不行如果只跑基础 SQLreadline 和 zlib 必须装。readline-devel 提供 psql 的命令行历史记录、上下翻页功能zlib 是数据压缩的基础库pg_dump 的压缩备份依赖它。openssl 用来支持 SSL 连接和 SCRAM 认证加密。flex 和 bison 是源码包里的解析器生成工具如果不装configure 阶段可能能过但 make 阶段绝对会报错。而且这些东西装一次以后还能复用机器上以后编译别的开源项目也用得上所以别省这一步。2.3 创建 postgres 用户和数据目录用下面命令创建专用账号id postgres /dev/null 21 || useradd -m postgres-m参数会给 postgres 用户创建 home 目录后续一些工具可能用到。如果用户已经存在直接继续就行。然后创建目录结构mkdir -p /data/pgsql/{data,log,backup} chown -R postgres:postgres /data/pgsql chmod 700 /data/pgsql/datachmod 700非常关键PostgreSQL 对数据目录的权限要求很严格属主必须是 postgres权限位必须是 700 或者更小如果数据目录是 755 或者其他用户可读initdb 直接拒绝操作。2.4 下载源码包和签名校验下载地址最常用的是 PostgreSQL 官方 FTP 镜像cd /usr/local/src wget https://ftp.postgresql.org/pub/source/v12.0/postgresql-12.0.tar.gz wget https://ftp.postgresql.org/pub/source/v12.0/postgresql-12.0.tar.gz.sha256解压前最好校验一下 sha256sha256sum -c postgresql-12.0.tar.gz.sha256输出OK才代表文件完整。这个步骤容易被忽略但镜像源偶尔会有坏包或者下载过程中断点续传导致文件不完整到 make 阶段才报错回头查起来特别难受。解压tar -xzf postgresql-12.0.tar.gz cd postgresql-12.03. 编译安装与数据库初始化全记录3.1 configure 参数背后的逻辑这是最关键的一步直接决定安装出来的 PostgreSQL 具备哪些能力。我常用这串参数./configure --prefix/usr/local/pgsql \ --with-openssl \ --with-perl \ --with-python \ --with-libxml \ --with-libxslt \ --with-readline \ --with-pgport5432解释一下每个参数的含义--prefix/usr/local/pgsql指定安装根目录。所有可执行文件会进/usr/local/pgsql/bin库文件进/usr/local/pgsql/lib头文件进/usr/local/pgsql/include。用这个 prefix 的好处是卸载时删目录就行不会污染系统路径。--with-openssl开启 SSL 加密连接支持。生产库可以配置sslon加密客户端通信。--with-perl和--with-python启用 PL/Perl 和 PL/Python 存储过程语言。如果业务用不到可以不配但建议加上免得以后想扩展功能又要重新编译。--with-libxml和--with-libxslt提供 XML 和 XSLT 处理函数。--with-pgport5432把默认端口写进编译配置这能确保以后所有命令行工具在未指定-p时都知道默认端口。如果你不做国际化可以加--enable-nls支持多语言提示如果做调试分析加--enable-debug会保留符号信息但生产库一般不建议。configure 执行完以后要检查尾部输出出现configure: error就要先解决依赖不要硬往下走。3.2 make 编译的现场记录编译命令很简单make -j$(nproc)-j$(nproc)表示用机器上所有 CPU 核心并行编译。如果内存比较小比如只有 2G建议make -j2否则编译器进程太多会吃满内存导致整机卡死。整个编译过程大约需要 5 到 15 分钟。这个阶段最常见的报错就是缺少某个头文件或者 flex/bison 版本太低解决办法就是回到 2.2 节把依赖补齐然后重新跑 make。PostgreSQL 的 make 有断点续编能力重新执行make会从失败的地方继续不用清理重来。编译通过后执行make install安装完成检查一下ls -l /usr/local/pgsql/bin应该能看到initdb、pg_ctl、psql、pg_dump、pg_basebackup等一系列工具。这里还有一个容易漏掉的步骤安装 contrib 扩展模块。make -C contrib installcontrib 模块包括pg_stat_statements、uuid-ossp、postgres_fdw等常用扩展生产环境基本都会用到。如果当时没装以后想要某个扩展再进源码目录补一次即可。3.3 initdb 初始化数据库集群初始化前先切到 postgres 用户su - postgres然后执行/usr/local/pgsql/bin/initdb -D /data/pgsql/data \ -E UTF8 \ --localeen_US.UTF-8 \ -U postgres \ -W参数含义-D数据目录。-E UTF8数据库集群默认字符集为 UTF8。除非你的业务全是 GBK 老系统否则一律用 UTF8。--localeen_US.UTF-8排序和格式化规则。如果没有生成对应 locale会报could not find suitable locale。可以先执行localectl list-locales看看系统支持哪些。如果不想折腾直接--localeC也能过但排序规则和人类语言环境的预期可能不一致建议还是用 UTF8。-U postgres超级用户名。-W要求初始化后设置超级用户密码。安全起见一定要加。如果当前用户不是 postgresinitdb 会直接拒绝并且提示cannot be run as root。注意su - postgres时的-很重要它会加载 postgres 用户的环境变量如果上一步把 PATH 写进了/etc/profile.d/postgres.sh现在可以直接用initdb命令。初始化成功的标志是看到Success. You can now start the database server using: pg_ctl -D /data/pgsql/data -l logfile start。此时/data/pgsql/data下会自动生成base、global、pg_hba.conf、postgresql.conf等文件数据目录权限也会自动被设置为 700。3.4 手动启动一次验证先临时启动一次验证环境没问题pg_ctl -D /data/pgsql/data \ -l /data/pgsql/log/pg.log \ start用pg_isready检查状态pg_isready -h 127.0.0.1 -p 5432如果返回/tmp:5432 - accepting connections说明服务已经在运行。临时启动目的是快速确认数据目录没有别的问题真正要长期跑还得靠 systemd这个下一节讲。4. 配置 systemd 和核心参数让数据库托管起来4.1 编写 postgresql-12.service 服务文件手工pg_ctl start的问题是服务器重启后不会自动拉起而且进程脱离了 systemd 管控crash 了也没人管。正确做法是写一个 systemd unit。在/etc/systemd/system/postgresql-12.service写入[Unit] DescriptionPostgreSQL 12 database server Afternetwork.target [Service] Typeforking Userpostgres Grouppostgres EnvironmentPGDATA/data/pgsql/data ExecStart/usr/local/pgsql/bin/pg_ctl -D ${PGDATA} -l /data/pgsql/log/pg.log start ExecStop/usr/local/pgsql/bin/pg_ctl -D ${PGDATA} stop -m fast ExecReload/usr/local/pgsql/bin/pg_ctl -D ${PGDATA} reload TimeoutSec300 [Install] WantedBymulti-user.target关键点拆解TypeforkingPostgreSQL 的 pg_ctl 启动后由 postmaster 后台进程接管systemd 需要等待 fork 出来的主进程退出才算服务拉起成功。Userpostgres和Grouppostgres确保所有子进程都归属 postgres 用户避免数据文件产生 root 归属。ExecStop里的-m fast快速关闭模式回滚未提交事务后立即停止比-m immediate安全。日常维护一律用 fast。TimeoutSec300防止大库恢复时启动时间超时导致 systemd 误判。随后执行systemctl daemon-reload systemctl enable --now postgresql-12 systemctl status postgresql-12看到active (running)就完成了托管。以后维护库就用systemctl start/stop/restart postgresql-12不用再记着老长一串 pg_ctl 参数。4.2 postgresql.conf 最小调优参数安装默认配置是保守的能跑不代表能扛业务。核心几个参数必须手工调。先用free -h确认物理内存以一台 8G 内存的小型服务器为例推荐配置listen_addresses * port 5432 max_connections 200 shared_buffers 2GB effective_cache_size 6GB work_mem 8MB maintenance_work_mem 256MB wal_buffers 16MB checkpoint_completion_target 0.9 max_wal_size 2GB min_wal_size 512MB解释几个关键决策shared_buffersPostgreSQL 的共享缓冲池通常设为物理内存的 25%8G 内存设 2G 合理。太大反而会增加系统脏页写回压力不是越大越好。effective_cache_size这是给查询规划器用的“操作系统文件缓存共享缓冲池”总量估算值设为物理内存的 75% 左右比较合适。它不会真正分配内存只影响优化器选择索引扫描还是全表扫描。work_mem单个排序或哈希操作的内存上限。如果并发连接很多这个值不能贪大200 个连接每个分 8M最坏情况就是 1.6G 的临时内存开销能接受。max_wal_size控制 WAL 文件能增长到多大的阈值。太小会导致频繁 checkpointIO 抖动太大则故障恢复时间变长。改完配置后重启服务systemctl restart postgresql-12如果不想重启压测环境也可以用SELECT pg_reload_conf();热加载部分参数。但shared_buffers这类启动期参数必须重启才能生效。4.3 pg_hba.conf 远程访问配置与认证模型安装初期pg_hba.conf默认只监听本地且host all all 127.0.0.1/32 trust是免密登录这在生产环境是绝对不能接受的。先修改postgresql.conf的listen_addresses *让服务监听所有网卡。然后编辑/data/pgsql/data/pg_hba.conf按顺序把规则追加在文件末尾。顺序非常关键PostgreSQL 从上到下匹配第一条命中的规则所以精确的规则要写在宽松规则前面。推荐配置# 本地 Unix Socket使用系统用户和密码认证 local all postgres peer # 本地回环地址 host all all 127.0.0.1/32 scram-sha-256 # 内网网段 host all all 192.168.1.0/24 scram-sha-256 # 其他一律拒绝默认 host all all 0.0.0.0/0 reject认证方式我统一推荐scram-sha-256这是目前最安全的密码认证协议。md5已经过时trust只配用于纯本地开发环境。每行规则前面的local指 Unix Sockethost指 TCP/IP。密码加密层次不要混用否则客户端连接时会报SCRAM authentication相关错误。修改完后设置密码并重载psql -U postgres -c ALTER USER postgres PASSWORD strong_password; systemctl reload postgresql-124.4 端到端验证建库、建表、查询现在我们从客户端角度做一次完整验证。在本机用 psql 连接psql -h 127.0.0.1 -U postgres -d postgres输入密码进入交互终端以后执行CREATE DATABASE appdb; \c appdb CREATE TABLE t_user ( id serial primary key, name varchar(50) not null, created_at timestamp default now() ); INSERT INTO t_user(name) VALUES (张三),(李四); SELECT * FROM t_user;如果每一步都正常返回说明服务、认证、访问控制链路没问题。再从另一台内网机器用命令远程测试PGPASSWORDstrong_password psql -h 192.168.1.20 -U postgres -d appdb -c SELECT version();能打印出版本信息这单安装就算彻底打通了。5. 踩坑实录这些坑我基本都踩过一遍5.1 initdb 阶段报错层出不穷报错一could not find suitable locale原因操作系统没生成对应语言的 locale 数据。解决方法先查可用 localelocale -a如果有en_US.utf8就把 initdb 的 locale 换成en_US.UTF-8。如果你一定要zh_CN.UTF-8先用localedef生成或者直接安装glibc-langpack-zh包。报错二ERROR: data directory ... has invalid permissions原因/data/pgsql/data目录已经被提前创建而且权限不对。initdb 要求目标目录要么不存在要么所有者是 postgres 且权限 700。解决chown -R postgres:postgres /data/pgsql chmod 700 /data/pgsql/data注意不要把chmod随便给成 755否则连启动都会报错。报错三initdb: error: cannot be run as root太常见了。忘了切换用户解决方案就是su - postgres后再执行。如果你想安全一点用sudo -u postgres /usr/local/pgsql/bin/initdb ...也是一样效果。5.2 能启动但远程连不上这个现象我记得很清楚服务明明起来了从另一台机器psql -h ip就是卡住或报超时。按照顺序排查先查监听ss -lntp | grep 5432如果只显示127.0.0.1:5432说明listen_addresses没改或者忘了 reload 配置。改成*再 reload。再查防火墙CentOSfirewall-cmd --permanent --add-port5432/tcp firewall-cmd --reloadUbuntuufw allow 5432/tcp还有 SELinuxgetenforce如果 Enforcing执行setsebool -P httpd_can_network_connect_db 1或者给端口加上下文规则。最省事的方案是让安全团队开策略不要为了图省事直接关 SELinux生产环境这是大忌。最后再确认pg_hba.conf是否包含对应 IP 网段和scram-sha-256规则。很多人改了postgresql.conf但忘了改pg_hba.conf所以远端客户机会一直报no pg_hba.conf entry for host ....5.3 make 时缺头文件的一揽子问题编译阶段最常见的报错之一是fatal error: readline/readline.h: No such file or directory这就是 readline-devel 没装。类似还有zlib.h、openssl/ssl.h。所有依赖在前文 2.2 节一次性装齐能消灭 90% 的编译报错。如果看到flex: command not found或bison: command not found同样回去补装。我遇到过最刁钻的是系统里同时有多个版本的 openssl 头文件configure 时找到了不兼容的路径。此时可以显式指定 CPPFLAGS 和 LDFLAGS./configure --prefix/usr/local/pgsql \ CPPFLAGS-I/usr/include/openssl \ LDFLAGS-L/usr/lib64不过普通环境基本用不上写在这里只是留个排查线索。5.4 版本维护与数据迁移的几条经验12.0 只是基线后面建议至少升到 12.x 的最新小版本。小版本升级一般只修 bug不破坏兼容性过程很简单下载新源码包编译安装到同一个 prefix然后systemctl stop postgresql-12直接覆盖 bin 和 lib再启动即可。主要因为 PostgreSQL 的磁盘数据格式在同一个大版本内是稳定的不需要 dump/restore。跨大版本迁移比如 12 升到 15就需要用官方pg_upgrade工具或者老土的pg_dump全量导出导入。我的建议是可以提前做一次小范围演练因为生产库的扩展插件版本、用户权限、表空间路径稍微复杂一点直接冲可能出事。另外日常备份必须养成肌肉记忆pg_dump -Fc -h 127.0.0.1 -U postgres appdb /data/pgsql/backup/appdb_$(date %F).dump-Fc输出自定义压缩格式体积小兼容pg_restore灵活恢复。整套库备份则用pg_basebackup这个工具适合做物理备份和流复制基础备份。我在实际维护中还有一个小习惯装完 PostgreSQL 后顺手写一份README放在/data/pgsql里记录编译参数、初始密码更换日期、数据目录挂载点、备份策略。很多运维事故都是因为过了半年没人知道当初这台机器是怎么装的有个说明文档能省掉后面接手的人大量排查时间。这个安装流程我前前后后执行过几十次每次踩的坑其实都集中在依赖缺失、权限错乱和认证配置这三类问题上。只要严格按照顺序做PostgreSQL 12.0 从源码到可用服务半小时内一定能搞定。