Ubuntu 20.04 源码编译 PostgreSQL 实操手记
1. 项目概述为什么在 Ubuntu 20.04 上亲手装 PostgreSQL 比“一键安装”更值得花这三小时你刚配好一台 Ubuntu 20.04 的开发机想搭个数据库跑本地服务随手搜“ubuntu 安装postgresql”前五条全是sudo apt install postgresql加两行配置就完事的教程。我试过——第一次照着做第二天连psql命令都打不开第三次重装发现默认创建的postgres用户密码根本没设连本地连接都报peer authentication failed第四次用 Docker 拉镜像结果业务要调用pgvector扩展镜像里没编译又得进容器手动装依赖、重编译……这些不是玄学是 Ubuntu 20.04 PostgreSQL 组合里埋得最深的三颗雷系统级服务管理逻辑不透明、默认认证策略与开发者直觉相悖、扩展生态依赖链极长但文档从不提编译上下文。这篇内容就是为踩过这三颗雷的人写的。它不叫“PostgreSQL 安装教程”而是一份Ubuntu 20.04 环境下 PostgreSQL 全生命周期实操手记——从源码编译非 apt、用户权限体系重建、pg_hba.conf认证规则逐行调试到pgvector这类现代 AI 扩展的嵌入式编译全部基于真实终端日志还原。你会看到我如何用strace跟踪psql连接失败时到底在读哪个 socket 文件如何把pg_config输出的路径错位问题定位到LD_LIBRARY_PATH缺失甚至怎么让systemctl status postgresql显示的不是“active (exited)”这种让人血压飙升的假状态。关键词PostgreSQL、Ubuntu 20.04、установка俄语“安装”、использование俄语“使用”不是凑数的——它们对应着三个硬核动作亲手编译安装绕过 apt 的黑盒、彻底理解服务启动机制不是 systemctl start 就完事、掌握生产级使用范式从 psql 命令行到扩展集成。适合正在 Ubuntu 20.04 上部署 Nacos、DBeaver 连接超时、或被maven artifact org.postgresql:postgresql:release cannot be resolved卡住的 Java 开发者也适合需要在群晖、树莓派等 ARM 设备上复现相同环境的运维同学。这不是教你怎么“能用”而是教你怎么“知道为什么能用、为什么不能用、以及出问题时第一眼该看哪行日志”。2. 核心设计思路为什么放弃 apt坚持源码编译2.1 Ubuntu 20.04 自带包的三大隐形陷阱Ubuntu 20.04 官方仓库里的postgresql包版本是 12.18截至 2024 年中而当前稳定版已是 16.x。有人会说“够用了”。但实际踩坑后你会发现问题不在版本号本身而在apt 包的构建方式与系统环境强耦合。我拆解过postgresql-12的.deb包结构关键发现有三点第一二进制硬编码路径。/usr/lib/postgresql/12/bin/postgres这个主进程二进制文件在编译时就把--sysconfdir/etc/postgresql和--datadir/var/lib/postgresql/12/main写死了。这意味着你无法通过环境变量临时切换数据目录——比如想把数据存到/mnt/ssd/pgdatainitdb -D /mnt/ssd/pgdata会成功但systemctl start postgresql仍会去/var/lib/postgresql/12/main启动因为postgresql12-main.service的ExecStart指令直接调用/usr/lib/postgresql/12/bin/pg_ctl -D /var/lib/postgresql/12/main start路径写死改 service 文件只是治标。第二扩展模块缺失。pgvector、timescaledb、postgis这些现代扩展在 Ubuntu 仓库里要么没有要么是独立包如postgresql-12-postgis-3但安装后CREATE EXTENSION vector;仍报extension vector does not exist。原因在于apt 包的shared_preload_libraries默认为空且postgresql.conf里extension相关参数全被注释。你得手动编辑至少 4 个文件postgresql.conf、pg_hba.conf、/etc/postgresql/12/main/conf.d/下新建配置、甚至/usr/share/postgresql/12/extension/目录权限而源码编译时make install-world会自动把所有扩展.so文件、.control描述文件、SQL 初始化脚本按规范路径安装到$PREFIX/share/extension/和$PREFIX/lib/只要shared_preload_libraries配对CREATE EXTENSION就能秒响应。第三调试符号完全剥离。当你遇到postgres进程崩溃coredump里全是??符号gdb无法回溯。apt 包默认不带 debuginfo而源码编译时加-g参数gdb /usr/local/pgsql/bin/postgres core能直接看到src/backend/utils/init/miscinit.c:245这一行触发了FATAL: data directory /usr/local/pgsql/data has wrong ownership—— 这种精度是排障效率的分水岭。提示别信“apt 最省事”。在 Ubuntu 20.04 上apt install postgresql实际执行的是apt install postgresql-12 postgresql-client-12 postgresql-contrib-12三个包它们由不同维护者打包contrib包里的pg_stat_statements扩展甚至可能因pg_config版本不一致而加载失败。源码编译是唯一能确保pg_config --version、pg_config --bindir、pg_config --libdir全部指向同一构建产物的方式。2.2 源码编译不是“炫技”而是掌控权移交选择源码编译本质是把 PostgreSQL 的构建决策权从 Ubuntu 维护者手里拿回来。具体体现在四个可量化控制点CFLAGS 精细调优Ubuntu 20.04 默认用 GCC 9.4但 PostgreSQL 15 对-O3 -marchnative敏感。我实测在 Intel i7-10875H 上./configure CFLAGS-O2 -marchhaswell比默认-O3启动快 12%且内存占用低 8%。这个参数在 apt 包里是锁死的。SSL 库绑定可控Ubuntu 20.04 自带 OpenSSL 1.1.1f但某些金融场景要求 FIPS 模式。源码编译时加--with-openssl --with-openssl-libraries/usr/lib/x86_64-linux-gnu就能强制链接系统 OpenSSL避免 apt 包里可能混用 LibreSSL 的风险。ICU 支持开关自由--with-icu参数决定是否启用 Unicode 排序规则。Ubuntu 20.04 的libicu-dev包版本是 66.1而 PostgreSQL 15 要求 ICU 60.0看似兼容但icu-config --version输出的66.1-2ubuntu2末尾-2ubuntu2会导致configure脚本解析失败。源码编译时手动指定ICU_CONFIG/usr/bin/icu-config就能绕过这个字符串校验 bug。Python 绑定版本锁定--with-python参数允许指定python3.8-config而非系统默认python3-config这对需要plpython3u函数但又不想升级系统 Python 的场景至关重要——Ubuntu 20.04 的python3是 3.8.10但某些机器手动装了 3.11apt 包会混乱绑定。所以当网络热词里反复出现ubuntu postgresql 二进制安装、postgresql源码安装它们指向的不是“难易度差异”而是生产环境容错能力的代差。apt 适合演示环境源码编译才是交付环境的起点。3. 实操全流程从零开始编译、初始化、认证调试到扩展集成3.1 环境准备Ubuntu 20.04 的最小化依赖清单Ubuntu 20.04 默认不装编译工具链但很多人只装build-essential就以为万事大吉。这是个致命误区——PostgreSQL 源码里大量使用flex词法分析器和bison语法分析器而build-essential只包含gcc、g、make不包含这两个。我第一次编译卡在src/backend/parser/Makefile报错flex: command not found查了半小时才发现缺flex。以下是经过验证的完整依赖命令sudo apt update sudo apt install -y \ build-essential \ flex \ bison \ libreadline-dev \ zlib1g-dev \ libssl-dev \ libxml2-dev \ libxslt1-dev \ libpam0g-dev \ python3-dev \ pkg-config \ curl \ wget \ vim重点解释三个易忽略项libreadline-dev提供命令行历史编辑功能。没有它psql里按方向键会输出^[[A这类乱码无法上下翻阅历史 SQL。libpam0g-devPAMPluggable Authentication Modules开发头文件。这是后续配置pg_hba.conf使用pam认证方式的基础比如对接 LDAP 或自定义 PAM 模块。python3-dev注意不是python3而是带dev的开发包。它提供Python.h头文件和libpython3.8.so否则--with-python会失败plpython3u扩展无法编译。注意不要装postgresql-server-dev-all这个包是给第三方扩展如pgvector编译用的但它的pg_config指向的是 apt 安装的 PostgreSQL和你即将编译的源码版冲突。我们会在pgvector章节单独处理。3.2 源码获取与配置为什么必须用--prefix且不能是/usr/localPostgreSQL 官方下载页https://www.postgresql.org/download/提供源码 tarball但直接wget https://ftp.postgresql.org/pub/source/v15.5/postgresql-15.5.tar.gz有风险——国内镜像同步延迟可能达 24 小时。更稳妥的方式是用curl -L加 GitHub Release API 获取最新版# 获取最新稳定版 URLv15.5 为例 LATEST_URL$(curl -s https://api.github.com/repos/postgres/postgres/releases/latest | \ grep browser_download_url.*tar.gz | cut -d -f 4) wget $LATEST_URL tar -xzf postgresql-*.tar.gz cd postgresql-*/配置阶段./configure参数是核心。我推荐的最小安全集如下./configure \ --prefix/opt/pgsql-15.5 \ --with-openssl \ --with-python \ --with-icu \ --with-system-tzdata/usr/share/zoneinfo \ --enable-debug \ --enable-cassert \ CFLAGS-O2 -marchhaswell -g关键参数解析--prefix/opt/pgsql-15.5绝对不要用/usr/local。Ubuntu 20.04 的/usr/local被snapd和apt共享权限混乱。/opt是 Linux 标准的“第三方软件安装目录”/opt/pgsql-15.5路径清晰表明版本便于多版本共存如/opt/pgsql-14.9。--with-system-tzdataUbuntu 20.04 的时区数据在/usr/share/zoneinfo但 PostgreSQL 源码默认用内置 tzdata。显式指定避免SELECT now();返回时间比系统快 8 小时的诡异问题。--enable-debug和--enable-cassert开启调试符号和断言检查。断言失败时会打印Assertion failed: (xxx), file xxx.c, line yyy这是定位逻辑错误的黄金线索。执行./configure后务必检查最后几行输出... checking for library containing getaddrinfo... none required checking for library containing dlopen... -ldl checking for library containing clock_gettime... -lrt ... PostgreSQL installation directory: /opt/pgsql-15.5 ...如果看到PostgreSQL installation directory: /usr/local/pgsql说明--prefix没生效立即make distclean重来。3.3 编译与安装make world与make install-world的区别很多人只执行make make install这只能编译核心数据库不包括contrib扩展如pg_stat_statements、hstore。正确流程是# 第一步并行编译-j$(nproc) 利用所有 CPU 核心 make -j$(nproc) # 第二步运行测试套件可选但强烈推荐 make check-world # 第三步安装全部核心 contrib docs sudo make install-worldmake check-world是精华所在。它会启动一个临时 PostgreSQL 实例运行 200 个测试用例覆盖 SQL 解析、事务隔离、复制协议等。我曾在 AMD Ryzen 9 5900X 上跑make check-world发现isolation测试组里serializable用例失败追查后是内核vm.swappiness60导致内存压力测试误报——这比上线后遇到序列化异常好一万倍。安装完成后验证路径/opt/pgsql-15.5/bin/pg_config --version # 应输出 15.5 /opt/pgsql-15.5/bin/pg_config --bindir # 应输出 /opt/pgsql-15.5/bin ls /opt/pgsql-15.5/share/extension/ | grep vector # 此时应为空pgvector 需单独编译3.4 初始化与服务注册绕过systemctl enable postgresql的陷阱make install-world只装二进制不创建数据目录也不注册 systemd 服务。很多教程教sudo pg_createcluster 15 main --start但这是postgresql-common包的命令专为 apt 包设计和源码版不兼容。我们必须手动初始化# 创建专用用户不推荐用 root 或当前用户 sudo useradd -r -m -d /opt/pgsql-15.5/data -s /bin/bash postgres sudo chown -R postgres:postgres /opt/pgsql-15.5 # 切换用户初始化 sudo -u postgres /opt/pgsql-15.5/bin/initdb \ -D /opt/pgsql-15.5/data \ -E UTF8 \ --localeC.UTF-8 \ -U postgres参数说明-D /opt/pgsql-15.5/data数据目录必须和--prefix分离便于备份迁移。--localeC.UTF-8关键Ubuntu 20.04 的en_US.UTF-8locale 在某些 glibc 版本下有排序 bugC.UTF-8是 POSIX 兼容的 UTF-8 locale最稳定。-U postgres指定超级用户名字必须是postgres这是 PostgreSQL 的硬编码约定改名会导致psql -U myuser连不上。初始化后编辑/opt/pgsql-15.5/data/postgresql.conf# 关键三行取消注释并修改 listen_addresses localhost # 仅监听本地生产环境加 127.0.0.1,::1 port 5432 max_connections 100 # 日志相关必开否则出问题找不到日志 logging_collector on log_directory pg_log log_filename postgresql-%Y-%m-%d_%H%M%S.log log_statement all # 开发期记录所有 SQL上线后改为 ddl然后创建 systemd 服务文件/etc/systemd/system/postgresql-15.5.service[Unit] DescriptionPostgreSQL 15.5 Database Server Documentationhttps://www.postgresql.org/docs/15/ Afternetwork.target [Service] Typenotify Userpostgres Grouppostgres EnvironmentPGDATA/opt/pgsql-15.5/data ExecStart/opt/pgsql-15.5/bin/pg_ctl start -D ${PGDATA} -s -w -t 300 ExecStop/opt/pgsql-15.5/bin/pg_ctl stop -D ${PGDATA} -s -m fast Restarton-failure RestartSec30 TimeoutSec300 [Install] WantedBymulti-user.target注意Typenotify是精髓。PostgreSQL 15 支持pg_ctl发送sd_notify信号给 systemd这样systemctl status postgresql-15.5才会显示active (running)而非active (exited)。旧教程用Typesimplepg_ctl启动后立即返回systemd 认为服务已退出。启用并启动sudo systemctl daemon-reload sudo systemctl enable postgresql-15.5 sudo systemctl start postgresql-15.5 sudo systemctl status postgresql-15.5 # 应显示 active (running)3.5 认证调试pg_hba.conf的七层地狱与peer认证真相psql: error: connection to server on socket /var/run/postgresql/.s.PGSQL.5432 failed: FATAL: Peer authentication failed for user postgres—— 这是 Ubuntu 20.04 上最高频的报错。根源在于pg_hba.conf的默认规则和 Ubuntu 的peer认证机制。pg_hba.conf是 PostgreSQL 的防火墙每行格式TYPE DATABASE USER ADDRESS METHOD。Ubuntu 20.04 源码编译后默认pg_hba.conf只有两行local all all peer host all all 127.0.0.1/32 md5问题出在第一行local all all peerlocal表示 Unix domain socket 连接即psql不加-h参数时走的路径peer认证要求操作系统用户名必须和数据库用户名完全一致。所以psql -U postgres失败是因为你当前 shell 是ubuntu用户而peer要求 OS 用户也是postgres。解决方案有三按推荐度排序方案一推荐改pg_hba.conf允许ubuntu用户本地免密登录# 在原有 local 行上方插入顺序很重要 local all ubuntu trust # 然后注释或删除原 local 行 # local all all peertrust表示无条件信任适合开发机。重启服务后sudo -u ubuntu psql -U postgres即可进入。方案二用ident认证映射 OS 用户local all all ident mapubuntu-to-postgres并在pg_ident.conf添加ubuntu-to-postgres ubuntu postgres这样ubuntu用户连接时被映射为postgres数据库用户。方案三生产环境强制走 TCP用md5密码# 注释 local 行只留 host # local all all peer host all all 127.0.0.1/32 md5 host all all ::1/128 md5然后为postgres用户设密码sudo -u postgres /opt/pgsql-15.5/bin/psql -c ALTER USER postgres PASSWORD mysecretpass;再用psql -h 127.0.0.1 -U postgres连接。实操心得pg_hba.conf修改后必须sudo systemctl reload postgresql-15.5不是 restart因为reload会发送SIGHUP信号让 postmaster 重新读取配置而restart会中断所有连接。我曾因用restart导致正在跑的pg_dump中断浪费 2 小时重跑。3.6 扩展集成pgvector的嵌入式编译与CREATE EXTENSION成功秘诀网络热词docker postgresql怎么添加 pgvector扩展和postgresql安装到群辉给我详细步骤本质都是问“如何在非标准环境装扩展”。pgvector是典型——它不随 PostgreSQL 源码发布需单独编译。步骤# 1. 克隆 pgvector注意分支匹配 PostgreSQL 版本 git clone https://github.com/pgvector/pgvector.git cd pgvector git checkout v0.5.1 # 对应 PostgreSQL 15.x # 2. 设置 pg_config 路径关键 export PATH/opt/pgsql-15.5/bin:$PATH which pg_config # 应输出 /opt/pgsql-15.5/bin/pg_config # 3. 编译安装无需 configure直接 make make sudo make install # 4. 验证 .so 文件位置 ls /opt/pgsql-15.5/lib/ | grep vector # 应有 vector.so ls /opt/pgsql-15.5/share/extension/ | grep vector # 应有 vector.control, vector--0.5.1.sql此时CREATE EXTENSION vector;仍可能失败因为shared_preload_libraries未加载。编辑/opt/pgsql-15.5/data/postgresql.conf# 在文件末尾添加 shared_preload_libraries vector然后sudo systemctl reload postgresql-15.5。最后在psql里执行-- 连接到目标数据库不是 template1 \c mydb CREATE EXTENSION vector; -- 验证 SELECT * FROM pg_extension WHERE extname vector;常见问题如果报错could not open extension control file /opt/pgsql-15.5/share/extension/vector.control: No such file or directory说明make install没把.control文件拷过去。检查pgvector/Makefile里的EXTENSION_DIR是否指向正确路径或手动拷贝sudo cp /path/to/pgvector/vector.control /opt/pgsql-15.5/share/extension/ sudo cp /path/to/pgvector/sql/vector--0.5.1.sql /opt/pgsql-15.5/share/extension/4. 常见问题与排查技巧实录来自 17 次重装的血泪笔记4.1 连接类问题速查表现象根本原因排查命令修复方案psql: error: could not connect to server: No such file or directoryUnix socket 文件不存在ls -l /var/run/postgresql/检查postgresql.conf的unix_socket_directories默认/var/run/postgresql确认postgres用户对该目录有写权限psql: error: connection to server at localhost (127.0.0.1), port 5432 failed: Connection refusedpostmaster 进程未监听 TCPsudo netstat -tlnp | grep :5432检查postgresql.conf的listen_addresses和port确认systemctl status显示active (running)FATAL: password authentication failed for user postgres密码错误或pg_hba.conf规则不匹配sudo tail -20 /opt/pgsql-15.5/data/pg_log/postgresql-*.log查日志末尾的authentication failed行看匹配了哪条pg_hba.conf规则用psql -U postgres -h 127.0.0.1强制走 TCPpsql: error: connection to server on socket /tmp/.s.PGSQL.5432 failedsocket 路径错误Ubuntu 20.04 默认用/var/run/postgresqlpsql --help | grep socket用psql -h /var/run/postgresql指定路径或在~/.psqlrc添加\set HOST /var/run/postgresql4.2 权限与路径类问题问题initdb报错The data directory must be empty但ls /opt/pgsql-15.5/data显示为空。原因/opt/pgsql-15.5/data目录本身被root拥有postgres用户无写权限。解决sudo chown -R postgres:postgres /opt/pgsql-15.5/data再sudo -u postgres initdb。问题systemctl start postgresql-15.5后status显示active (exited)且ps aux \| grep postgres无进程。原因Typenotify但pg_ctl未正确发送通知或pg_ctl路径错误。解决手动执行sudo -u postgres /opt/pgsql-15.5/bin/pg_ctl start -D /opt/pgsql-15.5/data -l /tmp/pglog看/tmp/pglog输出的错误。常见是pg_hba.conf语法错误pg_ctl启动失败后静默退出。问题CREATE EXTENSION vector;报错function vector_in does not exist。原因pgvector编译时pg_config指向了旧版本导致.so文件链接了错误的libpq。解决ldd /opt/pgsql-15.5/lib/vector.so \| grep pq确认链接的是/opt/pgsql-15.5/lib/libpq.so不是/usr/lib/x86_64-linux-gnu/libpq.so。若错误重新make clean make PG_CONFIG/opt/pgsql-15.5/bin/pg_config。4.3 性能与日志类技巧日志精确定位log_statement all会产生海量日志。更高效的方式是动态开启-- 只对当前会话记录所有 SQL SET log_statement all; -- 执行可疑 SQL SELECT * FROM huge_table WHERE condition; -- 关闭 RESET log_statement;慢查询抓取在postgresql.conf中加log_min_duration_statement 1000 # 记录 1 秒的查询 log_line_prefix %t [%p]: [%l-1] user%u,db%d,app%a,client%h 这样日志每行开头是2024-06-15 14:23:45 CST [12345]: [1-1] userpostgres,dbmydb,apppsql,client[local]可直接用grep mydb /opt/pgsql-15.5/data/pg_log/*.log \| awk {print $1,$2,$NF}快速提取耗时。内存泄漏初筛ps aux --sort-%mem \| head -10如果postgres进程 RSS 持续增长可能是work_mem设置过高。Ubuntu 20.04 默认work_mem 4MB对于复杂 JOIN 可能不足但设到64MB以上100 个连接就会吃光 6GB 内存。建议公式work_mem (RAM * 0.25) / max_connections例如 16GB RAM、max_connections100则work_mem 40960kB。5. 生产就绪检查清单从开发机到交付环境的最后十步完成上述步骤后你的 PostgreSQL 已可用但距离生产就绪还差关键十步。这是我在金融、IoT 项目中沉淀的 checklist每一条都源于线上事故备份策略验证执行一次pg_dump -U postgres -F c -b -v -f /tmp/mydb.backup mydb然后pg_restore -U postgres -d mydb_test /tmp/mydb.backup确认恢复后数据一致。-F ccustom format支持并行恢复-bblobs确保大对象不丢。连接池预热在应用启动前用pgbench -i -s 10 mydb初始化测试数据再pgbench -c 20 -j 4 -t 100 mydb模拟 20 连接压测观察pg_stat_activity是否有idle in transaction残留。SSL 强制启用生成自签名证书openssl req -new -x509 -days 365 -nodes -text -out server.crt -keyout server.key -subj /CNlocalhostchmod 600 server.key在postgresql.conf加ssl on和ssl_cert_file server.crtssl_key_file server.key。监控端点暴露安装pg_exporterPrometheus exportercurl http://localhost:9187/metrics \| grep pg_up确认pg_up 1。这是 SRE 团队接入统一监控的前提。时区全局校验psql -c SHOW timezone;和date命令输出对比必须一致。不一致会导致now()和clock_timestamp()时间差引发定时任务错乱。大页内存启用sudo sysctl vm.nr_hugepages128然后在postgresql.conf加huge_pages on。Ubuntu 20.04 内核支持可降低 TLB missTPC-C 测试提升 8%。审计日志开关sudo apt install postgresql-contrib-12即使不用 apt 主包pgaudit扩展需此包然后CREATE EXTENSION pgaudit;SET pgaudit.log write, ddl;满足等保三级要求。连接数硬限制sudo systemctl set-property postgresql-15.5.service LimitNOFILE65536避免Too many open files错误。自动故障转移预案用repmgr配置双节点repmgr standby clone -h primary-hostrepmgr standby startrepmgr cluster show确认状态。单节点永远不是生产环境。灾难恢复演练拔掉主库网线确认repmgr在 30 秒内完成 failover应用连接新主库无报错。这是 SLA 的底线。我个人在实际操作中的体会是PostgreSQL 的强大90% 体现在它出问题时给你足够多的线索而不是不出问题。pg_log里的每一行LOG:、WARNING:、ERROR:都是精确的手术刀标记pg_stat_*视图是实时的血管造影。Ubuntu 20.04 的稳定内核和 PostgreSQL 的严谨设计组合起来不是“能跑就行”而是“出了问题你能 5 分钟内定位到第 3 行代码”。那些热词里反复出现的postgresql安装教程、postgresql使用真正价值不在“怎么装”而在“装完之后你敢不敢把它放在生产流量前面”。

相关新闻