
简介针对Kylin V10信创环境与arm64硬件架构定制的Nacos 2.4.3 Docker镜像包面向需要在国产操作系统上部署微服务注册中心与配置中心的开发、运维工程师可解决ARM服务器上Nacos安装配置复杂、兼容性难保障的问题。压缩包共23个文件其中7个layer.tar为镜像分层数据9个json文件包含manifest清单与镜像配置7个VERSION文件记录各层元信息整体大小215.64MB便于离线导入与快速交付。已有277人学习下载适用于信创项目及ARM云环境的私有化部署。使用该镜像包可直接通过docker load加载省去在Kylin V10上手动构建镜像的繁琐过程同时基于2.4.3稳定版本保证了服务发现与配置管理功能在arm64架构上的一致表现有助于提升微服务运维效率并满足国产化安全合规要求。1. 为什么我盯上 nacos 2.4.3 的 arm64 镜像x64 镜像在 KylinV10 上直接翻车在国产化服务器上部署注册中心第一脚就踢到铁板。手里是一台飞腾/鲲鹏的 arm64 机器系统是 KylinV10想着 nacos 这种成熟中间件直接 docker pull 就完事结果容器一启动就报 exec format error连日志都没出来。折腾半天发现原因很简单官方镜像默认是 x64 指令集arm64 的 docker daemon 根本没法执行 x86 二进制。这台机器上又没法立刻换架构只能找专门适配 arm64 的镜像包。这份 nacos-2.4.3 arm64 docker 镜像包解决的就是这个场景离线环境、鲲鹏/飞腾/树莓派这类 arm64 机器想跑一个干净、可复现的 nacos 注册中心。它适合所有被架构问题卡住的从业者先确认 arm64 再动手后面每一步都会顺很多。2. 加载并运行 arm64 镜像包从 load 到端口映射细节决定成败2.1 load 后先做三件事确认架构、修正标签、清理残留拿到nacos-2.4.3-arm64.tar.gz后第一反应不是直接docker run而是先确认包里的镜像到底是什么平台、什么标签。离线包在打包时可能保留着原来的仓库地址也可能是从私有仓库导出的不看清就启动后面所有排查都会被镜像名带偏。# 加载离线镜像包-i 指定 tar 包路径 docker load -i nacos-2.4.3-arm64.tar.gz # 列出所有本地 nacos 镜像确认 REPOSITORY 和 TAG docker images | grep nacos # 用 inspect 验证真实架构Architecture 字段必须是 arm64 docker image inspect --format {{.Architecture}} {{.Os}} 镜像名:TAG第一步docker load会把压缩包里的镜像层全部解压到 docker 本地目录。如果这台机器之前加载过同样镜像docker 会复用已存在的层输出里出现Loaded image和Already exists同时存在这不代表出问题。第二步用grep nacos过滤是为了防止本地已经有旧的 x64 镜像避免run的时候选错对象。第三步的Architecture字段是硬标准如果是amd64说明这个包根本不是给 arm64 机器用的直接删除镜像并重新获取如果是arm64则进入下一步。检查完架构后我习惯给镜像重新打一个短标签因为离线包里的原始标签往往很长比如registry.example.com/nacos/nacos-server:v2.4.3-arm64每次docker run敲这么长一串很容易抄错。打标签用 IMAGE ID 最稳妥# 从 docker images 输出里抓 IMAGE ID再打名为 nacos-arm64:2.4.3 的新标签 docker tag $(docker images | grep nacos.*2.4.3 | awk {print $3}) nacos-arm64:2.4.3这里用$(...)命令替换自动获取 ID前提是docker images | grep nacos里只有一行是 2.4.3。如果机器上同时存在其他 tag 的 nacos建议手动执行docker images先看清楚再手工把 IMAGE ID 填进去不要靠 awk 赌输出顺序。打标签只是个软链接同一个 IMAGE ID 可以有多个标签不影响原始数据。如果你担心镜像包在传输过程中被篡改加载前可以校验压缩包的 SHA-256# 计算压缩包哈希和发布方提供的哈希对比 sha256sum nacos-2.4.3-arm64.tar.gz这一步在涉密内网部署时尤其重要多花十秒钟能避免加载到被替换过的坏包。对比一致后继续 load不一致就重新下载。2.2 单机模式启动参数8848/9848/9849 一个都不能少nacos 2.x 默认的 8848 端口是 HTTP 主端口但客户端通信走的是 gRPC端口基于主端口自动偏移。偏移规则是硬编码的主端口 1000 是客户端 gRPC 端口就是 98481001 是服务端通信端口就是 9849。这三个端口在单机模式下都要映射缺一个就会出现“web 控制台能登录但服务注册一直超时”的中间态。docker run -d \ --name nacos \ -p 8848:8848 \ -p 9848:9848 \ -p 9849:9849 \ -e MODEstandalone \ -e PREFER_HOST_MODEhostname \ -e NACOS_AUTH_ENABLEfalse \ nacos-arm64:2.4.3MODEstandalone表示单机模式此时 nacos 会使用内置 derby 数据库不需要外部 MySQL适合第一次验证镜像包可用性。PREFER_HOST_MODEhostname让 nacos 把自己注册时使用的地址设置为宿主机 hostname配合全局配置能减少容器 IP 漂移带来的问题如果你按自己环境已经配置好了域名解析也可以不写。NACOS_AUTH_ENABLEfalse是 2.4.3 的默认值显式写出来是为了让读启动命令的人明确知道当前没开鉴权。启动后用两条命令确认状态# 跟踪日志看到 Nacos started successfully 即为启动完成 docker logs -f nacos # 从宿主机测试 HTTP 端口是否响应 curl -I http://127.0.0.1:8848/nacoscurl -I返回 HTTP 头里的状态码如果是 200 或 302说明 web 控制台已经就绪。这时用浏览器访问http://服务器IP:8848/nacos默认账号密码nacos/nacos。进入后台后左侧能看到“服务管理”和“配置管理”两个主菜单说明镜像包运行正常。此时你可以先创建一个临时 namespace 测试写读再决定是否接 MySQL。如果容器启动后立刻退出别急着怀疑镜像包先执行docker logs nacos看输出。大部分 arm64 上的启动失败都和 JVM 内存计算有关这个在后面的避坑章具体分析。2.3 为什么不建议用 qemu 模拟 arm64性能和稳定性都不值当有人会想到我在 arm64 机器上用docker run --platform linux/amd64跑 x64 镜像让 docker 调用 qemu-user 做指令翻译不也能跑起来吗技术上确实能但实际部署 nacos 时我不推荐这条路。qemu 的二进制翻译会把每条 x86 指令翻译成 arm64 指令执行Java 应用的方法调用、GC 扫描、反射调用都会经过翻译层性能损耗至少 30%。nacos 作为注册中心本质是一个高并发 IO 和心跳处理的系统gRPC 长连接上每个包都要经过 qemuCPU 会被拉高到接近满载。更麻烦的是qemu 模拟下线程调度和系统调用的时序和原生环境不一样我在模拟环境里见过容器内线程数异常增长、epoll 回调丢失导致客户端 registration 超时的诡异现象这类问题根本没有好的日志排查入口。这里给的 arm64 镜像包是原生二进制不需要翻译层CPU 指令直接执行内存占用也少一块翻译缓存的开销。如果有人在 x64 开发机上试图加载这个 arm64 包运行时会报exec format error反过来也是一样。所以架构匹配是第一优先级不要试图用模拟层绕过生产环境绕不过去。3. 接入 MySQL 8.4建库脚本、连接串和配置分层3.1 建库导表docker cp 脚本 utf8mb4 字符集standalone 模式的 derby 数据库适合快速验证但配置中心在生产环境必须接 MySQL。nacos 官方容器内自带建表脚本路径是/home/nacos/conf/mysql-schema.sql。脚本里包含了配置、服务、权限、审计等核心表比如config_info、config_history、service_name等。建库这一步必须用 utf8mb4因为 nacos 配置内容可能包含中文、表情符号旧版 utf8mb3 会报字符集转换错误。# 在 MySQL 宿主机上执行创建专用库 mysql -u root -p -e CREATE DATABASE nacos_config DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; # 从已运行的 nacos 容器里拷贝建表脚本到当前目录 docker cp nacos:/home/nacos/conf/mysql-schema.sql ./mysql-schema.sql # 使用 nacos 账号导入前提是该账号具备建表权限 mysql -u nacos -p nacos_config mysql-schema.sql # 验证表是否齐全config_info 存在即可 mysql -u nacos -p nacos_config -e show tables;第一步建库命令在 MySQL 宿主机的 shell 里执行不要进容器。第二步docker cp需要容器已经启动如果你还没启动 nacos可以先用docker create创建一个临时容器再docker cp用完删除。导入前确认nacos账号对nacos_config库有CREATE、ALTER、INSERT、UPDATE、DELETE、SELECT权限否则导入会中断。导入后show tables的输出里应该有几十张表包括config_info、config_info_aggr、tenant_info、users、roles等。如果只导入了部分表启动时 schema 校验就会报错。很多人在这个地方踩过坑直接进入 nacos 容器执行mysql命令导入。实际上 nacos 基础镜像不一定装 mysql client而且把宿主机的 MySQL 账号塞进容器会留下安全风险。正确做法是让宿主机上的 mysql client 连接远程库执行导入容器只负责运行 nacos 进程。3.2 连接参数拆解caching_sha2_password 和时区nacos 连接 MySQL 是通过环境变量驱动的容器启动时会根据环境变量自动覆盖内部的application.properties。这种方式比手动改配置文件更符合 docker 部署习惯升级镜像版本时不需要重新打补丁。关键参数如下表环境变量作用示例SPRING_DATASOURCE_PLATFORM数据源类型不写则默认 derbymysqlMYSQL_SERVICE_HOSTMySQL 地址不能填容器内 localhost192.168.1.10MYSQL_SERVICE_PORTMySQL 端口3306MYSQL_SERVICE_DB_NAME数据库名nacos_configMYSQL_SERVICE_USER连接账号nacosMYSQL_SERVICE_PASSWORD连接密码Nacos123MYSQL_SERVICE_URL_PARAMJDBC 连接的追加参数allowPublicKeyRetrievaltrueuseSSLfalse...docker run -d \ --name nacos \ -p 8848:8848 \ -p 9848:9848 \ -p 9849:9849 \ -e MODEstandalone \ -e SPRING_DATASOURCE_PLATFORMmysql \ -e MYSQL_SERVICE_HOST192.168.1.10 \ -e MYSQL_SERVICE_PORT3306 \ -e MYSQL_SERVICE_DB_NAMEnacos_config \ -e MYSQL_SERVICE_USERnacos \ -e MYSQL_SERVICE_PASSWORDNacos123 \ -e MYSQL_SERVICE_URL_PARAMallowPublicKeyRetrievaltrueuseSSLfalseserverTimezoneAsia/Shanghai \ nacos-arm64:2.4.3注意密码里的特殊字符。如果密码包含#等整段值要用单引号包裹防止 bash 解释。MYSQL_SERVICE_URL_PARAM中由于有bash 会把它当作后台执行符所以整个参数必须用双引号包裹这是一个非常隐蔽的 shell 陷阱。为什么必须加allowPublicKeyRetrievaltrue因为 MySQL 8.4 默认账号使用caching_sha2_password认证JDBC 驱动在非 SSL 连接下需要先从服务器获取 RSA 公钥来加密密码传输驱动默认禁止这个行为所以会报Public Key Retrieval is not allowed。加上这个参数就是显式放行。useSSLfalse是因为内网环境多数没有给 MySQL 配证书不开 SSL 能省掉 TLS 握手的开销和证书校验的报错。serverTimezoneAsia/Shanghai让 JDBC 用东八区解释 datetime 字段避免控制台和数据库时间相差 8 小时。启动后看日志搜索关键字docker logs nacos | grep -E mysql|MySQL|database看到Connect to MySQL successful或类似的db init success输出说明数据源已经建立。接着连到 MySQL 验证use nacos_config; select count(*) from config_info;能返回一个数字可以是 0就说明表可读。如果报Table nacos_config.config_info doesnt exist回头检查导入的脚本是不是导错了库。3.3 配置分层在 MySQL 里的体现namespace、group、dataId 对应哪张表nacos 配置管理有 namespace、group、dataId 三层概念。很多人背过概念但部署完 MySQL 后还是分不清。你可以在数据库里直接看到这三层的落盘位置这比任何文档都直观。tenant_info表存 namespace默认 public 命名空间在表里并没有显式记录而是以空字符串形式存在只有通过控制台创建的 namespace 才会在tenant_info里插入一行生成带namespace_id的记录。config_info表存配置正文核心字段是data_id、group_id、tenant_id、content、md5。config_info_beta表是 beta 发布的配置灰度发布时会写入这里。-- 查看一条配置在数据库里的完整记录 select data_id, group_id, tenant_id, content, md5 from config_info where data_id application.yml;这条 SQL 可以帮你确认客户端为什么拿不到配置。如果客户端指定了 namespacedev那么它读取的是tenant_id dev的记录而你通过控制台在 public 命名空间发布的配置tenant_id是空字符串两边就对不上。我习惯在接入新环境时先手动在数据库里插入一条测试配置再通过客户端读取验证整条链路。插入时gmt_create和gmt_modified要填当前时间md5字段可以留空nacos 启动后会自行计算。这样可以绕开控制台直接确认 MySQL 权限和数据表结构是否正确。4. 避坑arm64 nacos 部署中我踩过的五个坑4.1 现象docker pull 报 no matching manifest for linux/arm64在内网环境执行docker pull nacos/nacos-server:v2.4.3时返回no matching manifest for linux/arm64 in the manifest list entries原因有两层。第一部分镜像仓库的 tag 并没有构建 arm64 变体manifest 列表里只有 linux/amd64。第二内网镜像同步工具经常只同步了 amd64 的 manifest导致仓库里缺失 arm64 的入口。docker 客户端拉镜像时会自动匹配当前机器的架构匹配不到就直接报错。解决思路不要依赖在线拉取直接用离线镜像包。加载后通过docker image inspect确认架构。如果必须在在线环境拉取可以在拉取命令后面加--platform linux/arm64前提是远端仓库确实存在这个平台的 manifest否则加了也没用。我在内网遇到的情况是同一个 tag 在 Docker Hub 有 arm64但同步到内网时只保留了 amd64这时候离线包是唯一确定的路。4.2 现象容器启动即退出日志显示 Cannot allocate memory在 arm64 小主机上运行容器一两秒就退出docker logs nacos显示Exception in thread main java.lang.OutOfMemoryError: Cannot allocate memory原因nacos 启动脚本会读取宿主机内存大小来自动计算 JVM 堆。如果宿主机只有 2G 内存脚本算出来的最大堆可能是 1G再加上 C2 编译器、metaspace、线程栈容器在 cgroup 限制下直接内存超卖malloc返回不了内存就崩了。这个现象在树莓派 4B、飞腾入门机型上特别常见。解决显式覆盖 JVM 参数不要让脚本自动算。docker run -d \ --name nacos \ -p 8848:8848 \ -p 9848:9848 \ -p 9849:9849 \ -e MODEstandalone \ -e JVM_XMS128m \ -e JVM_XMX256m \ -e JVM_XMN128m \ -e JVM_MS64m \ -e JVM_MMS256m \ nacos-arm64:2.4.3其中JVM_XMS是初始堆JVM_XMX是最大堆JVM_XMN是新生代最大容量JVM_MS是元空间初始值JVM_MMS是元空间最大值。对配置中心来说最大堆 256m 足够支撑日常几千条配置的读写。如果配置项超过一万条再调到 512m不要一开始就给 2G。改完之后重启执行docker stats nacos观察内存占用稳定在 200m 左右是正常的。4.3 现象客户端频繁重连nginx 转发只开了 8848服务客户端能正常注册但每隔几秒就抛connection refused或者client reconnect报警。查了 nginx 和防火墙只放行了 8848。原因nacos 2.x 的客户端注册和配置订阅默认走 gRPC连接的端口是 884810009848。如果网络层只放行 8848客户端向注册中心发起注册时虽然能从服务端拿到 9848 的地址但 TCP 握手连不上客户端就会陷入重连循环。这是 nacos 2.x 和 1.x 最核心的差异很多从 1.x 迁移过来的人都踩过。解决确保 9848 和 9849 同时放通。单机模式下客户端连 9848服务端节点间心跳走 9849。如果前面挂了 nginx要配置 TCP 层的 stream 转发不能用 HTTP 代理# nginx.conf 中的 stream 块注意不是在 http 块里 stream { upstream nacos_grpc { server 127.0.0.1:9848; } server { listen 9848; proxy_pass nacos_grpc; } }这段配置写在 nginx 的stream块中而不是http块。gRPC 是长连接HTTP 层的 proxy_pass 处理不了这种流量。配置好后在客户端机器上测试端口连通性nc -vz 服务器IP 9848返回succeeded就说明端口通了再观察客户端日志重连告警应该消失。4.4 现象MySQL 8.4 报 Public Key Retrieval is not allowednacos 启动日志里出现java.sql.SQLException: Public Key Retrieval is not allowed原因MySQL 8.4 默认用户认证插件是caching_sha2_passwordJDBC 驱动在非 SSL 连接下首次连接时需要获取服务器 RSA 公钥来加密密码传输但驱动默认出于安全考虑禁止自动获取公钥于是抛出这个异常。这不是 nacos 的问题是 JDBC 和 MySQL 8 之间的兼容性约束。解决在MYSQL_SERVICE_URL_PARAM中加入allowPublicKeyRetrievaltrue。顺手把useSSLfalseserverTimezoneAsia/Shanghai一起带上避免这次过了下次又踩时区坑。完整的参数串如下allowPublicKeyRetrievaltrueuseSSLfalseserverTimezoneAsia/Shanghai如果公司安全规范强制要求 SSL那就不能关useSSL需要给 MySQL 配置证书并在连接串里指定 trustStore这是另一个话题。还有一个备选方案是把 nacos 账号改成mysql_native_password插件但 MySQL 8.4 默认禁用了这个插件需要先启用再改账号操作复杂不如在 JDBC 参数里放行公钥来得干净。我一般优先改 URL 参数不动数据库账号。4.5 现象控制台时间是 UTC和实际差 8 小时进入 nacos 控制台创建配置后看到“最近更新时间”显示凌晨 3 点但本地时间是 11 点整整差了 8 小时。原因基础镜像默认没有设置时区容器内系统时间是 UTCJVM 读取系统默认时区也变成 UTC最终写入数据库的时间字段自然偏了 8 小时。解决启动容器时挂载宿主机时区文件并设置 TZ 环境变量docker run -d \ --name nacos \ -v /etc/localtime:/etc/localtime:ro \ -e TZAsia/Shanghai \ ... 其他环境变量 ...在 KylinV10 上宿主机的/etc/localtime已经是指向Asia/Shanghai的符号链接挂载成只读文件即可。改完后重启容器在容器内执行docker exec nacos date如果输出里带CST或0800说明时区已经生效。再到控制台刷新页面更新时间就和本地时间一致了。这个坑不影响注册中心的通信但影响配置变更的审计排查值得在部署时一步修掉。5. 上线前验证与进阶健康检查、鉴权、集群化部署启动只是开始上线前至少验证三个点健康检查接口能通、鉴权规则生效、节点能正确注册到集群。健康检查用 nacos 自带的 readiness 接口。这个接口不走默认控制台路径要带/v1curl http://localhost:8848/nacos/v1/console/health/readiness返回{code:200,message:success}才算就绪。启动过程中这里会返回 503所以它能比日志更准确反映服务是否真正可用。我通常会把这条命令写进 docker 的--health-cmd参数里让 docker daemon 自动做健康检查。鉴权开关在 2.4.3 里默认关闭生产环境必须打开。token 要求 base64 编码后的长度至少 32 字节生成方式如下echo -n nacos-arm64-$(openssl rand -hex 16) | base64把输出填入启动参数-e NACOS_AUTH_ENABLEtrue \ -e NACOS_AUTH_TOKEN生成的base64串 \ -e NACOS_AUTH_IDENTITY_KEYserverIdentity \ -e NACOS_AUTH_IDENTITY_VALUEnacos-arm64-cluster开鉴权后控制台登录不再是默认的nacos/nacos所有 Open API 请求都要带accessToken。注意 cluster 下所有节点的NACOS_AUTH_IDENTITY_KEY和NACOS_AUTH_IDENTITY_VALUE必须一致否则节点间互相认证会失败。集群部署时把MODE改成cluster节点数建议至少三个且为奇数nacos 2.4.3 内置 raft 协议选举 leader。除了 8848、9848、9849集群节点之间还要开放 raft 选举使用的 7848 端口。为了隔离外部流量我一般会给集群单独建一个 docker 网络docker network create nacos-net所有 nacos 容器加入同一网络后容器之间可以通过容器名互相访问不依赖宿主机 IP。节点配置中填的NACOS_SERVERS格式类似nacos1:8848,nacos2:8848,nacos3:8848这里的名字就是网络里的容器名。我的习惯是每次部署一个环境先跑一个deploy.sh把镜像架构检查、端口映射检查、MySQL 连通性检查三件事串成脚本确认通过后线上问题至少少一半。从那以后我在 arm64 服务器上部署 nacos 再也没有因为架构不匹配翻过车。希望这份经验能帮到你。本文还有配套的精品资源点击获取