FrankenPHP在信创环境下的适配

FrankenPHP在信创环境下的适配 FrankenPHP 在信创环境下的适配 — 完整实战指南先把话挑明:FrankenPHP 适配信创的核心难点不在 PHP,而在它的出身。FrankenPHP 不是传统的 PHP-FPM,它是用 Go 语言写的、通过 cgo 把 libphp 直接嵌进去的应用服务器(底层是 Caddy)。所以信创适配Go 工具链C 编译器PHP 源码 这三样都得在国产·CPU/OSo上跑通,这才是真正的坑。 下面用大白话把每一层讲透。---一、先搞懂 FrankenPHP 为什么适配难 传统部署:NginxPHP-FPM ←两个独立二进制,各发行版都有现成包,装上就行 FrankenPHP:单个二进制Caddy(Go)内嵌libphp(C)通过 cgo 粘在一起 ↑必须CGO_ENABLED1,必须有 Go 工具链gccPHP 源码/库 大白话:PHP-FPM 是别人编译好的现成软件,你 yum 一下就有。FrankenPHP 在信创环境大概率要自己从源码编译,因为官方发布的预编译二进制只有 linux/amd64 和 linux/arm64(glibc 还是新版的),国产环境要么 CPU 架构不对(龙芯),要么 glibc 太老(麒麟/UOS)。所以你必须掌握自己编译这条路。---二、信创 CPU/OS 适配难度矩阵(先定方案)CPU 架构 ┌────────────────────┬─────────────────────┬────────────────┬─────────────────┬────────────────────────────┐ │ 国产 CPU │ 实际架构 │ Go 支持 │ 难度 │ 说明 │ ├────────────────────┼─────────────────────┼────────────────┼─────────────────┼────────────────────────────┤ │ 海光 Hygon │x86_64(AMD Zen)│ 完美 │ ⭐ 最简单 │ 跟普通 x86 服务器一样 │ ├────────────────────┼─────────────────────┼────────────────┼─────────────────┼────────────────────────────┤ │ 兆芯 Zhaoxin │ x86_64 │ 完美 │ ⭐ 最简单 │ 同上 │ ├────────────────────┼─────────────────────┼────────────────┼─────────────────┼────────────────────────────┤ │ 鲲鹏Kunpeng(华为)│ARM64(aarch64)│ 完美 │ ⭐⭐ 简单 │ 标准 ARM64,官方有 arm64 包 │ ├────────────────────┼─────────────────────┼────────────────┼─────────────────┼────────────────────────────┤ │ 飞腾 Phytium │ ARM64 │ 完美 │ ⭐⭐ 简单 │ 同鲲鹏 │ ├────────────────────┼─────────────────────┼────────────────┼─────────────────┼────────────────────────────┤ │ 龙芯 Loongson │LoongArch(loong64)│1.19主线支持 │ ⭐⭐⭐⭐ 最难 │ ★真正的硬骨头,要源码编译 │ ├────────────────────┼─────────────────────┼────────────────┼─────────────────┼────────────────────────────┤ │ 申威 SW │SW64(类 Alpha)│ 几乎无 │ ⭐⭐⭐⭐⭐ 劝退 │ Go 不支持,基本走不通 │ └────────────────────┴─────────────────────┴────────────────┴─────────────────┴────────────────────────────┘ 操作系统 ┌────────────────────────────────┬────────────────┬─────────┬───────────────────────┐ │ 国产 OS │ 底层血统 │ 包管理 │ glibc 坑 │ ├────────────────────────────────┼────────────────┼─────────┼───────────────────────┤ │ 银河麒麟 KylinOSV10(服务器版)│ RHEL/CentOS 系 │ yum/dnf │ glibc 较老(2.28左右)│ ├────────────────────────────────┼────────────────┼─────────┼───────────────────────┤ │ 中标麒麟 │ RHEL 系 │ yum │ 同上 │ ├────────────────────────────────┼────────────────┼─────────┼───────────────────────┤ │ 统信 UOS │ Debian 系 │ apt │ glibc 视版本 │ ├────────────────────────────────┼────────────────┼─────────┼───────────────────────┤ │ Loongnix/AOSC(龙芯专用)│ Fedora/独立 │ dnf │ 配合 loong64 │ └────────────────────────────────┴────────────────┴─────────┴───────────────────────┘ 核心决策:-生产首选 海光(x86)或鲲鹏/飞腾(ARM64)——这俩是标准架构,适配几乎无痛。-**龙芯(LoongArch)**是真难,需要源码编译整条链,下面单独重点讲。-glibc 老的问题用**静态编译(musl)**绕过,后面讲。---三、方案 A:海光 x86/鲲鹏·飞腾ARM64(推荐主力)这俩是标准架构,Go 和 PHP 官方都原生支持,适配思路一样,只是 GOARCH 不同。3.1最省事:用静态编译版二进制(强烈推荐)FrankenPHP 官方对 amd64/arm64 提供全静态二进制(用static-php-climusl 编译,不依赖系统 glibc)。这能直接绕开麒麟/UOS 的 glibc 太老问题。 # 在麒麟/UOS 上,鲲鹏 ARM64 机器 curl-L https://github.com/php/frankenphp/releases/latest/download/frankenphp-linux-aarch64 \ -o frankenphpchmodx frankenphp./frankenphp version # 能跑就说明静态二进制兼容你的国产 OS # 海光 x86 机器就下 frankenphp-linux-x86_64 大白话:静态二进制把 PHP、所有 C 库、glibc 全打包进一个文件了(用的 musl libc,不依赖系统库)。所以不管你麒麟的 glibc 多老,它都能跑。这是信创适配最快的捷径——能下载就别自己编译。 ▎ ⚠️注意:静态二进制内置的扩展是固定的一套(curl/pdo_mysql/opcache 等)。国产数据库的 PDO ▎ 驱动(达梦/人大金仓)它没有,需要扩展时还得自己编译,见方案 C。3.2自己从源码编译(需要定制扩展时)如果你要加国产数据库驱动、或下载的二进制跑不起来,就自己编。 #1.装Go(鲲鹏 ARM64 用 arm64 包,海光用 amd64 包)wget https://go.dev/dl/go1.23.4.linux-arm64.tar.gz # 海光换 linux-amd64tar-C/usr/local-xzf go1.23.4.linux-arm64.tar.gzexportPATH$PATH:/usr/local/go/bin go version #2.装编译依赖(麒麟/中标麒麟 yum)yum install-y gcc make autoconf libtool \ php-devel \ # 关键:需要 PHP 的开发库和头文件 libxml2-devel sqlite-devel curl-devel openssl-devel # 统信 UOS 用 apt:#aptinstall-y gcc make php-dev libxml2-dev libsqlite3-dev libcurl4-openssl-dev#3.关键:PHP 必须是ZTS(线程安全)版本#FrankenPHP 的 worker 模式要求 PHP 编译时带--enable-zts# 国产 OS 自带的 PHP 通常不是 ZTS,大概率要自己编PHP(见下)#4.编译 FrankenPHPgit clone https://github.com/php/frankenphpcd frankenphp/caddy/frankenphp CGO_ENABLED1\ CGO_CFLAGS$(php-config--includes)\ CGO_LDFLAGS$(php-config --ldflags) $(php-config --libs)\ go build-o/usr/local/bin/frankenphp3.3自己编译 ZTS 版PHP(信创几乎必做)国产 OS 自带的 PHP 基本都不是线程安全(ZTS)的,而 FrankenPHP 的 worker 模式必须 ZTS。所以通常要自己编一个 PHP:# 下载 PHP 源码(8.2)wget https://www.php.net/distributions/php-8.3.14.tar.gztar xzf php-8.3.14.tar.gzcd php-8.3.14./configure \--enable-embed \ # ★必须:生成 libphp 嵌入库,FrankenPHP 靠它--enable-zts \ # ★必须:线程安全,worker 模式前提--disable-zend-signals \ # FrankenPHP 推荐关掉--enable-opcache \ # 性能--with-openssl--with-curl--enable-mbstring \--with-pdo-mysql # 先带个 MySQL 驱动占位 make-j$(nproc)make install 大白话:这一步是信创适配的关键劳动。--enable-embed 让 PHP 编译出一个能被别的程序嵌进去的库(libphp.so),--enable-zts 让它线程安全。这俩是 FrankenPHP 的硬性前提,而国产 OS 的现成 PHP 包都不满足,所以自己编 PHP 几乎是信创适配的必经之路。---四、方案 B:龙芯LoongArch(最硬的骨头,重点)龙芯是 LoongArch 架构(loong64),全新指令集,不是 ARM 也不是 x86。这是信创里最难的。4.1三个关键前提确认 #1.确认 Go 支持loong64(Go1.19主线已支持)uname-m # 应输出 loongarch64 go version go tool dist list|grep loong # 应看到 linux/loong64 #2.龙芯有新世界(new world)/旧世界(old world)ABI 之分!这是大坑 # 新世界:基于上游内核/glibc(Loongnix 新版、AOSC),用主线 Go # 旧世界:龙芯早期自己魔改的 ABI,需要龙芯定制的 Go 工具链 ldd--version # 看 glibc 版本判断新旧世界 大白话(必须懂的龙芯坑):龙芯有新世界和旧世界两套不兼容的 ABI。新世界用社区主线工具链就行;旧世界(很多早期3A4000/部分3A5000 系统)的二进制 ABI 跟主线不兼容,你必须用龙芯官方提供的定制版 Go 和 gcc,否则编出来的东西跑不起来或链接失败。适配第一步先搞清楚目标机器是新世界还是旧世界,这决定了你用哪套工具链。4.2龙芯编译思路(新世界为例)# 推荐在 Loongnix-server(Fedora/RHEL 血统,龙芯官方维护)上操作 # 或 AOSCOS(对 loong64 支持好)#1.Go:优先用龙芯官方/社区适配的 Go 包(loong64)# 新世界用主线:https://go.dev/dl/go1.23.x.linux-loong64.tar.gz# 旧世界用龙芯定制版(从 龙芯开源社区/loongnix 源获取)#2.PHP 源码编译(LoongArch 上 PHP8.x 主线已可编译)yum install-y gcc make autoconf libxml2-devel # Loongnix./configure--enable-embed--enable-zts--disable-zend-signals \--enable-opcache--with-openssl--with-curl make-j$(nproc)make install #3.编FrankenPHP(同方案 A 的步骤4,GOARCH 自动是 loong64)CGO_ENABLED1\ CGO_CFLAGS$(php-config--includes)\ CGO_LDFLAGS$(php-config --ldflags) $(php-config --libs)\ GOARCHloong64 \ go build-o/usr/local/bin/frankenphp./caddy/frankenphp4.3龙芯的现实建议-static-php-cli(官方静态编译工具)对 loong64 支持不完善,所以龙芯上很难做全静态二进制,基本只能动态链接在目标机现编。-务必在龙芯真机或龙芯官方 SDK 容器里编译,不要指望在 x86 上交叉编译 loong64 的 cgo 程序(cgo 交叉编译需要完整的 loong64 C 工具链PHP 库,极其麻烦)。-优先选 Loongnix-server 或 统信 UOS 龙芯版 作为编译和运行环境,它们的 PHP/gcc 包对龙芯适配最好。-如果项目不强依赖龙芯,强烈建议生产用鲲鹏/飞腾(ARM64)代替龙芯跑 FrankenPHP,省80%的事。龙芯适合作为信创合规备选。---五、方案 C:接国产数据库(达梦/人大金仓/GaussDB)这是信创最实际的需求。FrankenPHP 跑的是你的 PHP 应用,应用要连国产数据库。5.1两条路线 路线1(推荐):走兼容协议,用现成驱动-人大金仓 KingbaseES:兼容 PostgreSQL 协议 →直接用 PHP 的 pdo_pgsql,连接串指向 Kingbase 端口即可,无需特殊驱动。-GaussDB/openGauss:也兼容 PG 协议 →同样用 pdo_pgsql。-达梦 DM:部分版本有 MySQL 兼容模式,但通常建议用官方专用驱动(下面)。 # 编 PHP 时带上 pgsql 驱动,就能连 Kingbase/openGauss./configure--enable-embed--enable-zts \--with-pdo-pgsql--with-pgsql...路线2:用厂商官方 PHP 扩展-达梦 DM 提供官方 PHP PDO 扩展(pdo_dm/php_dm)。-人大金仓也有官方 PHP 接口。 # 以达梦为例:把达梦提供的扩展源码编成.so cd/opt/dmdbms/drivers/php_pdo # 达梦安装目录下的 PHP 驱动源码 phpize # 用你编的那个 ZTS PHP 的 phpize./configure--with-php-config/usr/local/bin/php-config makemake install # 生成 pdo_dm.so#php.ini 里加载echoextensionpdo_dm.so/usr/local/lib/php.ini 大白话:国产数据库连接有两招。第一招最省心:金仓、GaussDB 都假装自己是 PostgreSQL,你的 PHP 用标准 pdo_pgsql 就能连,连厂商驱动都不用装。第二招针对达梦这种有自己协议的:用达梦官方给的 PHP 扩展源码,拿你那个 ZTS 版 PHP 的 phpize 编成.so,在 php.ini 里加载。关键:编扩展用的 phpize 必须是你 FrankenPHP 里那个 PHP 的,ZTS 版和非 ZTS 版扩展不通用,版本对不上加载会直接报错。5.2应用层代码(框架无关)// 连人大金仓(走 PG 协议)$pdonewPDO(pgsql:host192.168.1.10;port54321;dbnametest, SYSDBA, pwd);// 连达梦(用官方 pdo_dm 扩展)$pdonewPDO(dm:host192.168.1.20;port5236,SYSDBA,SYSDBA);---六、Worker 模式与信创性能优化 FrankenPHP 最大卖点是 worker 模式(应用常驻内存,不像 FPM 每个请求重启),信创环境下这个性能优势尤其值钱(国产 CPU 单核性能通常弱于 Intel,常驻省掉的启动开销更划算)。#Caddyfile 配置 worker 模式{frankenphp{worker{file/var/www/public/index.php num8# worker 进程数,建议CPU 核数(鲲鹏64核可调高)}}}信创调优要点:1.worker num 按国产 CPU 核数调:鲲鹏/飞腾常是32/64核,可以开很多 worker 弥补单核弱。2.必须开 OpaCacheJIT(如果 PHP8编译带了):国产 CPU 单核弱,JIT 收益明显。3.ZTS 有约10-20%单核性能损耗,但 worker 常驻带来的整体提升远超过这点损耗。4.关掉 zendsignals(--disable-zend-signals),线程模型下更稳。---七、容器化部署(信创私有云首选)信创环境多用国产容器平台(华为 CCE、麒麟 KubeSphere、道客 DaoCloud 等),容器化能把自己编译的复杂度封装一次,到处复用。7.1信创版Dockerfile(鲲鹏 ARM64 为例)# ★基础镜像必须用国产 OS 的容器镜像(信创合规要求)# 麒麟官方镜像/openEuler(华为开源,鲲鹏适配最好)FROM openeuler/openeuler:24.03-lts AS builder # 海光用 x86 的 openeuler,龙芯用 loongnix 镜像 # 装编译链 RUN yum install-y golang gcc make autoconf libtool \ libxml2-devel sqlite-devel openssl-devel curl-devel # 编 ZTS PHP WORKDIR/build RUN curl-O https://www.php.net/distributions/php-8.3.14.tar.gz \ tar xzf php-8.3.14.tar.gz cd php-8.3.14 \ ./configure --enable-embed --enable-zts --disable-zend-signals \ --enable-opcache --with-openssl --with-curl --with-pdo-pgsql \ make -j$(nproc) make install# 编 FrankenPHP RUN git clone--depth1https://github.com/php/frankenphp \ cd frankenphp/caddy/frankenphp \ CGO_ENABLED1 \ CGO_CFLAGS$(php-config --includes) \ CGO_LDFLAGS$(php-config --ldflags) $(php-config --libs) \ go build -o /usr/local/bin/frankenphp#运行镜像(同样用国产 OS)FROM openeuler/openeuler:24.03-lts COPY--frombuilder/usr/local/bin/frankenphp/usr/local/bin/COPY--frombuilder/usr/local/lib/libphp.so/usr/local/lib/RUN ldconfig COPY./app/var/www WORKDIR/var/www EXPOSE80443CMD[frankenphp,run,--config,/etc/Caddyfile]大白话:容器化是信创落地的最佳实践。把编 ZTS PHP编 FrankenPHP这套苦活封进一个镜像,编一次,以后整个团队、整个集群直接拉镜像跑。两个信创合规红线:①基础镜像必须用国产OS(openEuler/麒麟,别用 ubuntu/alpine);②镜像推到国产镜像仓库(华为 SWR、Harbor 私有仓),不要依赖 docker.io。 ▎ openEuler 是华为开源的、对鲲鹏适配最好的服务器 OS,信创认可度高,有 ARM64/x86/loong64 三种镜像,是 FrankenPHP ▎ 信创容器化的理想基底。---八、信创适配踩坑速查表 ┌────────────────────┬───────────────────────────────────────┬──────────────────────────────────────────────┐ │ 坑 │ 现象 │ 解法 │ ├────────────────────┼───────────────────────────────────────┼──────────────────────────────────────────────┤ │ glibc 太老 │ 官方二进制启动报 GLIBC_2.34notfound │ 用全静态(musl)二进制,或在目标机源码编译 │ ├────────────────────┼───────────────────────────────────────┼──────────────────────────────────────────────┤ │ PHP 不是 ZTS │ worker 模式启动失败/段错误 │ 自己编 PHP 带--enable-zts--enable-embed │ ├────────────────────┼───────────────────────────────────────┼──────────────────────────────────────────────┤ │ 扩展加载失败 │ pdo_dm.so undefined symbol │ 扩展必须用同一个 ZTS PHP 的 phpize 编 │ ├────────────────────┼───────────────────────────────────────┼──────────────────────────────────────────────┤ │ 龙芯新旧世界混用 │ 二进制无法执行/链接错 │ 确认 ABI,旧世界用龙芯定制工具链 │ ├────────────────────┼───────────────────────────────────────┼──────────────────────────────────────────────┤ │ 交叉编译 cgo 失败 │ loong64 在 x86 上编不过 │ cgo 必须在目标架构真机/容器内编译 │ ├────────────────────┼───────────────────────────────────────┼──────────────────────────────────────────────┤ │ SELinux 拦截(麒麟)│ 进程起不来/权限拒绝 │ 配 SELinux 策略或调 permissive 测试 │ ├────────────────────┼───────────────────────────────────────┼──────────────────────────────────────────────┤ │ 国产 CPU 单核弱 │ 性能不如预期 │ 开 worker 模式OPcacheJIT,worker 数拉满 │ └────────────────────┴───────────────────────────────────────┴──────────────────────────────────────────────┘---九、最终推荐方案(一句话决策)信创 FrankenPHP 最优落地路线:CPU 选型:鲲鹏/飞腾(ARM64)≈海光(x86)龙芯(LoongArch)申威(放弃)OS:openEuler/银河麒麟服务器版 V10 构建方式:容器化(国产OS基础镜像)封装ZTS PHP FrankenPHP编译 PHP:自编8.3带--enable-embed--enable-zts(必做)数据库:金仓/GaussDB 走 pdo_pgsql;达梦用官方 pdo_dm 扩展 运行模式:worker 模式OPcacheJIT(弥补国产CPU单核弱)镜像仓库:华为SWR/私有Harbor(不依赖docker.io)核心认知:FrankenPHP 信创适配的本质,是把 Go工具链C编译器ZTS版PHP 这三样在国产 CPU/OS 上跑通,然后用容器封装让这套 苦活只做一次。标准架构(ARM64/x86)几乎无痛,真正的硬骨头只有龙芯,而龙芯能用鲲鹏替代时就尽量替代。