尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

银河麒麟V10 ARM架构离线安装PostGIS:从依赖管理到源码编译

银河麒麟V10 ARM架构离线安装PostGIS:从依赖管理到源码编译 上个月帮人处理一台飞腾平台的银河麒麟V10要求离线装PostGIS做空间数据入库。机器没外网apt和yum全是废的源码包倒是拷进U盘了结果真正折腾了两天。配置文件、依赖库、编译选项、扩展加载一个接一个坑排队等着。后来把整个过程复盘了一遍发现大部分问题其实都出在三个地方没搞清麒麟系统是继承自哪条Linux主线、没理顺PostGIS底层依赖链、没搞明白扩展机制去哪个目录找文件。这篇文章就把这套ARM架构下的离线安装弯路全写出来给后来人省点时间。1. 先认清环境麒麟V10的“血统”决定后续一切做法1.1 银河麒麟V10的两种分支Ubuntu系与CentOS系很多人拿到麒麟系统第一反应就是“这是个国产Linux”然后直接开始敲命令。这个问题在在线环境里可能不明显因为发行版自带工具会帮你兜底但在离线环境下你连包管理器都用不对后面全白搭。银河麒麟V10实际有两条技术路线一条基于Ubuntu常见的是18.04/20.04的底子包管理走apt另一条继承自CentOS常见V10 SP1/SP2包管理走yum。这两条路线的依赖名、仓库结构、库文件路径差异很大比如Ubuntu系里PostgreSQL的扩展目录是/usr/share/postgresql/12/extension而CentOS系可能放在/usr/share/pgsql/extensionrpm包叫postgresql12-server-develdeb包叫postgresql-server-dev-12。这些差异在联网环境会被包管理器自动消化离线环境全靠人肉判断。判断方法很简单开个终端逐条执行cat /etc/os-release cat /etc/kylin-release which apt apt-get 2/dev/null which yum 2/dev/null uname -m cat /proc/cpuinfo | grep -i model | head -5os-release里如果出现IDubuntu或者VERSION_CODENAME字段说明走apt系如果IDkylin但ID_LIKEcentos fedora说明走的是rpm系。uname -m输出aarch64就是ARM 64位架构飞腾FT-2000/64、飞腾腾锐D2000、鲲鹏920这一类的芯片都是这个输出。提示不要凭机器外观或系统截图里的“银河麒麟”字样判断一定要进命令行确认包管理类型。两台都是“银河麒麟V10”的机器可能一台用apt一台用yum离线包准备错了直接浪费时间。1.2 确认自带PostgreSQL版本与扩展目录PostGIS不是独立数据库它是PostgreSQL的扩展插件版本必须和PostgreSQL版本匹配。PostGIS 3.3官方支持PG 11到15PostGIS 3.4支持PG 12到16装之前先确认库版本否则后面要么编译不过要么创建扩展时报错。# 查看已装PostgreSQL服务端版本 ls /usr/lib/postgresql/ # Ubuntu系常见路径 rpm -qa | grep postgresql # CentOS系 psql --version postgres --version同时还要确认pg_config的位置编译PostGIS时必须用--with-pgconfig把路径指给它which pg_config pg_config --version pg_config --sharedir pg_config --pkglibdirpg_config --sharedir返回的路径下面有一个extension目录PostGIS编译安装后会把postgis.control、postgis--3.3.2.sql这些文件放进去--pkglibdir对应so动态库的落位目录。这两个路径是排查“扩展文件找不到”类报错的关键。2. 离线安装路线的选择为什么不推荐硬塞rpm/deb包2.1 三条路线的对比与最终选型我在离线环境装PostGIS试过三条路直接找编译好的rpm/deb包、用容器镜像离线搬运、源码编译安装。路线优点坑点适用场景rpm/deb二进制包安装快依赖由包管理器处理ARM架构下官方源很少有PostGIS第三方源依赖不完整麒麟源不一定有源里有现成包、依赖恰好全在时Docker容器离线导入环境隔离好避开系统依赖问题需要先有docker环境ARM镜像要自己拉PostGIS容器与外部网络/数据卷要额外配置允许容器化部署的场景源码编译依赖可控、可定制最稳耗时长需要自己管理GEOS/GDAL/Proj等前置库离线ARM环境的首选实话说如果你能搞到和目标机器完全同版本麒麟、同架构的二进制包直接装是最快的。但实际操作中rpm包经常遇到依赖冲突deb包又经常缺这个缺那个光是libgdal一个库就能牵扯出一串版本依赖在隔离内网里补包补到怀疑人生。所以我把源码编译作为主线方案二进制包作为补充方案。2.2 核心依赖链梳理GEOS、GDAL、Proj分别管什么PostGIS不是一个小单体它站在一堆几何处理库的肩膀上关键是这些库之间还有依赖关系。离线编译前必须把这些弄清楚否则在configure阶段就会卡住。PostGIS的核心依赖有三个GEOS负责几何拓扑运算ST_Intersects、ST_Buffer、ST_Union这些空间计算函数全靠它。版本太老会导致部分函数不可用或结果异常。Proj负责坐标投影转换ST_Transform的底层实现没有它做不了坐标系转换。GDAL负责栅格数据和矢量数据格式的读写导入Shapefile、GeoTIFF都要用到它底层又依赖libtiff、libjpeg、libpng等一堆库。还有一个容易被忽略的libjson-c新版PostGIS处理GeoJSON数据时依赖它。编译时缺了它通常不会直接报致命错误但后续调用ST_GeomFromGeoJSON会莫名其妙失败检查半天才发现是编译时的老问题。建议的编译顺序先编译安装Proj再编译GEOS再编译GDAL最后编译PostGIS。因为PostGIS的configure脚本会去检查这些库的版本和头文件缺前置库时直接报checking for GEOS... no但即便它没报错运行时也可能因为so库路径问题崩掉。2.3 有网环境下如何准备ARM架构的离线包离线装包不意味着你完全不需要网络我们需要在另一台有网络的机器上把源和依赖包备齐。这里有个最容易踩的坑在x86机器上下载的deb/rpm包拷到ARM机器上根本装不了。离线包必须去ARM镜像源上拉。如果是Ubuntu系麒麟在有网的ARM机器或者配置了ARM模拟器上执行apt-get update mkdir -p /tmp/postgis-pkgs cd /tmp/postgis-pkgs apt-get download postgis postgresql-12-postgis-3 \ postgresql-server-dev-12 \ libgeos-dev libgdal-dev libproj-dev libjson-c-dev \ gcc make如果没法登录ARM机器下载可以手动改源。把/etc/apt/sources.list里的地址前缀从http://ports.ubuntu.comx86是archive.ubuntu.com换到ARM源然后直接下载。CentOS系麒麟用yumdownloader或--downloadonlymkdir -p /tmp/postgis-rpms yum install --downloadonly --downloaddir/tmp/postgis-rpms \ postgis postgresql12-server-devel \ geos-devel gdal-devel proj-devel json-c-devel注意离线环境即使把所有rpm/deb包拷进去了也可能因为依赖链层层套娃而缺包。比如PostGIS 3.3需要GDAL 3.2以上而系统源里的GDAL可能只有2.4这种情况下二进制包路线基本走不通直接切到源码编译。源码包的获取相对简单去PostGIS官网、GEOS官网、Proj官网、GDAL官网下载对应版本的tar.gz源码包即可。我当时带的版本是一套经过验证的组合PostGIS 3.3.2 GEOS 3.10.3 Proj 7.2.1 GDAL 3.4.1这个组合在ARM下编译没有大问题。3. 源码编译环节的ARM适配与炸点排查3.1 编译基础环境gcc、make与pg_config路径源码编译需要基础工具链。离线情况下先检查系统里有没有gcc和makegcc --version make --version如果没有你就得额外下载离线包。Ubuntu系麒麟需要下载gcc、g、make、build-essential以及postgresql-server-dev-XXCentOS系需要gcc、gcc-c、make、postgresql12-devel。devel包很重要里面包含PG的服务端头文件没有它PostGIS compile阶段直接找不到postgres.h。这里插一个ARM特有的情况飞腾和鲲鹏芯片虽然都是aarch64架构但具体微架构有差异。绝大多数情况下默认的-marcharmv8-a就够用了不需要手动指定更高指令集。如果你发现系统自带gcc版本较老编译某些新版本GDAL时报internal compiler error优先考虑换旧版GDAL而不是折腾编译器升级。3.2 configure、make、make install的标准姿势PostGIS编译安装的标准三步命令如下tar -xzf postgis-3.3.2.tar.gz cd postgis-3.3.2 ./configure \ --prefix/usr/local/postgis \ --with-pgconfig/usr/lib/postgresql/12/bin/pg_config \ --with-geosconfig/usr/local/geos/bin/geos-config \ --with-gdalconfig/usr/local/gdal/bin/gdal-config \ --with-projdir/usr/local/proj \ --without-raster make -j4 sudo make install--prefix是安装根目录.so和.sql文件会基于这个前缀展开到对应目录。--with-pgconfig告诉编译器用它来定位PG的头文件和扩展目录这个路径必须和你要加载扩展的那个PostgreSQL实例严格对应机器上有多个PG版本时尤其要小心。--with-geosconfig、--with-gdalconfig分别指向GEOS和GDAL的配置脚本。--without-raster是我个人习惯纯矢量数据处理的场景不需要栅格模块去掉可以避免GDAL依赖过多带来的连锁问题。如果确实需要ST_AsTIFF、ST_AsGDALRaster等栅格功能就别加这个参数。3.3 ARM环境下三个高频编译报错的处理报错一GEOS configuration file not found出现的典型场景是把GEOS源码单独装到了/usr/local但PostGIS的configure默认搜索路径覆盖不到。checking for GEOS... no configure: error: GEOS not found排查链路先确认GEOS是否编译安装成功ls /usr/local/bin/geos-config。执行/usr/local/bin/geos-config --version确认能输出版本号。在PostGIS的configure命令里明确加--with-geosconfig/usr/local/bin/geos-config。GEOS编译安装本身很简单源码目录里执行./configure make sudo make install即可但它有个隐藏依赖libstdcARM系统如果裁剪过基础包会出现undefined reference tostd::__cxx11::basic_string这类链接错误那就说明gcc工具链本身没装全。报错二unknown type name json_t编译到jsonutils.c时崩溃原因是缺libjson-c-dev。有些精简版麒麟系统默认不带这个头文件包。解决方法是源码编译安装json-ctar -xzf json-c-0.15.tar.gz cd json-c-0.15 mkdir build cd build cmake .. -DCMAKE_INSTALL_PREFIX/usr/local make sudo make install sudo ldconfigJson-C编译依赖cmake如果没装cmake还得先搞一个。所以我在准备离线包时会把工作做得细一点直接把你可能需要的所有编译工具列个清单备齐避免来回折腾。报错三make过程中被OOM杀掉现象是在ARM服务器上执行make -j8或make -j16时编译进程突然消失现场只留下gcc: fatal error: Killed signal terminated program cc1。ARM服务器核心数通常不少但单核性能和内存带宽有限尤其是一些配置了32核但只有16G内存的机器高并行编译直接吃满内存被内核OOM Killer干掉。解决方法是调低并行度make -j4 # 或者直接 make如果编译GDAL时还反复OOM可以切换到-O2优化级别降低内存峰值export CFLAGS-O2 -g0 ./configure ...4. 扩展加载与运行期配置真正让人头秃的地方4.1 CREATE EXTENSION postgis失败的几种原因编译安装完成后进入PostgreSQL创建扩展这一步会暴露大量问题CREATE EXTENSION postgis;最常见的几种报错could not open extension control file /usr/share/postgresql/12/extension/postgis.control说明扩展控制文件没有安装到PG路径或者找错了PG实例。查pg_config --sharedir返回的extension目录下是否有该文件没有就手动拷贝过去。could not load library /usr/lib/postgresql/12/lib/postgis-3.so: libgdal.so.26: cannot open shared object filePostgreSQL进程是系统的daemon用户启动时不会加载/usr/local/lib的默认搜索路径导致GDAL动态库找不到。这种情况通常出现在我们单独编译更新了GDAL但系统路径里没有软链或ld配置的时候。ERROR: function postgis_init_geometry_absorption() does not exist这类错误通常是PostGIS源码和版本不匹配或者扩展SQL文件里的函数定义和so库不一致。多见于把不同版本的PostGIS文件混着拷贝了。4.2 用ldd和ldconfig排查动态库加载问题遇到libgdal.so.26这种找不到so的问题用ldd看PostGIS扩展模块的依赖最直接ldd /usr/lib/postgresql/12/lib/postgis-3.so # 输出里会看到 libgdal.so.26 not found找到依赖位置后把库路径写入ld配置echo /usr/local/gdal/lib /etc/ld.so.conf.d/gdal.conf sudo ldconfig提示make install之后最好立刻执行ldd检查一遍so依赖不要等到数据库里报错再查。如果你用我前面推荐的“源码编译安装到/usr/local”方案这一步几乎必须做。这里有个判断技巧ldd输出里 not found是明确缺少的依赖 /usr/lib/aarch64-linux-gnu/libxxx.so则说明依赖已找到但路径可能和你预期不一致。如果加载库时提示版本不对如找不到libgdal.so.26而系统只有libgdal.so.28说明系统自带GDAL版本比编译时的高PostGIS用它编译的那个版本运行也会出问题。这本质上是个版本冲突问题需要把新版本的GDAL加入ld路径优先加载。4.3 验证安装结果从接受到空间函数全量自测扩展创建成功后不能就此收工。我的习惯是做个完整的验证逐条输出检查-- 查看PostGIS版本及编译时依赖版本 SELECT PostGIS_Full_Version(); -- 查看可用扩展 \dx -- 空间参考系统表是否可读 SELECT count(*) FROM spatial_ref_sys; -- 测试基本几何构造函数 SELECT ST_AsText(ST_GeomFromText(POINT(116.4 39.9), 4326)); -- 测试坐标系转换 SELECT ST_AsText(ST_Transform(ST_GeomFromText(POINT(116.4 39.9), 4326), 3857)); -- 测试缓冲区运算 SELECT ST_Area(ST_Buffer(ST_GeomFromText(POINT(0 0), 4326), 1.0));如果ST_Transform报错说找不到转换参数多半是spatial_ref_sys表的数据没导全。PostGIS的make install默认会把spatial_ref_sys.sql装到extension目录并自动导入但如果你手动拷贝文件可能漏掉这步需要单独执行psql -f /usr/share/postgresql/12/contrib/postgis-3.3/spatial_ref_sys.sql。5. 实操中遇到的典型坑与完整排查链路5.1 坑一apt/yum源头就是找不到postgis包刚在麒麟系统上尝试apt install postgis时是一切噩梦的开端。银河麒麟的软件仓库默认收录的GIS相关软件非常有限很多时候压根没有postgis包或者版本老旧。如果你硬要从默认源里翻翻到的概率极低而且就算翻到了3系PostGIS对系统库的版本要求也足以让老仓库无所适从。排查链路尝试apt search postgis确认源里有没有。如果source列表被清空或者只配置了本地的Kylin源需要手动加回系统对应的Ubuntu/CentOS源但离线环境往往不允许访问外网。结论默认源基本走不通直接放弃二进制包方案切到源码编译。这一步越早切换到源码编译越省时间。如果源里有旧版本PostGIS但版本太老比如只提供2.5以下的版本那还是不推荐装因为老版本和PostgreSQL 12以上版本的兼容性存在隐患空间索引操作正常但ST_Transform在新PG版本上可能报奇怪错误。5.2 坑二扩展明明装上去了pg_restore或系统重启后消失有次我装完扩展创建数据表导入数据全部正常。第二天机器重启登录psql一查空间表全打不开了报错说extension缺失。这个问题的根因是PostGIS的so和control文件虽然还在但PostgreSQL实例的dynamic_library_path没有指向我们安装的目录实例重启后加载扩展失败pg_restore时也找不到该扩展的定义。排查链路查SHOW dynamic_library_path;确认是否包含/usr/lib/postgresql/12/lib或我们自定义的/usr/local/postgis/lib。如果路径不对在postgresql.conf里修改dynamic_library_path或者把so库软链到PG默认的lib目录。确认安装到了正确的实例。有些机器上存在多个PG实例pg_config只有一个但ls /etc/postgresql/下可能有12、13两个目录每个实例有独立的extension和lib目录。你可以全装到一个地方也可以每个实例都带独立副本但千万别串。5.3 坑三GDAL版本冲突引发的运行期崩溃这个坑最隐蔽。系统本身自带了libgdal可能是2.4版本我们编译PostGIS时又源码安装了新版GDAL 3.4写到/usr/local/gdal。按理说ldconfig配置好就没问题但如果数据库进程是从某个脚本用特殊环境变量启动的或者PG库目录里有一份旧的libgdal.so加载顺序就会错乱最终导致PostGIS运行时崩溃或报ST_AsMVT等函数无法使用。排查链路lddPostGIS的so文件看实际加载的libgdal.so来自哪个路径。查看/etc/ld.so.conf.d/下哪些配置生效ldconfig -p | grep gdal。检查PG的lib目录里是否有旧版gdal库ls -la /usr/lib/postgresql/12/lib/ | grep gdal。如果发现加载了错误的GDAL不动系统自带的版本优先调整ld.so.conf.d里的搜索顺序让/usr/local/gdal/lib排在系统路径前面然后ldconfig。这个曾耗费我最长时间因为PostGIS编译、安装都很正常直到实际跑栅格数据的函数时才崩溃根本想不到是GDAL版本冲突这种底层问题。我把这次折腾过程中的高频问题整理成一个排查表方便现场对照症状根本原因快速定位方法解决方案apt无法定位postgis包麒麟软件仓库无此包apt search postgis切换源码编译方案configure报GEOS not foundGEOS未编译或路径未指定检查geos-config是否存在加--with-geosconfig参数编译报json_t未知类型缺少libjson-c-dev搜索json-c头文件源码编译安装json-cmake进程被killARM机器内存不足dmesg查OOM记录降低并行度或用-O2编译CREATE EXTENSION无法打开control文件扩展文件未安装到PG扩展目录ls $(pg_config --sharedir)/extension手动拷贝或重新make install加载so报libgdal找不到系统ld路径未包含GDAL路径ldd postgis-3.so加入ld.so.conf.d并ldconfig重启后扩展丢失扩展装到了错误PG实例或dynamic_library_path不对确认多实例、查dynamic_library_path修正路径或软链so运行期GDAL崩溃系统旧GDAL与新增GDAL冲突ldconfig -p查加载路径调整ld库搜索顺序5.4 坑四用错了PostGIS与PostgreSQL的版本组合PostGIS 3.x对PostgreSQL版本有明确要求。比如PostGIS 3.3虽然官方支持PG 11到15但在PG 11上编译就经常遇到头文件里某个结构体定义不匹配的问题而到了PG 16PostGIS 3.2以下的老版本基本不可能编译通过。很多人在离线环境里拿到了一个过老的PostGIS源码包PG又是较新版本configure阶段过了make阶段直接报错。排查链路先确认PG主版本psql --version。确认源码包版本和兼容矩阵。PostGIS官网的release notes里都有兼容性列表不妨花五分钟看一下。建议组合PG 12配PostGIS 3.2或3.3PG 13配PostGIS 3.2PG 14配PostGIS 3.3。这里顺便提一句PostGIS的git源码版本和release tarball版本在文件结构上有细微差别如果是从git clone的代码configure前需要先执行./autogen.sh这个又依赖autoconf系列工具没准备好又得去凑一堆包。所以离线环境下只认release tarball更省心。6. 一点实际经验总结如果你和我一样必须在内网ARM架构的麒麟系统上离线装PostGIS我的建议是分四步走第一花10分钟确认系统血统、PG版本、CPU架构这是后面所有决策的基础第二提前在有网机器上把源码包、编译工具链、所有依赖源码备齐多准备比少准备强第三严格按照Proj → GEOS → GDAL → PostGIS的顺序编译每一步都单独验证第四安装完成后立刻执行ldd检查so依赖并用SQL语句做完整功能自测。还有一个好用的技巧在开始操作之前把整个安装过程输出到一个日志文件# 全程记录出问题方便回溯 script -q install.log这个日志文件在出问题时的价值怎么强调都不为过尤其是到了第N次编译时你可以往前翻找出到底是哪个依赖版本变了导致的连锁问题。另外强烈建议在动手前备份postgresql.conf和pg_hba.conf两个配置文件别问为什么问就是改完忘记改回去整个库连不上被领导骂过。装完PostGIS只是开始后面还有空间索引调优、坐标系对齐、数据导入性能这些硬骨头。但至少扩展能跑起来PostGIS_Full_Version()能正常输出版本信息那个时刻的成就感还是值得的。
返回列表