1. 为什么我们需要做国产化适配最近几年我身边越来越多的朋友和客户都在聊“国产化”这件事。简单来说就是要把我们核心业务系统里那些国外的技术组件比如数据库、中间件、服务器芯片逐步替换成国内自主研发的产品。这背后有技术自主可控的考量也有对供应链安全的长远布局。Nacos 作为阿里巴巴开源的明星项目是微服务架构中服务发现和配置管理的“神经中枢”它的稳定运行至关重要。但在国产化环境中我们常常会遇到两个核心挑战一是数据库从 MySQL 换成了像瀚高这样的国产数据库二是服务器硬件从 x86 架构迁移到了 ARM 架构。我刚开始接触这个任务时也以为就是改改数据库连接字符串那么简单。但实际一上手才发现Nacos 2.3.1 版本默认只支持 MySQL 和 Derby要让它和瀚高数据库“握手言和”需要深入到源码层面理解它的数据访问层设计。而 ARM 架构的适配则涉及到整个软件从编译、打包到最终容器化运行的全链路调整。这个过程踩了不少坑但也积累了一套完整的实战经验。今天我就把这套从源码修改、SPI扩展、到 Docker 镜像构建的“全链路改造方案”分享给你希望能帮你少走弯路。2. 动手前的环境与工具准备工欲善其事必先利其器。在开始敲代码之前我们需要把“战场”布置好。这里我列一个详细的清单你可以对照着一步步来确保基础环境万无一失。开发与编译环境操作系统推荐使用 Ubuntu 20.04/22.04 LTS 或 CentOS 7/8。我实测下来在 ARM 架构的国产化服务器如华为鲲鹏、飞腾上直接操作能提前发现一些架构相关的问题。Java 环境Nacos 2.3.1 基于 Java 8 构建请确保安装 JDK 8建议版本 1.8.0_292 或更高。ARM 架构下你需要安装对应的 ARM 版本 JDK例如aarch64架构的 OpenJDK。Maven版本需要 3.5.0 以上用于项目构建和依赖管理。同样在 ARM 服务器上请使用对应架构的 Maven 包。Git用于拉取 Nacos 的源代码。关键软件与依赖Nacos 2.3.1 源码这是我们的改造对象。直接从 GitHub 的官方仓库拉取指定版本确保代码基线一致。git clone -b 2.3.1 https://github.com/alibaba/nacos.git瀚高数据库 JDBC 驱动这是连接瀚高数据库的桥梁。你需要从瀚高官方获取对应版本的 JDBC 驱动 Jar 包例如HgdbJdbc-6.2.3.jar。一个常见的“坑”是驱动包不仅要放入项目的依赖路径最好也提前安装到你的本地 Maven 仓库方便后续打包。可以使用mvn install:install-file命令手动安装。Docker用于构建 ARM 架构的容器镜像。如果你的开发机是 x86 的但目标环境是 ARM就需要配置 Docker 的buildx插件来支持跨平台构建或者直接在 ARM 服务器上执行构建。数据库环境准备在瀚高数据库中你需要提前创建一个专供 Nacos 使用的数据库例如nacos_config和对应的用户例如nacos/nacos。这里特别注意一点瀚高数据库有Schema的概念不同于 MySQL 的数据库。你需要在连接字符串中明确指定currentSchema参数否则 Nacos 启动时会找不到表。这个细节我们后面在配置文件里会重点说。3. 第一步源码改造与瀚高数据库驱动集成拿到源码后我们先解决数据库的问题。Nacos 的数据持久化层设计得比较清晰主要通过nacos-config模块处理配置信息通过nacos-datasource-plugin插件体系来支持不同的数据库。我们的改造也围绕这两部分展开。3.1 修改项目依赖POM.xml首先我们要告诉 Maven 项目“嘿我们新增了一个瀚高数据库的依赖。” 这需要修改两处pom.xml文件。根目录pom.xml在dependencyManagement节点下添加瀚高 JDBC 驱动的版本管理。这样做的好处是所有子模块引用这个驱动时版本号都统一管理避免冲突。!-- 在根目录的 pom.xml 中找到 dependencyManagement 部分 -- dependencyManagement dependencies !-- 其他依赖... -- !-- 新增瀚高数据库驱动依赖管理 -- dependency groupIdcom.highgo/groupId artifactIdHgdbJdbc/artifactId version6.2.3/version !-- 请替换为你的实际驱动版本 -- /dependency /dependencies /dependencyManagementnacos-config模块的pom.xml这个模块负责核心的配置管理功能需要直接引入瀚高驱动。!-- 在 nacos-config 模块的 pom.xml 的 dependencies 部分添加 -- dependency groupIdcom.highgo/groupId artifactIdHgdbJdbc/artifactId !-- 版本号由父POM统一管理这里无需指定 -- /dependency改完后记得在项目根目录执行一下mvn clean compile检查一下依赖是否能正常下载和引入没有报错就说明第一步成功了。3.2 修改数据库驱动类名Nacos 在连接外部数据库时有一个关键的配置类ExternalDataSourceProperties它里面硬编码了默认的 JDBC 驱动类。我们的任务就是把它从 MySQL 的驱动换成瀚高的驱动。找到文件nacos-config/src/main/java/com/alibaba/nacos/persistence/datasource/ExternalDataSourceProperties.java。定位到下面这行代码private static final String JDBC_DRIVER_NAME com.mysql.cj.jdbc.Driver;将它修改为瀚高数据库的驱动类名private static final String JDBC_DRIVER_NAME com.highgo.jdbc.Driver;这里有个小提示不同版本的瀚高数据库驱动类名可能略有差异。最稳妥的方法是用解压软件打开你下载的HgdbJdbc-6.2.3.jar查看META-INF/services/java.sql.Driver文件或者直接查看 Jar 包根目录下的类路径确认准确的驱动类全名。3.3 扩展数据源插件常量Nacos 通过一个名为nacos-datasource-plugin的插件模块来抽象对不同数据库的支持。我们需要先在常量定义中“注册”瀚高数据库的类型。找到文件nacos-datasource-plugin/src/main/java/com/alibaba/nacos/plugin/datasource/constants/DataSourceConstant.java。你会看到类似这样的定义public class DataSourceConstant { public static final String MYSQL mysql; public static final String DERBY derby; // ... 可能还有其他 }我们在其中添加瀚高数据库的常量public class DataSourceConstant { public static final String MYSQL mysql; public static final String DERBY derby; public static final String HIGHGO highgo; // 新增瀚高数据库标识 }这个HIGHGO常量就是我们后续所有瀚高数据库专属 Mapper 实现类的“身份证”。4. 第二步实现瀚高数据库的SPI扩展这是整个适配工作的核心部分也是工作量最大的一块。Nacos 的数据访问层采用了SPIService Provider Interface机制这是一种非常优雅的扩展方式。简单理解就是Nacos 定义了一套操作数据库的接口比如“查询配置信息”、“插入历史记录”而具体每种数据库MySQL、Derby怎么实现这些接口则由对应的实现类来完成。我们要做的就是为瀚高数据库编写这一套实现类。4.1 理解Mapper与SPI机制在nacos-datasource-plugin模块的impl目录下你可以看到mysql和derby两个包里面就是它们各自的实现。我们的目标是在这里创建一个highgo包并实现九个核心的 Mapper 接口。这些 Mapper 接口包括ConfigInfoMapper配置信息核心表操作ConfigInfoAggrMapper聚合数据管理ConfigInfoBetaMapperBeta配置管理ConfigInfoTagMapper配置标签管理ConfigTagsRelationMapper配置与标签关系管理HistoryConfigInfoMapper历史配置管理GroupCapacityMapper集群容量管理TenantCapacityMapper租户容量管理TenantInfoMapper租户信息管理为什么需要重写因为不同数据库的 SQL 语法有差异。最典型的例子就是分页查询。MySQL 使用LIMIT offset, size而瀚高数据库语法与 PostgreSQL 兼容使用LIMIT size OFFSET offset。此外一些函数、日期处理、批量插入的语法也可能需要调整。4.2 关键Mapper实现示例与分页改造我们以最常用的ConfigInfoMapperByHighgo为例看看如何将一个分页查询方法从 MySQL 语法适配到瀚高语法。原始 MySQL 实现ConfigInfoMapperByMySql中的findAllConfigInfoFetchRows方法可能类似这样简化public MapperResult findAllConfigInfoFetchRows(MapperContext context) { String sql SELECT t.id,data_id,group_id,tenant_id,app_name,content,md5 FROM ( SELECT id FROM config_info WHERE tenant_id LIKE ? ORDER BY id LIMIT ?, ? ) g, config_info t WHERE g.id t.id ; return new MapperResult(sql, parameters); }注意其中的LIMIT ?, ?。在瀚高数据库的实现中我们需要将其改写为LIMIT ? OFFSET ?并且参数顺序也变了先传pageSize再传startRow在代码中通过context获取。瀚高数据库的实现ConfigInfoMapperByHighgoOverride public MapperResult findAllConfigInfoFetchRows(MapperContext context) { String sql SELECT t.id,data_id,group_id,tenant_id,app_name,content,md5 FROM ( SELECT id FROM config_info WHERE tenant_id LIKE ? ORDER BY id OFFSET ? LIMIT ? ) g, config_info t WHERE g.id t.id ; return new MapperResult(sql, CollectionUtils.list( context.getWhereParameter(FieldConstant.TENANT_ID), context.getStartRow(), // OFFSET 参数 context.getPageSize() // LIMIT 参数 )); }这里有个非常重要的细节context.getStartRow()返回的是偏移量起始值context.getPageSize()返回的是每页大小。在瀚高的 SQL 中OFFSET startRow LIMIT pageSize这个顺序必须正确。你需要为上面提到的九个 Mapper 接口逐一创建对应的ByHighgo实现类并仔细检查每一个 SQL 语句确保语法完全兼容瀚高数据库。这个过程需要耐心最好在修改后能连接一个测试用的瀚高数据库对关键 SQL 进行验证。4.3 注册SPI服务提供者实现完所有类之后我们还需要告诉 Nacos“嗨我这里有瀚高数据库的实现啦请加载它。” 这是通过 SPI 的配置文件完成的。找到文件nacos-datasource-plugin/src/main/resources/META-INF/services/com.alibaba.nacos.plugin.datasource.mapper.Mapper。这个文件里已经列出了 MySQL 和 Derby 的所有实现类。我们只需要在文件末尾追加我们新增的九个瀚高实现类的全限定名。# 原有内容... com.alibaba.nacos.plugin.datasource.impl.mysql.ConfigInfoAggrMapperByMySql com.alibaba.nacos.plugin.datasource.impl.mysql.ConfigInfoBetaMapperByMySql ... com.alibaba.nacos.plugin.datasource.impl.derby.ConfigInfoAggrMapperByDerby com.alibaba.nacos.plugin.datasource.impl.derby.ConfigInfoBetaMapperByDerby ... # 新增瀚高数据库的实现类 com.alibaba.nacos.plugin.datasource.impl.highgo.ConfigInfoAggrMapperByHighgo com.alibaba.nacos.plugin.datasource.impl.highgo.ConfigInfoBetaMapperByHighgo com.alibaba.nacos.plugin.datasource.impl.highgo.ConfigInfoMapperByHighgo com.alibaba.nacos.plugin.datasource.impl.highgo.ConfigInfoTagMapperByHighgo com.alibaba.nacos.plugin.datasource.impl.highgo.ConfigTagsRelationMapperByHighgo com.alibaba.nacos.plugin.datasource.impl.highgo.HistoryConfigInfoMapperByHighgo com.alibaba.nacos.plugin.datasource.impl.highgo.TenantInfoMapperByHighgo com.alibaba.nacos.plugin.datasource.impl.highgo.TenantCapacityMapperByHighgo com.alibaba.nacos.plugin.datasource.impl.highgo.GroupCapacityMapperByHighgo这样当 Nacos 启动并设置数据源类型为highgo时它就会自动加载我们编写的这些实现类。5. 第三步配置与单机启动测试代码层面的改造完成后我们进入配置和测试阶段。这一步的目标是让 Nacos 服务能够真正跑起来并连接到瀚高数据库。5.1 修改控制台配置文件Nacos 的控制台console模块有一个关键的配置文件它决定了应用启动时连接哪个数据库。找到文件nacos-console/src/main/resources/application.properties。我们需要修改其中的数据源配置部分关键的几个参数如下# 指定数据库平台为 highgo这会触发SPI加载我们编写的实现类 spring.sql.init.platformhighgo # 数据库实例数量单库就写1 db.num1 # 瀚高数据库连接URL。注意以下几个关键点 # 1. jdbc:highgo://[主机]:[端口]/[数据库名] # 2. currentSchemanacos_config 这个参数至关重要它指定了连接后使用的模式Schema相当于MySQL的数据库。 # 3. 其他参数如字符集、超时设置等根据实际情况调整。 db.url.0jdbc:highgo://your-highgo-host:5866/nacos_config?currentSchemanacos_configcharacterEncodingutf8connectTimeout10000socketTimeout30000autoReconnecttrueuseUnicodetrueuseSSLfalseserverTimezoneUTC # 数据库用户名和密码 db.user.0nacos db.password.0nacos # 指定JDBC驱动类与我们之前在代码中修改的保持一致 db.pool.config.driverClassNamecom.highgo.jdbc.Driver重点强调currentSchema如果你在瀚高中创建的 Schema 不叫nacos_config请务必修改成你实际的名字。如果不加这个参数连接会成功但 Nacos 会在默认的publicschema 下找表导致报“表不存在”的错误。5.2 单机模式启动与验证由于我们还在开发测试阶段可以先以单机模式启动 Nacos 服务验证数据库连接和基础功能是否正常。在项目根目录下执行以下 Maven 命令来启动控制台模块它会内嵌启动 Nacos 服务cd nacos-console mvn spring-boot:run -Dnacos.standalonetrue-Dnacos.standalonetrue这个参数告诉 Nacos 以单机模式运行这样它就不会去尝试连接集群节点。看到控制台输出类似Nacos started successfully in stand alone mode的日志后打开浏览器访问http://localhost:8848/nacos。如果能看到 Nacos 的登录页面并且能用默认账号nacos/nacos登录进去说明服务基本启动成功了。接下来进行核心验证登录管理界面进入“配置管理”或“服务管理”。尝试新建一个配置。如果创建成功并且能在列表里看到说明写操作INSERT是正常的。刷新页面或重新查询这个配置说明读操作SELECT也是正常的。可以再尝试修改和删除这个配置验证完整的 CRUD 流程。同时务必观察后台日志有没有出现 SQL 语法错误、连接异常等信息。如果一切顺利恭喜你Nacos 与瀚高数据库的适配在单机模式下已经基本成功了6. 第四步项目打包与发布本地测试通过后我们需要将改造好的 Nacos 打包成可部署的发行版。6.1 执行项目打包命令回到 Nacos 源码的根目录执行官方的发布打包命令。这个命令会跳过测试和代码检查加快打包速度。# 在项目根目录执行 mvn -Prelease-nacos -Dmaven.test.skiptrue -Dpmd.skiptrue -Dcheckstyle.skiptrue clean install -U这个过程会持续几分钟Maven 会编译所有模块并最终在distribution/target/目录下生成打包好的文件通常是nacos-server-$version.tar.gz这种格式的压缩包。6.2 获取与验证发布包打包完成后进入distribution/target/目录找到生成的压缩包。你可以将这个包解压到任意目录例如/home/nacos。解压后目录结构通常包含bin启动脚本、conf配置文件、logs日志目录和target依赖包等。重要的一步将我们之前修改的nacos-console/src/main/resources/application.properties文件复制到解压后目录的conf/application.properties覆盖掉默认的配置。这样打包好的发行版就包含了连接瀚高数据库的所有设置。然后你可以进入bin目录执行sh startup.sh -m standaloneLinux/Mac或cmd startup.cmd -m standaloneWindows来启动单机版再次进行功能验证。确保从打包好的独立发布包启动一切功能依然正常。这步验证是为了排除开发环境干扰确认发行包是完整可用的。7. 第五步构建ARM架构的Docker镜像最后一步我们要让这个适配了瀚高数据库的 Nacos能够运行在 ARM 架构的服务器上。最优雅的方式就是将其制作成 Docker 镜像。7.1 准备ARM基础镜像Docker 镜像构建需要一个基础环境。由于目标架构是 ARM通常是aarch64我们不能使用默认的 x86 基础镜像。需要寻找或构建支持 ARM 的基础镜像。基础工具镜像例如buildpack-deps:buster-curl需要其 ARM 版本。可以从 Docker Hub 的官方镜像仓库查找带有arm64v8或aarch64标签的版本。Java运行环境Nacos 需要 JRE。同样我们需要 ARM 架构的 OpenJDK 8 JRE 镜像。例如arm64v8/openjdk:8-jre-slim或类似标签的镜像。在你的私有镜像仓库或能够访问的仓库中准备好这两个基础镜像。假设我们准备好的镜像分别是your-registry.com/library/arm64/buildpack-deps:buster-curl和your-registry.com/library/arm64/openjdk:8-jre-slim。7.2 编写ARM架构的Dockerfile在 Nacos 源码根目录下创建一个名为Dockerfile_arm的文件。这个文件定义了如何从源码构建出 ARM 版的 Nacos 镜像。# 第一阶段使用ARM架构的构建工具镜像将打包好的Nacos解压 FROM your-registry.com/library/arm64/buildpack-deps:buster-curl as installer ARG NACOS_VERSION2.3.1 # 将我们上一步打包好的tar.gz复制到镜像中 COPY distribution/target/nacos-server-${NACOS_VERSION}.tar.gz /var/tmp/ RUN tar -xzvf /var/tmp/nacos-server-${NACOS_VERSION}.tar.gz -C /home/ # 第二阶段使用ARM架构的JRE运行时镜像 FROM your-registry.com/library/arm64/openjdk:8-jre-slim # 设置环境变量与官方镜像保持一致 ENV MODEcluster \ PREFER_HOST_MODEip\ BASE_DIR/home/nacos \ CLASSPATH.:/home/nacos/conf:$CLASSPATH \ ... # 其他环境变量省略可参考官方Dockerfile WORKDIR $BASE_DIR # 从第一阶段构建的镜像中复制已经解压的nacos目录 COPY --frominstaller [/home/nacos, /home/nacos] # 复制启动脚本需要从官方nacos-docker仓库获取对应的arm版启动脚本 ADD build/bin/docker-startup.sh bin/docker-startup.sh # 创建日志目录并设置输出 RUN mkdir -p logs \ cd logs \ touch start.out \ ln -sf /dev/stdout start.out \ ln -sf /dev/stderr start.out RUN chmod x bin/docker-startup.sh EXPOSE 8848 ENTRYPOINT [bin/docker-startup.sh]注意docker-startup.sh这个启动脚本需要从 Nacos 官方的 docker 仓库nacos-group/nacos-docker对应版本v2.3.1中获取并放置在你的源码build/bin/目录下。这个脚本负责在容器内以正确的参数启动 Nacos。7.3 使用CI/CD管道构建镜像可选但推荐手动构建镜像容易出错我推荐使用 Jenkins 或 GitLab CI 等工具自动化这个过程。这里给出一个 Jenkins Pipeline 脚本的示例它直接在 ARM 构建节点label arm64上执行确保构建出的镜像就是 ARM 原生版本。pipeline { agent { docker { image your-registry.com/library/arm64/maven-arm64:3.5.3 // ARM版Maven构建镜像 args -v /root/.m2:/root/.m2 -v /usr/bin/docker:/usr/bin/docker -v /var/run/docker.sock:/var/run/docker.sock label arm64 } } stages { stage(Build Nacos) { steps { sh mvn -Prelease-nacos -Dmaven.test.skiptrue -Dpmd.skiptrue -Dcheckstyle.skiptrue clean install -U } } stage(Build Push Docker Image) { steps { withCredentials([usernamePassword(credentialsId: your-harbor-cred, passwordVariable: HPASSWD, usernameVariable: HUSER)]) { sh docker build -f Dockerfile_arm -t your-registry.com/your-project/nacos-arm64:2.3.1-highgo . docker login your-registry.com -u $HUSER -p $HPASSWD docker push your-registry.com/your-project/nacos-arm64:2.3.1-highgo } } } } }这个 Pipeline 做了两件事1. 在 ARM 节点上编译打包 Nacos2. 使用我们写的Dockerfile_arm构建 Docker 镜像并推送到私有镜像仓库。7.4 在生产环境部署最后在你的 ARM 架构生产服务器上就可以通过 Docker 命令拉取并运行我们定制好的镜像了。docker run -d \ --name nacos-server \ -p 8848:8848 \ -e MODEstandalone \ # 单机模式集群模式需配置其他参数 -e SPRING_DATASOURCE_PLATFORMhighgo \ -e DB_URL_0jdbc:highgo://highgo-host:5866/nacos_config?currentSchemanacos_config... \ -e DB_USER_0nacos \ -e DB_PASSWORD_0your_password \ your-registry.com/your-project/nacos-arm64:2.3.1-highgo通过环境变量覆盖数据库连接信息可以避免将敏感信息硬编码在镜像中更符合生产部署的安全规范。走到这里一个完整支持瀚高数据库、并能在 ARM 服务器上原生运行的 Nacos 2.3.1 服务就真正准备好了。整个适配过程从源码层切入理解了 Nacos 的扩展机制最后通过容器化封装形成了一套可复制、可部署的标准化方案。在实际操作中最花时间的部分往往是 SPI 扩展 Mapper 的实现需要仔细核对每一条 SQL 的瀚高兼容性。建议在开发阶段就搭建好瀚高数据库测试环境边写边测效率会高很多。