银河麒麟V10 ARM服务器离线部署Docker与Nacos实操指南
最近给一台银河麒麟V10 ARM架构的服务器做离线部署目标非常明确内网环境完全不能连外网要把 Docker 和 Nacos 都跑起来还得开机自启。整个过程踩了不少坑尤其是 ARM 架构这个词看起来简单实际却决定着你下载的每个包能不能用。这篇就把完整的离线安装流程整理出来从安装包准备、系统预检查、Docker 部署到 Nacos 容器化启动加上我实战中遇到的各种报错和排查思路给要在银河麒麟 ARM 服务器上做离线部署的朋友一个可直接参考的清单。准备工作做足了整个流程其实就是“拷贝、解压、加载镜像、启动容器”这几步。真正让人翻车的往往不是你操作不熟而是包选错了架构、镜像平台不对、端口没放行这类细节。我会把这些地方重点标出来希望能帮你少走几趟弯路。1. 离线部署的整体思路与环境准备1.1 为什么离线部署在 ARM 架构上特别容易出问题绝大多数 Linux 软件的安装方式在能联网的机器上都很简单要么apt install要么yum install再复杂一点的拉个容器镜像完事。但在完全隔离的内网环境里这条路直接堵死你只能提前准备好所有安装包再把它们手动传进服务器。这时候 ARM 架构就成了最大的变量。银河麒麟 V10 可以运行在 x86_64、aarch64、loongarch64 等不同架构上每一个架构都有自己的二进制格式和依赖库。如果在下载软件包时没有选择对应架构的版本哪怕文件名看起来一模一样拷进去之后一执行就会报Exec format error。这就像你把一把内六角扳手拿去拧十字螺丝螺纹都能对上一点但实际咬合不了。所以离线安装的第一步不是动手操作而是先确认这套服务器到底是什么系统、什么架构、缺什么工具。1.2 开工前先确认系统版本、架构和基础工具不要凭直觉判断服务器架构直接上命令看。我自己的习惯是执行这几条cat /etc/os-release uname -m uname -r getconf LONG_BIT以我手头这台机器为例输出大概是NAMEKylin Linux Advanced Server VERSIONV10 SP2 IDkylin ID_LIKEcentosuname -m输出aarch64说明这是 ARM 64 位架构必须下载 aarch64/arm64 的软件包。如果输出是x86_64那你下面所有包都要换成 amd64 架构。getconf LONG_BIT输出 64则是 64 位系统几乎可以确定不需要去考虑 32 位兼容的问题。这一步的价值是帮你确定整个离线目录的“采购清单”。银河麒麟 V10 还有基于 Debian 体系的版本这时包管理工具可能是dpkg/apt也可能只有rpm/yum。我这次用的服务器是 RPM 系但为了避开包依赖的差异Docker 我直接选择了官方静态二进制包安装Nacos 则用容器镜像方式启动。这样就避免了很多“缺一个依赖、少一个库”的问题。1.3 离线安装包准备清单离线安装包不是指某一个压缩包而是一整套完整资源。我在离线环境部署 Nacos 时会准备以下几类东西资源用途格式来源Docker 静态二进制包安装 Docker 引擎tar.gzDocker 官方 static 包Nacos Server 镜像以容器方式运行 Nacostar 镜像文件在联网机器上docker pullMySQL 镜像Nacos 配置数据存储tar 镜像文件在联网机器上docker pullNacos 初始化 SQL初始化数据库表结构.sql 文件Nacos 官方仓库或镜像内拷贝sha256sum 校验工具校验包完整性系统自带无需额外准备在联网机器上我会先建立一个/data/kylin-offline目录把这些包全部按类别放好再通过 U 盘或内网传输工具整个拷贝到目标服务器。不要一个个零散传很容易丢包也容易漏。后面我会详细说每个文件的获取方式和具体命令。2. 银河麒麟 V10 系统预检查与基础配置2.1 普通用户密码修改和 docker 权限组很多朋友在拿到一台服务器时只有一个普通用户账号安装软件需要切换到 root或者临时提权。修改普通用户密码用一条命令就能解决并不复杂。如果你是 root 用户直接执行passwd 用户名然后按照提示连续输入两次新密码即可。如果你是普通用户想修改自己的密码可以执行passwd系统同样会要求输入当前密码和新密码。这个操作和架构、发行版关系不大银河麒麟 V10 上也是这样处理。另外后面我们用普通用户执行 Docker 命令时可能会遇到Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?明明 Docker 已经启动了普通用户还是连不上是因为/var/run/docker.sock的权限默认属于 root 组。解决办法就是把当前用户加入 docker 组usermod -aG docker 用户名执行完之后必须退出重登或者直接newgrp docker刷新会话否则组权限不会立即生效。这是我经常看到新手卡住的地方。2.2 防火墙、Swap 和文件句柄限制内网环境很多人会图省事直接把防火墙关掉。做测试可以生产环境我不建议这么做。更稳妥的做法是只放行需要用到的端口。先确认防火墙状态systemctl status firewalld如果这台机器以前没被配置过你可以在当前测试阶段临时停掉systemctl stop firewalld systemctl disable firewalld等你上线 Nacos 后再根据实际端口策略放行。Nacos 2.x 版本除了 8848 端口还需要放行 9848、9849 端口这个我在后面的坑位里会重点说。文件句柄上限对 Nacos 这类高并发服务也比较重要。可以临时查看ulimit -n如果值比较小比如 1024建议调整到更大的数值。临时调整可以ulimit -n 65535永久调整需要修改/etc/security/limits.conf在文件末尾加上* soft nofile 65535 * hard nofile 65535关于 Swap如果你的服务器内存比较小建议先加内存或者控制 Nacos 的 JVM 内存参数不要指望 Swap 兜底。容器模式下频繁交换会导致性能忽高忽低很不稳定。2.3 目录规划与文件传输在目标服务器上我会先规划好目录mkdir -p /opt/offline/packages mkdir -p /opt/offline/images mkdir -p /opt/nacos/data mkdir -p /opt/nacos/logs/opt/offline用来放离线包和镜像文件部署完成后这些文件仍建议保留方便日后扩容或回滚。/opt/nacos用作 Nacos 容器挂载的数据和日志目录。文件传输方式看你的现场条件。有内网管理网优先用scp或者sftpscp -r /data/kylin-offline/* root目标IP:/opt/offline/如果只有 U 盘插入后先挂载fdisk -l mkdir -p /mnt/usb mount /dev/sdb1 /mnt/usb cp -r /mnt/usb/* /opt/offline/传完之后用sha256sum对比一下文件哈希确保包在传输过程中没损坏。我是会提前把每个安装包的 sha256 值写在一个SHA256SUMS.txt文件里放到同一目录下到目标机上执行cd /opt/offline sha256sum -c SHA256SUMS.txt只有显示全部 OK才能进入下一步。3. Docker 离线安装与验证3.1 Docker 离线包下载和校验安装 Docker 我选的方案不是yum也不是apt而是直接用 Docker 官方提供的静态二进制包。这种方式最干净不依赖银河麒麟的软件仓库也不会有莫名其妙的依赖缺失。下载地址需要进入 Docker 官方静态二进制目录选择aarch64目录然后找到对应版本。例如我用的版本是 24.0.9wget https://download.docker.com/linux/static/stable/aarch64/docker-24.0.9.tgz注意这里目录必须是aarch64不能手滑下成x86_64。下载完成后把文件的 sha256 值和官方页面上给出的值做对比sha256sum docker-24.0.9.tgz如果和官方公布的值一致说明下载过程没有损坏。ARM 架构的安装包如果来源不正规很影响后续排查所以我建议每次都做校验宁可多花三十秒也不要赌运气。3.2 解压、安装二进制和服务文件先解压tar xf docker-24.0.9.tgz解压之后会产生一个docker目录里面包括 docker、dockerd、containerd、containerd-shim-runc-v2、ctr、docker-init、docker-proxy 等文件。把这些文件全部复制到系统路径cp docker/* /usr/bin/然后验证一下版本docker version这一步只能看到 Client 版本服务端还没有启动。要让 Docker 通过 systemd 托管需要手动创建服务文件。创建/etc/systemd/system/docker.service[Unit] DescriptionDocker Application Container Engine Documentationhttps://docs.docker.com Afternetwork-online.target firewalld.service containerd.service Wantsnetwork-online.target Requiresdocker.socket [Service] Typenotify ExecStart/usr/bin/dockerd -H fd:// --containerd/run/containerd/containerd.sock ExecReload/bin/kill -s HUP $MAINPID TimeoutSec0 RestartSec2 Restartalways LimitNOFILEinfinity LimitNPROCinfinity LimitCOREinfinity TasksMaxinfinity Delegateyes KillModeprocess [Install] WantedBymulti-user.target再创建/etc/systemd/system/docker.socket[Unit] DescriptionDocker Socket for the API [Socket] ListenStream/var/run/docker.sock SocketMode0660 SocketUserroot SocketGroupdocker [Install] WantedBysockets.target这两个文件是 Docker 能开机自启、并通过 socket 方式被普通用户访问的关键。设好之后重新加载 systemdsystemctl daemon-reload systemctl enable --now docker.socket systemctl enable --now docker.service为什么非要走 systemd 管理因为服务器重启后我们希望 Docker 能自动拉起后面 Nacos 容器也要设置restartalways才能保证整套服务在断电重启后不用人工干预。3.3 启动 Docker 并验证架构启动完成后立刻看一次版本号docker version正常会同时输出 Client 和 Server 信息。再确认当前 Docker 运行的平台架构docker info | grep Architecture我在 ARM 机器上执行后输出是Architecture: aarch64如果你看到的是x86_64那说明你装错包了。还有一种情况是Failed to start docker.service: Unit docker.service not found.多半是 service 文件没有放到正确路径或者没有执行systemctl daemon-reload。如果你需要在内网使用 Docker 命令行但机器上没有cgroup权限或者内核模块不完整启动 dockerd 时会报failed to start daemon: Devices cgroup isnt mounted这种情况通常是系统没挂载 cgroup 相关文件系统。可以执行mount -t cgroup -o devices cgroup /sys/fs/cgroup/devices但更推荐先检查内核参数确认/sys/fs/cgroup正常。银河麒麟 V10 服务器版一般内核都完整只要你的容器运行时相关模块没被裁剪问题不大。3.4 在联网机器上准备 ARM 架构的镜像 tar 包离线环境没有 Docker Hub 可拉镜像必须在能联网的机器上提前拉好并导出为 tar 文件。这里有个非常容易踩的坑如果联网机器是 x86_64 架构默认执行docker pull拉下来的镜像是 amd64 版本拿到 ARM 服务器上docker load后虽然能加载成功但一启动容器就会报exec format error所以在联网机器上准备镜像时必须保证镜像平台是linux/arm64。最简单的方式是在一台 ARM 架构且有公网访问的机器上拉取docker pull nacos/nacos-server:v2.3.2 docker pull mysql:8.0.36如果只有 x86_64 的联网机器可以用 Docker 的--platform参数拉取指定平台镜像docker pull --platform linux/arm64 nacos/nacos-server:v2.3.2 docker pull --platform linux/arm64 mysql:8.0.36拉取后检查一下镜像架构确认无误再导出docker image inspect nacos/nacos-server:v2.3.2 --format {{.Architecture}}输出应该是arm64。然后保存镜像docker save -o nacos-server-v2.3.2.tar nacos/nacos-server:v2.3.2 docker save -o mysql-8.0.36.tar mysql:8.0.36docker save可以保留镜像的完整元数据包括架构信息。导出的 tar 文件会和安装包一起传到目标服务器的/opt/offline/images/目录。到了目标服务器上加载镜像docker load -i /opt/offline/images/nacos-server-v2.3.2.tar docker load -i /opt/offline/images/mysql-8.0.36.tar加载完成后用docker images看一下镜像列表确认标签和架构正常。4. Nacos 离线部署与配置4.1 Nacos 版本选型与安装方式Nacos 在 ARM 上没有特殊限制它是 Java 写的只要镜像平台和 JDK 平台正确运行方式基本一致。我在生产里倾向使用 2.x 版本这里以v2.3.2为例功能稳定API 也比较成熟。安装方式有两种一种是直接用 tar 包部署原生 Nacos需要自己装 JDK另一种是用 Docker 容器运行就省去了手动配 JDK 的麻烦。我这次选的是容器化方式因为离线环境下 JDK 包又是个额外依赖容器镜像里已经内置好了省事很多。4.2 快速跑通最简单的单机模式最快速验证离线包是否正常的方法是先用 Nacos 内置的 Derby 数据库跑单机模式。Derby 是嵌入式的不需要额外准备数据库适合第一次在内网把链路打通。创建一个 Docker 网络方便后面接入 MySQLdocker network create nacos-network然后启动单机 Nacosdocker run -d \ --name nacos \ --network nacos-network \ -p 8848:8848 \ -p 9848:9848 \ -e MODEstandalone \ nacos/nacos-server:v2.3.2启动后观察日志docker logs -f nacos看到类似Nacos started successfully in stand alone mode. use embedded storage说明 Nacos 已经启动成功。再用curl探测健康状态curl http://localhost:8848/nacos/v1/console/health/readiness返回true就说明客户端接口正常。打开浏览器访问http://服务器IP:8848/nacos就能看到控制台登录页默认用户名密码都是nacos。需要注意Nacos 2.x 同时依赖 8848 和 9848 端口。8848 是 HTTP 主端口9848 是 gRPC 通信端口如果只映射了 8848客户端注册服务时依然会失败。这个坑我踩过一次后面专门讲。4.3 改用 MySQL 持久化生产推荐单机 Derby 只适合验证环境数据一旦容器删除就全没了。生产环境建议用 MySQL 持久化。我在离线包中准备了 mysql:8.0.36 镜像现在把它启动到同一个网络里。先创建 MySQL 容器docker run -d \ --name mysql8 \ --network nacos-network \ -p 3306:3306 \ -e MYSQL_ROOT_PASSWORDroot \ -e MYSQL_DATABASEnacos_config \ -v /opt/nacos/mysql-data:/var/lib/mysql \ --character-set-serverutf8mb4 \ --collation-serverutf8mb4_unicode_ci \ --restartalways \ mysql:8.0.36MySQL 启动需要一点时间用日志确认docker logs -f mysql8看到ready for connections就说明数据库起来了。然后导入 Nacos 官方初始化 SQL表结构文件需要在联网阶段准备好。我通常是从 Nacos 镜像里直接拷贝出来docker run --rm nacos/nacos-server:v2.3.2 cat /home/nacos/conf/mysql-schema.sql mysql-schema.sql离线环境下这一步在联网机器操作得到mysql-schema.sql后随镜像一起带进内网。再把它传入 MySQLdocker exec -i mysql8 mysql -uroot -proot nacos_config mysql-schema.sql导入成功后重新启动一个使用 MySQL 存储的 Nacos 容器docker run -d \ --name nacos-mysql \ --network nacos-network \ -p 8848:8848 \ -p 9848:9848 \ -e MODEstandalone \ -e SPRING_DATASOURCE_PLATFORMmysql \ -e MYSQL_SERVICE_HOSTmysql8 \ -e MYSQL_SERVICE_DB_NAMEnacos_config \ -e MYSQL_SERVICE_USERroot \ -e MYSQL_SERVICE_PASSWORDroot \ -e MYSQL_SERVICE_PORT3306 \ -v /opt/nacos/logs:/home/nacos/logs \ --restartalways \ nacos/nacos-server:v2.3.2注意这里MYSQL_SERVICE_HOST写的是 MySQL 容器名mysql8因为两个容器在同一个自定义网络里可以通过容器名互相访问。如果用 Docker 默认 bridge 网络容器名解析不一定好用所以我建议都放到nacos-network里。4.4 Nacos 配置中心的实际验证部署完不能只看控制台能打开还要实际验证一下配置中心功能。最直接的方式是用 curl 发布一条配置再读取出来。发布配置curl -X POST http://localhost:8848/nacos/v1/cs/configs?dataIdtest.propertiesgroupDEFAULT_GROUPcontentapp.namenacos-demo读取配置curl http://localhost:8848/nacos/v1/cs/configs?dataIdtest.propertiesgroupDEFAULT_GROUP如果返回app.namenacos-demo说明配置中心读写正常。服务注册发现功能可以通过控制台左侧“服务管理”页面看到注册上来的服务。如果只有 Nacos 本身没有服务列表也不用急等后续业务服务接入后自然会有。4.5 端口放行与开机自启容器已经设置了--restartalways服务器重启后 Docker 会把 Nacos 和 MySQL 自动拉起。这是容器部署相比原生部署最大的优势我不需要再去写一堆开机脚本。但如果环境里有防火墙外部机器仍访问不了控制台。放行端口如下firewall-cmd --permanent --add-port8848/tcp firewall-cmd --permanent --add-port9848/tcp firewall-cmd --permanent --add-port9849/tcp firewall-cmd --reload9849 端口同样用于 gRPC通常也用得上直接一起放行。如果系统用的是ufw则对应ufw allow 8848/tcp ufw allow 9848/tcp ufw allow 9849/tcp我个人的做法是先确认容器能跑起来再考虑防火墙规则。很多时候容器端口已经映射了防火墙没放行外部 socket 连不上排查了很久才发现问题出在防火墙上这种低级的坑最浪费时间。5. 常见问题与排查技巧实录5.1 容器启动报 exec format error这个报错我遇到过不止一次几乎都是镜像架构和宿主机架构不匹配引起的。比如你在 x86_64 机器上docker pull了默认的nacos/nacos-server镜像然后把镜像传到 ARM 服务器上启动就会报standard_init_linux.go:228: exec user process caused: exec format error排查办法很简单docker image inspect nacos/nacos-server:v2.3.2 --format {{.Architecture}}如果镜像在 ARM 服务器上显示的架构不是arm64那就说明来源镜像不对。解决办法是回到联网机器用--platform linux/arm64重新拉取再 save 一次。5.2 Docker 服务启不来日志里有 device or resource busy这个报错大多和旧版 Docker 残留进程有关。如果你以前用脚本启动过 Docker再切到 systemd 托管时旧进程可能还占着/var/run/docker.sock或相关文件。现场可以直接systemctl stop docker pkill dockerd pkill containerd systemctl start docker如果依然不行可以检查 systemd 的服务状态systemctl status docker -l journalctl -u docker -n 100日志是定位问题最直接的信息。不要只看最后一句多翻几十行有时候真正起不来的原因在中间部分。5.3 Nacos 控制台能打开但客户端总是注册不上服务这个坑很隐蔽。Nacos 2.x 引入 gRPC 之后客户端会额外连接 9848 端口。如果你只放行了 8848控制台可以正常访问但服务注册、配置订阅都会超时。当时现场表现是Spring Cloud 服务启动时反复重试连接控制台里看不到服务列表但 Nacos 容器本身日志却没有任何崩溃信息。排查方法ss -lnt | grep -E 8848|9848确认两个端口都在监听。然后检查服务器防火墙和安全组策略把 9848、9849 都加入放行列表。如果是 Docker 映射端口注意-p 9848:9848不要漏掉。5.4 Nacos 容器经常 OOM日志显示内存不够Nacos 默认 JVM 参数比较保守所以在小内存服务器上比较容易撞到内存上限。低配服务器比如 4G 内存同时跑 MySQL 和 Nacos 时我建议显式设置 JVM 内存环境变量-e JVM_XMS512m \ -e JVM_XMX512m \ -e JVM_XMN256m \这三个参数分别控制初始堆、最大堆和新生代大小。配合容器的内存限制一起使用--memory1g这样至少能保证不会因为 Nacos 把整台服务器的内存吃光把 MySQL 也带崩。5.5 离线安装其他软件时缺依赖的通用处理方式如果在银河麒麟 V10 上用rpm或dpkg安装软件时提示缺依赖最简单的思路是优先找静态编译版本或容器镜像。Docker 容器之所以适合离线部署就是因为它把所有依赖都封装好了。如果一定要用系统包管理方式RPM 系可以尝试rpm -ivh xxx.rpm --nodeps或者yum localinstall xxx.rpm -y但--nodeps是强行走捷径系统里如果真缺了运行库装完后软件照样跑不起来到时候排查更头疼。所以能用容器、尽量用容器这个观点我每次离线部署都会反复提。6. 安装包整理与后续扩展6.1 做一个完整的离线软件仓库目录离线部署最容易出现的问题不是不会装而是不知道有哪些包漏了。我习惯把所有离线资源组织成固定目录目录结构如下/opt/offline/ ├── packages/ │ └── docker-24.0.9.tgz ├── images/ │ ├── nacos-server-v2.3.2.tar │ └── mysql-8.0.36.tar ├── sql/ │ └── mysql-schema.sql └── SHA256SUMS.txt其中SHA256SUMS.txt记录了每个文件的哈希值方便在目标服务器上做完整性校验。这样即使部署中断、重新再来也可以快速确认资源没有缺失。我也建议在目录里写一个README.md把命令和注意事项随手记录下来别太过相信自己的记忆力过两三个月回看很多细节都会变得模糊。6.2 用同样的思路扩展部署 Nginx、MySQL 等中间件当你把“离线安装包 镜像导入 容器启动”这套流程跑顺之后再部署其他中间件基本都是复制黏贴的事。比如离线部署 Nginx你只需要在联网机器拉取nginx:1.24.0镜像保存、传输、加载然后启动容器时挂载好配置目录和日志目录就行。银河麒麟服务器上跑这些容器中间件跟其他 Linux 发行版没有本质区别。你只需要记住三条原则选择正确的 ARM 架构包、在隔离环境外提前准备镜像、用 systemd 或容器自启策略保证服务拉起。这三点想清楚整个离线部署的稳定性和后续维护难度都会大大降低。这次部署做完之后我最大的一个体会是离线环境并不可怕怕的是在“不确定”的状态下动手。每下载一个包都要确认架构每传一个文件都要做校验每启动一个服务都要看日志。磨刀不误砍柴工前期多花五分钟做检查比后期排查半小时要强得多。如果你也在银河麒麟 V10 ARM 服务器上折腾离线安装希望能从这篇记录里找到几条有用的路径。