
前一阵子把公司一批业务系统往信创环境迁移麒麟操作系统、国产芯片的服务器前后折腾了快两个月。中间碰到的问题一个接一个有些是文档里写得含糊有些是网上根本搜不到答案全靠一点点试。现在复盘一下这段经历把踩过的坑和摸索出来的解决办法记录下来希望给后面做信创迁移的朋友省点时间。1. 信创迁移不是换台机器那么简单很多人一开始对信创迁移的理解是把应用从 x86 服务器搬到国产服务器上重新部署一遍就行。实际做下来才发现这个问题牵扯到操作系统、CPU 架构、中间件、数据库、JDK 版本、前端依赖任何一环对不上都会卡住。先说最基础的信创服务器操作系统麒麟版跟 CentOS 的差异远不止界面长得不一样。虽然麒麟对外宣称兼容 Linux 生态但实际用起来很多习惯性的操作会踩坑。我接触的这批机器是麒麟 V10 系统芯片是海光或者鲲鹏。海光的架构是 x86_64兼容性相对好一些很多基于 Intel/AMD 的软件可以直接跑。但鲲鹏是 ARM 架构情况就复杂了——所有依赖 CPU 架构的二进制文件都得重新适配。这里有个很关键的认知信创不是指某一种 CPU而是一个生态的代称。拿到一台信创机器第一件事就是确认架构否则后面全白搭。# 查看 CPU 架构 lscpu | grep Architecture # 查看操作系统版本 cat /etc/os-release # 查看内核版本 uname -r这三条命令建议在拿到机器后第一时间执行并把结果记录下来。后面凡是遇到装不上跑不起来编译报错十有八九都要回到这些基础信息上去排查。另外一个容易忽略的是 glibc 版本。很多在 CentOS 7 上编译好的二进制包直接拿到麒麟上跑会报GLIBC_2.27 not found之类的错误。原因就是麒麟的 glibc 版本比 CentOS 7 的新但比某些应用程序编译时依赖的版本旧。这种问题要么找兼容版本要么源码编译。2. 麒麟系统网络配置最基础也最容易被绊倒网络配置听起来是个入门操作但在信创环境里真闹出过不少笑话。麒麟操作系统默认是图形界面管理网络但服务器版很多场景下用的是命令行这就需要搞清楚它的网络管理机制。麒麟 V10 用的网络管理工具跟 CentOS 7 类似是 NetworkManager但配置文件路径和方式有些差异。我遇到的情况是配好了静态 IP重启后网络没起来ip addr 一看网卡压根没加载配置。排查过程大概是这样的# 查看网卡名称 ip addr # 查看 NetworkManager 状态 systemctl status NetworkManager # 查看连接配置 nmcli connection show问题出在麒麟的 NetworkManager 默认把网卡当作 DHCP 管理我手动改了/etc/sysconfig/network-scripts/ifcfg-eth0配置文件但 NetworkManager 并没有自动重新加载。解决办法有两种我最后采用了第一种方式一使用 nmcli 配置# 修改连接为静态 IP nmcli connection modify eth0 ipv4.addresses 192.168.1.100/24 nmcli connection modify eth0 ipv4.gateway 192.168.1.1 nmcli connection modify eth0 ipv4.dns 114.114.114.114 8.8.8.8 nmcli connection modify eth0 ipv4.method manual # 重启网络连接 nmcli connection down eth0 nmcli connection up eth0方式二直接改配置文件改完要重启 NetworkManagervim /etc/sysconfig/network-scripts/ifcfg-eth0 # 内容示例 BOOTPROTOstatic ONBOOTyes IPADDR192.168.1.100 NETMASK255.255.255.0 GATEWAY192.168.1.1 DNS1114.114.114.114注意一个细节麒麟系统里如果 NetworkManager 接管了网络直接改配置文件后不重启 NetworkManager 是不生效的而且有时候重启了还会被覆盖掉。最稳的方式是用 nmcli 命令修改让 NetworkManager 自己去写配置。还有一个坑是双系统修改启动顺序。我的笔记本上装了 Windows 和麒麟双系统默认启动的是麒麟但我大多数时候需要进 Windows。网上搜到的教程基本都针对老版本的 GRUB麒麟 V10 的 GRUB 配置方式有变化。在麒麟系统里# 查看当前默认启动项 grub2-editenv list # 列出所有启动项 awk -F\ $1menuentry {print i : $2} /etc/grub2-efi.cfg # 设置默认启动项比如 Windows 是第 3 项从 0 开始计数 grub2-editenv create grub2-reboot 2注意grub2-reboot只对下一次重启生效适合临时切换如果想永久修改默认启动项要改/etc/default/grub里的GRUB_DEFAULT然后执行grub2-mkconfig -o /boot/efi/EFI/kylin/grub.cfg路径可能因安装方式不同而不同。这个操作本身不复杂但网上很多教程写的是/boot/grub2/grub.cfg在麒麟上并不适用导致很多新手怎么改都不生效。实际部署时建议先用grub2-editenv list确认当前环境再决定操作方式。3. 关机命令的坑你以为的和实际发生的聊一个特别基础但坑到人的点信创系统的关机命令。麒麟系统的关机命令传统方式是shutdown -h now或poweroff这个我一开始用着没觉得有什么。直到有一天我执行shutdown -h now后机器确实关机了但过了一段时间发现服务器还在远程管理界面能看到状态是已停止——这其实是正常的。但真正的问题是在麒麟系统中如果当前有用户会话还处于激活状态shutdown -h now会卡住迟迟不执行关机。排查下来发现麒麟系统的 shutdown 命令调用的是 systemd 的关机流程如果系统里有活动的登录会话比如我用 SSH 连着它会先尝试优雅地关闭会话如果会话不响应就会挂起等待。我的处理方式# 强制立即关机 shutdown -h now # 如果卡住改用 systemctl poweroff -i # 或者强制切断电源不推荐但应急有效 echo o /proc/sysrq-triggersystemctl poweroff -i的-i参数会忽略所有非活跃的依赖直接关机实测下来比shutdown -h now更利索。我把这个写进了信创迁移的操作规范里后面团队的人再没遇到过关机卡死的问题。4. 应用部署阶段的重重阻碍网络和系统层面的问题解决后真正的硬仗在应用部署阶段。我们迁移的是一套 Java 微服务系统前端是 Node.js 构建的静态资源数据库是 MySQL中间件用的是 Nginx 和 Redis。这些组件在 CentOS 上是轻车熟路但到了麒麟 ARM 架构的机器上每一个都可能有坑。4.1 JDK 版本带来的诡异乱码项目用的是 JDK 8但麒麟系统默认的 JDK 是 OpenJDK 11路径和默认编码都不同。最开始没注意项目里用到的 fastjson 2.0.64 在解析 JSON 时出现了中文乱码排查了好几天最终定位到是 JDK 版本和 fastjson 的兼容性问题。fastjson 2.0.64 在某些 JDK 版本下JSON 字符串的默认编码处理方式不同特别是当系统区域设置不是 UTF-8 时很容易出现乱码。我的解法分两步统一系统区域设置为 UTF-8# 查看当前区域设置 locale # 修改为 UTF-8 localectl set-locale LANGzh_CN.UTF-8 # 或 export LANGen_US.UTF-8在 JVM 启动参数中强制指定编码java -Dfile.encodingUTF-8 -Dsun.jnu.encodingUTF-8 -jar app.jar这里-Dfile.encoding是 Java 读取文件时的编码-Dsun.jnu.encoding是 JVM 与操作系统交互时使用的编码。两者都设成 UTF-8能避免绝大多数的乱码问题。4.2 安装 Node.js别直接拿官方包跑另一个让我记忆深刻的坑是给信创环境安装 Node.js。起初我想当然地认为下载一个 Linux 的 tar 包解压就能用结果折腾了整整一个下午。先说结论在信创环境下装 Node.js不能直接拿官网的 Linux 包用。官网的预编译二进制包很多是基于 glibc 的 x86_64 架构编译的放在麒麟环境上要么架构对不上要么依赖不匹配。我第一次没多想下载了 node-v16.20.2-linux-x64.tar.xz 解压配置好 PATH执行node -v报错node: /lib/x86_64-linux-gnu/libm.so.6: version GLIBC_2.27 not found (required by node)这就是典型的 glibc 版本不匹配。系统自带的 glibc 版本比编译这个二进制时用的版本低直接干瞪眼。我当时给了自己两条路一是找适配麒麟的 arm64 版本或者统信 UOS 的软件源二是干脆用源码编译。麒麟系统自带的软件源里其实有 nodejs但版本往往偏旧我记得源里大概是 v10.24.0 左右对于一般测试够用但要跑新一点的工具链就捉襟见肘。如果要用源码编译需要注意以下几点确认系统有 gcc、g、make、python2 或 python3这些都是编译 Node.js 的基础依赖。./configure时指定好安装路径比如--prefix/usr/local/node。make 的时间视机器性能而定我那一台 8 核的机器跑了大约 20 分钟如果配置低可能要更久。编译完成之后node -v就没有 glibc 报错了。这里有个建议不要觉得编译麻烦就跳过信创环境下源码编译才是最稳的方案。很多预编译包都是基于非信创环境构建的拿来直接跑坑太多了。4.3 数据库与中间件的兼容性排查再往后是 MySQL。最初尝试直接用 apt 安装 MySQL但在麒麟上装的是 MariaDB而不是 MySQL。虽然 MariaDB 兼容 MySQL 协议但有些 SQL 方言和存储引擎的行为还是有差别特别是在使用 MyISAM 引擎或者某些特殊查询语法时。最终我们决定用 Docker 部署 MySQL 5.7 的 arm64 版本镜像。这里又要提一个坑网上很多教程用的 MySQL 镜像都是 x86 架构的在 ARM 上拉取并不会报错但运行时会出现Exec format error的错误。原因是 Docker 拉取镜像时默认按照当前平台拉取但如果你不指定--platform参数有些镜像仓库会自动引导到错误平台。docker pull --platform linux/arm64 mysql:5.7强制指定平台就不会拉错了。同样的道理Redis 和 Nginx 也要注意架构docker pull --platform linux/arm64 redis:6.2 docker pull --platform linux/arm64 nginx:1.24Redis 和 Nginx 的官方镜像在 ARM 架构下支持得都不错基本拿来就能用。真正麻烦的是那些比较偏门的开源组件比如某些消息队列和注册中心arm64 镜像要么没有要么版本很老只能自己在 Dockerfile 里从源码构建。5. 比赛视角下的信创不是学命令是学排查思路每年都有不少信创相关的技能比赛比如信创服务器操作系统的配置与管理麒麟版。很多人觉得这类比赛考的是背命令、记配置文件但实际参加过就知道真正拉开差距的是面对一个完全没有文档、没有搜索引擎的环境时你怎么从报错信息里找到线索。举一个比赛里遇到过的问题系统要求把 Apache 服务配置成支持 HTTPS证书文件已提供但配置完成后浏览器提示证书不可信。大多数人第一反应是检查证书链、看配置格式但其实问题出在系统时钟上——信创机器出厂后如果没同步过时间系统时间可能偏差很大导致证书校验不通过。处理方式也很简单# 同步时间 timedatectl set-ntp true # 或者手动设置 date -s 2025-01-01 12:00:00这种坑在真实生产环境里更常见。所以我的经验是信创的比赛和真实工作考的不是你知道多少命令而是你能在多短的时间内定位问题。多练journalctl、dmesg、strace这些排查工具比背任何配置文档都管用。5.1 排查工具链在麒麟系统上的使用笔记这里重点记录一下我自己常用的排查链路journalctl -xe查看系统日志的最后一段报错很多服务启动失败的信息都能从这里看到。systemctl status看服务到底处于什么状态是 failed 还是 activeexited以及失败原因。strace -p跟踪进程的系统调用当某个程序卡住时可以看到它阻塞在哪个系统调用上。lsof -i查看端口占用和网络连接排查端口冲突很方便。df -h和iostat排查磁盘空间和 IO 瓶颈。还有一个很容易被忽略的细节麒麟系统的/var/log/messages和 CentOS 的一样存在但很多程序还会往~/.xsession-errors或者~/.cache/下写日志。特别是前端页面起不来时往往不是 Nginx 的问题而是构建后的静态资源路径不对这时候看/var/log/nginx/error.log比看系统日志更直接。5.2 信创目录到底是什么规划先行最后再聊一个概念性的事——信创目录。这个词在不同的上下文里含义不同有时指的是信创产品名录哪些国产软件、硬件进入了政府采购/迁移认可范围有时指的是项目里为信创适配单独维护的目录结构。我实际工作中更关注后者信创迁移不是改几个配置文件就完事而是一个需要单独规划的子项目。我建议在项目启动时先建立一个信创适配目录包含以下子目录docs/记录所有环境信息架构、系统版本、内核、glibc、JDK 版本。scripts/沉淀整套部署流程脚本包括环境检查、依赖安装、应用启动。patches/记录所有二进制的替代方案和源码编译产物。known-issues/记录所有踩过的坑及解决办法方便后续团队查阅。这个目录建立得好后面无论是复盘、交接还是参赛都能省很多事。6. 迁移验证清单照着做能少走一半弯路写一套我自己整理的信创迁移验证清单照着做能避免大部分低级问题检查项操作预期结果CPU 架构lscpu明确是 x86_64 还是 aarch64操作系统版本cat /etc/os-release确认是麒麟 V10 还是其它版本glibc 版本ldd --version确认与应用程序的依赖是否兼容JDK 版本java -version确认是 OpenJDK 8 还是 11且编码为 UTF-8Node 版本node -v确认架构匹配无 GLIBC 报错网络配置nmcli connection show确认 IP、网关、DNS 正确系统时间timedatectl确认时间偏差在合理范围Docker 平台docker info看 Architecture确认拉取的镜像架构正确防火墙systemctl status firewalld确认业务端口已放行这张表我建议在部署前、部署中、部署后各跑一遍。特别是部署后再检查一次能发现很多当时能用重启后不行的隐性 bug。7. 经验之外还想说的事信创迁移这件事做之前觉得是换个环境跑代码做之后才明白这实际上是一个重新理解底层依赖的机会。x86 CentOS 的路径太顺畅了顺畅到很多东西都不用关心架构不用关心因为统一glibc 不用关心因为大家都一样JDK 不用关心因为包管理器装好就是对的。但在信创环境里没有一个环节是可以想当然的。有一句话我最近常跟团队说信创环境是最好的祛魅工具它逼着每个开发者去搞清楚自己的应用到底依赖了什么。再分享一个实操中总结的经验不要把信创适配的所有工作都压到最后。最好在迁移之前先在虚拟机里搭一套同架构、同系统的环境把依赖梳理一遍确认所有组件在这个架构下都有替代方案再动生产。这个预演过程省下来的时间远超那几天的加班量。过程中如果遇到网上搜不到答案的问题也别急着崩溃。先回到最底层用ldd查动态库依赖用strace看系统调用用file看二进制格式大多数问题的答案就在这几步里。信创环境的坑虽然多但漏洞往往不是黑盒只要一层层剥下去总能找到根因。最后送一句个人很深的体会信创不是替代而是重构。在这个过程中真正有价值的不是把业务跑起来而是那群人在把业务跑起来的过程中积累下的对系统底层的理解和一套属于自己的排查方法论。这些东西放到未来的任何技术栈里都是升值品。