资讯动态

Docker部署Nacos完整实战:从单机到三节点集群避坑指南

发布时间:2026/10/19 5:47:46 来源:尧图企业网站定制
一看到“Docker安装Nacos”这个需求很多人的第一反应就是docker run一个8848端口拉起来就完事。真正实操过的人都知道这套流程远不是一条命令那么简单版本怎么选、端口要映射哪几个、数据存在哪里、单机和集群怎么切、鉴权要不要开任何一个环节没想清楚后面就是连环坑。这篇文章我打算把Docker部署Nacos这件事从头到尾讲透内容包括镜像选型、端口规划、MySQL持久化、单机部署、三节点集群编排、鉴权配置以及我实际调试中遇到的坑和排查方法。内容适合两类人一类是刚接触Nacos、想用Docker快速搭一套环境来学习的开发者另一类是已经在微服务容器化改造中准备把Nacos从单机迁到集群的团队。1. 动手部署Nacos之前先把版本、模式、持久化这三件事定下来很多人一上来就搜命令其实部署一个中间件第一步永远是做选择题。Nacos的部署方式不像Redis那样无脑起一个容器就行它有三个前置问题必须想清楚用哪个版本、跑单机还是集群、数据放哪里。这三个问题不解决后面无论怎么配都会有隐患。1.1 版本选择别直接用latest先看1.x和2.x的区别Nacos的官方镜像名是nacos/nacos-serverDocker Hub上有历史版本tag也有latest。我的建议非常明确不要用latest一定要指定一个具体的版本号比如v2.5.1。原因很简单容器化部署最大的优势是可复现但latest是漂移的今天拉的和下周拉的可能根本不是同一个东西。你今天部署成功下个月同事再部署一遍可能就遇到新版本的兼容性问题。更关键的是1.x和2.x在通信协议上有本质差异。1.x时代客户端和服务端之间的交互基本依赖8848这个HTTP端口部署简单只映射8848基本够用。2.x之后Nacos引入了gRPC通信除了8848之外还额外占用了9848和9849等端口。如果还沿用1.x的思路只映射8848会出现一个非常经典的现象控制台能打开、页面看着一切正常但微服务客户端死活注册不上去日志里报连接超时或无法连接。这个坑我后面在排查章节还会单独讲。所以结论是新项目直接选2.x的最新稳定版本客户端SDK也尽量选配套的新版本。版本跨度不要拉太大2.4的客户端配2.0的服务端大概率会遇到协议兼容问题。1.2 单机还是集群先认清自己的需求别为了“高可用”而上集群Nacos支持两种工作模式standalone单机模式和cluster集群模式。这个选择不难但容易被过度设计。如果你是本地开发、个人学习、或者公司内部一个几十个人的测试环境单机模式完全够用。一条命令跑起来控制台能登录服务能注册配置能下发这就是它的全部使命。如果是生产环境或者你希望服务在节点宕机后依然不被中断那么集群模式是必须的。Nacos集群至少需要3个节点节点之间通过Raft协议做一致性协调配合外部MySQL做数据共享。3个节点可以容忍1个节点挂掉5个节点可以容忍2个所以生产环境推荐奇数节点。有一个细节很多人不知道如果启动容器的时候不设置MODEstandaloneNacos有时会默认按集群模式去尝试启动然后因为没有找到其他集群节点进程直接报错退出。我第一次部署时就因为这个吃了亏当时以为是镜像问题查了半天才发现只是少了一个环境变量。1.3 持久化方案内置Derby还是外部MySQL直接决定数据安全Nacos默认使用内置的Derby数据库。Derby的好处是零依赖、开箱即用拉一个镜像起来就能跑不需要准备任何外部依赖。但它的坏处也很致命数据库文件在容器内部一旦容器被删除你在控制台里创建的所有配置、所有命名空间全部灰飞烟灭。如果你只是本地体验用Derby没问题。但只要你打算让Nacos承载稍微正式一点的业务就应该切换到外部MySQL。生产环境就更不用说了必须用MySQL而且要定期备份。原因是MySQL是独立于容器之外的数据源容器挂了、镜像换了、节点迁移了数据都还在而Derby和容器绑定容器生命周期等于数据生命周期。我用一个简单的对比表来总结使用场景推荐持久化方式原因本地快速体验内置Derby零依赖拉起来就跑测试环境外部MySQL环境可以随时重建数据不丢生产环境外部MySQL加定时备份数据可迁移、可恢复、可审计这个选择还会直接影响后面上集群的难度。如果一开始就用了MySQL以后从单机扩到集群只是改配置的事如果一开始用Derby后面迁移数据反而是一件麻烦事。2. 单机部署Nacos的完整实战从初始化数据库到开启鉴权这一章我会把单机部署的全过程走一遍包括准备MySQL、用docker run快速验证、用docker compose固化部署配置、以及最后开启鉴权保护控制台。每一步我都会说清楚为什么这么做。2.1 第一步先把MySQL数据库和账号准备好使用外部MySQL时需要先创建一个数据库并导入Nacos的初始化脚本。Nacos的表结构脚本在镜像内其实是有的不需要去网上单独下载。最稳妥的做法是用一个临时容器把脚本导出来docker run --rm nacos/nacos-server:v2.5.1 sh -c cat /etc/nacos/conf/nacos-mysql.sql /opt/nacos/nacos-mysql.sql这段命令的意思是启动一个临时容器把容器里的nacos-mysql.sql文件内容重定向到宿主机。拿到脚本之后先在MySQL里创建数据库推荐使用utf8mb4字符集然后导入表结构mysql -h 127.0.0.1 -P 3306 -uroot -p -e CREATE DATABASE nacos_config DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; mysql -h 127.0.0.1 -P 3306 -uroot -p nacos_config /opt/nacos/nacos-mysql.sql这里有个容易踩的坑字符集必须指定清楚。如果MySQL数据库的字符集不是utf8mb4导入脚本时某些表可能创建失败或者后面写入配置时出现中文乱码。检查字符集的命令是SHOW CREATE DATABASE nacos_config;看到utf8mb4就对了。数据库建完之后建议单独创建Nacos专用的MySQL账号不要直接用root跑业务。理由是容器化的Nacos连接信息是以环境变量的方式明文写在compose文件里的用最小权限账号能把风险控制在有限的数据库范围内CREATE USER nacos% IDENTIFIED BY 这里填一个强密码; GRANT ALL PRIVILEGES ON nacos_config.* TO nacos%; FLUSH PRIVILEGES;注意授权范围这里要写清楚。如果你的MySQL和Docker容器在同一台宿主机上nacos账号的host范围可以写localhost也可以写%。但如果Nacos容器在另一台服务器上host范围必须包含那台服务器的IP段否则Nacos连接MySQL时会报Host is not allowed to connect to this MySQL server。2.2 第二步用docker run快速跑通第一版数据库准备好之后先用一条docker run命令把Nacos拉起来。我下面这条命令是经过实际验证的可以直接参考docker run -d \ --name nacos-server \ -p 8848:8848 \ -p 9848:9848 \ -p 9849:9849 \ -e MODEstandalone \ -e NACOS_AUTH_ENABLEtrue \ -e NACOS_AUTH_TOKEN你的Base64密钥 \ -e NACOS_AUTH_IDENTITY_KEYserverIdentity \ -e NACOS_AUTH_IDENTITY_VALUEsecurity \ -e MYSQL_SERVICE_HOST192.168.1.101 \ -e MYSQL_SERVICE_PORT3306 \ -e MYSQL_SERVICE_DB_NAMEnacos_config \ -e MYSQL_SERVICE_USERnacos \ -e MYSQL_SERVICE_PASSWORD你的MySQL密码 \ -e TZAsia/Shanghai \ -v /opt/nacos/logs:/home/nacos/logs \ --restartalways \ nacos/nacos-server:v2.5.1这里每一个参数都有明确作用。MODEstandalone指定单机模式这是最容易漏掉的一项漏了就可能出现之前说的按集群模式启动失败的问题。端口映射方面8848是主HTTP端口控制台就是通过它访问的客户端SDK的server-addr也填这个端口的地址9848和9849是2.x的gRPC通信端口必须和8848一起映射出来。很多教程只提8848结果客户端能访问控制台但注册不上服务问题就出在这里。NACOS_AUTH_*这组变量是鉴权配置生产环境必须开后面我会单独展开说。MYSQL_SERVICE_*是外部MySQL连接信息TZAsia/Shanghai解决容器内日志时间比北京时间慢8个小时的问题别看它小排查问题的时候时间对不上会非常痛苦。最后通过-v把日志目录挂载到宿主机方便直接查看和日志采集。启动完成后浏览器访问http://你的主机IP:8848/nacos看到控制台首页就算成功。如果开启了鉴权默认账号密码是nacos/nacos登录后第一件事是去改掉默认密码这个习惯能省掉后面很多安全风险。2.3 第三步用docker compose固化部署配置docker run适合快速验证但不适合作为正式交付方式。生产环境我更推荐docker compose原因很简单一条命令启动整个服务配置项以文件形式存在可以进Git做版本管理同事拿到文件就能复现一套一模一样的环境。下面是我常用的单机compose配置version: 3.8 services: nacos: image: nacos/nacos-server:v2.5.1 container_name: nacos-server restart: always ports: - 8848:8848 - 9848:9848 - 9849:9849 environment: MODE: standalone TZ: Asia/Shanghai NACOS_AUTH_ENABLE: true NACOS_AUTH_TOKEN: 你的Base64密钥 NACOS_AUTH_IDENTITY_KEY: serverIdentity NACOS_AUTH_IDENTITY_VALUE: security MYSQL_SERVICE_HOST: 192.168.1.101 MYSQL_SERVICE_PORT: 3306 MYSQL_SERVICE_DB_NAME: nacos_config MYSQL_SERVICE_USER: nacos MYSQL_SERVICE_PASSWORD: 你的MySQL密码 volumes: - ./logs:/home/nacos/logs - ./data:/home/nacos/data启动命令就一行docker compose up -d修改配置之后也不用重新创建容器直接docker compose up -d让compose检测到文件变化并重新应用配置即可。这里需要注意YAML格式的一个细节布尔值的写法。NACOS_AUTH_ENABLE的值建议写成true而不是裸的true。为什么YAML解析器会把裸的true解析成布尔类型而Nacos容器内的启动脚本期望拿到的是字符串结构环境变量最终变成NACOS_AUTH_ENABLEtrue这个文本。虽然多数情况下两者都能正常工作但为了减少不确定性我习惯统一加引号。数据目录也建议像上面这样挂载出来好处是即使以后切到MySQL容器内产生的缓存数据、临时文件也能随着宿主机目录一起备份这是一种双保险。2.4 第四步开启鉴权别让控制台裸奔Nacos在默认情况下是不开启鉴权的这意味着只要网络能访问到8848端口任何人都能打开控制台、查看和修改你的配置、看到你所有服务的注册列表。开发环境无所谓但生产环境如果这样裸奔等同于把配置中心的大门敞开了。要开启鉴权核心是三个环境变量环境变量作用NACOS_AUTH_ENABLE鉴权总开关设为trueNACOS_AUTH_TOKEN服务端用于校验token的密钥必须是Base64字符串NACOS_AUTH_IDENTITY_KEY、NACOS_AUTH_IDENTITY_VALUE服务端内部身份标识集群节点之间保持一致其中NACOS_AUTH_TOKEN是最容易被配置错的一项。它的生成规则是先准备一段不少于32字节的原始字符串然后进行Base64编码把编码结果填进去。比如echo -n 这里填一个只有你自己知道的随机密钥越长越好 | base64执行后输出的内容就是token的值。注意echo一定加-n参数去掉末尾的换行符否则编码结果里混入换行会导致鉴权校验失败。开启鉴权后不只是控制台需要登录微服务客户端也要做相应配置。以Java体系的微服务客户端为例在bootstrap.yml或application.yml里需要额外配置用户名和密码否则客户端要么拉不到配置要么注册服务的时候被服务端拒绝。还有一个集群相关的坑如果集群里多个节点的NACOS_AUTH_TOKEN不一致节点之间同步数据时会被相互拒绝。现象非常迷惑控制台能正常登录服务列表却时有时无日志里还看不到明显的报错。所以集群部署时所有节点的鉴权参数必须保持一致。3. 从单机升级到三节点集群编排一套能扛生产的Nacos单机版跑通只是第一步如果你的服务要面向正式环境下一步就是搭建集群。这一章我拆一下集群的部署原理然后给出一套用docker compose编排三节点集群的可行方案。3.1 Nacos集群的工作原理与硬性要求Nacos集群的核心逻辑是多个Nacos节点共享同一个MySQL数据源节点之间通过Raft协议进行状态同步和选主。客户端访问任意一个节点都能读到一致的配置数据。如果一个节点挂了其他节点自动接管流量。为了满足这个逻辑集群部署有几个硬性条件至少3个Nacos节点建议奇数因为Raft协议选举需要多数派存活所有Nacos节点都能访问同一个MySQL数据库且库中的表结构一致节点之间的网络必须互通特别是Raft通信端口7848每个节点的时区尽量一致避免日志和数据交互中的时间错乱还有一个容易被忽略的点集群节点之间的注册地址不要用127.0.0.1或localhost。因为Nacos节点在容器里时localhost指向的是容器自己不是另外的节点。正确做法是通过容器编排服务名互相访问下文的compose配置已经处理了这个问题。3.2 编写三节点集群的docker compose下面是一套三节点集群的compose配置做了精简核心思路是一个名为nacos_net的桥接网络里跑三个Nacos容器通过服务名nacos1、nacos2、nacos3互相发现version: 3.8 services: nacos1: image: nacos/nacos-server:v2.5.1 container_name: nacos-server-1 restart: always ports: - 8848:8848 - 9848:9848 - 9849:9849 environment: MODE: cluster TZ: Asia/Shanghai NACOS_SERVERS: nacos1:8848,nacos2:8848,nacos3:8848 NACOS_AUTH_ENABLE: true NACOS_AUTH_TOKEN: 你的Base64密钥 NACOS_AUTH_IDENTITY_KEY: serverIdentity NACOS_AUTH_IDENTITY_VALUE: security MYSQL_SERVICE_HOST: 192.168.1.101 MYSQL_SERVICE_PORT: 3306 MYSQL_SERVICE_DB_NAME: nacos_config MYSQL_SERVICE_USER: nacos MYSQL_SERVICE_PASSWORD: 你的MySQL密码 volumes: - ./logs1:/home/nacos/logs - ./data1:/home/nacos/data networks: - nacos_net nacos2: image: nacos/nacos-server:v2.5.1 container_name: nacos-server-2 restart: always ports: - 8849:8848 - 9849:9848 - 9849:9849 environment: MODE: cluster TZ: Asia/Shanghai NACOS_SERVERS: nacos1:8848,nacos2:8848,nacos3:8848 NACOS_AUTH_ENABLE: true NACOS_AUTH_TOKEN: 你的Base64密钥 NACOS_AUTH_IDENTITY_KEY: serverIdentity NACOS_AUTH_IDENTITY_VALUE: security MYSQL_SERVICE_HOST: 192.168.1.101 MYSQL_SERVICE_PORT: 3306 MYSQL_SERVICE_DB_NAME: nacos_config MYSQL_SERVICE_USER: nacos MYSQL_SERVICE_PASSWORD: 你的MySQL密码 volumes: - ./logs2:/home/nacos/logs - ./data2:/home/nacos/data networks: - nacos_net nacos3: image: nacos/nacos-server:v2.5.1 container_name: nacos-server-3 restart: always ports: - 8850:8848 - 9850:9848 - 9851:9849 environment: MODE: cluster TZ: Asia/Shanghai NACOS_SERVERS: nacos1:8848,nacos2:8848,nacos3:8848 NACOS_AUTH_ENABLE: true NACOS_AUTH_TOKEN: 你的Base64密钥 NACOS_AUTH_IDENTITY_KEY: serverIdentity NACOS_AUTH_IDENTITY_VALUE: security MYSQL_SERVICE_HOST: 192.168.1.101 MYSQL_SERVICE_PORT: 3306 MYSQL_SERVICE_DB_NAME: nacos_config MYSQL_SERVICE_USER: nacos MYSQL_SERVICE_PASSWORD: 你的MySQL密码 volumes: - ./logs3:/home/nacos/logs - ./data3:/home/nacos/data networks: - nacos_net networks: nacos_net: driver: bridge这里面有两个细节值得琢磨。第一三个容器在宿主机上的端口不能一样所以第二个节点的宿主机端口映射为8849、9849、9850第三个节点映射为8850、9850、9851但容器内部的端口始终是8848、9848、9849。第二NACOS_SERVERS写的是容器服务名因为在nacos_net网络里nacos1、nacos2、nacos3这三个名字可以被彼此解析到不需要写宿主机的IP。关于端口对应规律Nacos 2.x在8848主端口基础上会在启动时自动占用884810009848和884810019849这两个gRPC端口所以映射的时候要带上。第三个节点我又额外验证了一次容器内部还是固定三个端口宿主机映射成几个不同的高位端口即可。3.3 用Nginx在集群前面做统一入口集群部署完成后客户端不能直接连接某个具体节点因为如果那个节点挂了客户端不会自动切换到其他节点。正确做法是在集群前面加一个负载均衡入口客户端只需要连接负载均衡的地址。Nginx的upstream配置可以参考下面这段示例upstream nacos_upstream { least_conn; server 127.0.0.1:8848; server 127.0.0.1:8849; server 127.0.0.1:8850; } server { listen 8848; proxy_pass http://nacos_upstream; proxy_set_header Host $host; }要注意的是least_conn负载均衡算法比较适合Nacos这种长连接场景你可以按自己的负载需求调整。客户端侧的server-addr地址统一填Nginx所在的IP和端口例如192.168.1.100:8848。这样当某个Nacos节点宕机后Nginx会把请求转到健康的节点上客户端无感知。3.4 集群部署成功后如何验证集群部署完成后光看容器状态是不够的。我建议按以下顺序做一轮验证先打开任意一个节点的控制台进入“集群管理”下的“节点列表”正常情况下应该能看到三个节点都是UP状态并且选出一个Leader。再去“配置管理”里新建一条测试配置保存后稍等片刻刷新其他节点看配置是否同步出现。最后启动一个微服务客户端连接负载均衡地址确认服务能注册成功并且控制台服务列表中能看到对应实例。如果这些都通过集群基本就算可以交付了。4. 部署Nacos最容易踩的5类坑以及排查命令速查这一章我总结了自己和同事在实际部署中反复遇到过的几类问题希望能帮你少走一些弯路。4.1 服务注册不上先检查9848端口有没有放出去这是Nacos 2.x部署中最高频的故障没有之一。现象非常典型控制台能打开微服务客户端启动时也没有立刻报错但过一会儿就显示连接失败或注册超时。根本原因往往是宿主机的9848端口没有映射出来或者防火墙拦截了9848的入站流量。Nacos客户端在连接时会先通过8848端口获取服务端地址信息然后自动使用9848端口与服务端建立gRPC长连接。如果9848不通客户端就卡在长连接这一步。排查时先在宿主机上执行ss -lntp | grep -E 8848|9848|9849如果只能看到8848监听而看不到9848说明容器端口映射漏了。在compose配置里补上- 9848:9848再重启服务即可。4.2 容器无限重启十有八九是MySQL连不上Nacos容器启动时如果连不上MySQL会不断重试表现就是docker ps -a里状态一直在Restarting。第一时间看日志docker logs --tail 200 nacos-server日志里如果出现MySQL connecting failed或Communications link failure这类关键字重点检查三件事。第一MYSQL_SERVICE_HOST是否写成了localhost或127.0.0.1。在容器里这两个地址指向容器自己不指向宿主机改成宿主机在局域网内的IP。第二MySQL账号是否授权了允许Nacos容器所在IP的访问范围。如果账号host只授权了localhost那Docker容器从外部访问自然会被拒。第三MySQL本身是否开启了TCP/IP监听特别是一些本地MySQL默认只监听localhost需要确认端口对外开放。手动在容器内测试MySQL连通性也是个好习惯docker exec -it nacos-server bash mysql -h 宿主机IP -P 3306 -unacos -p nacos_config能成功进入MySQL命令行就说明网络和账号都没有问题问题出在Nacos的环境变量配置上。4.3 开启鉴权后所有客户端都连不上这个问题的典型场景是不开启鉴权时一切正常开启鉴权后客户端突然全线报错控制台也登不上。排查思路分三层。第一层检查NACOS_AUTH_TOKEN是否满足要求。token必须是Base64编码结果且原始字符串长度不少于32字节。很多人直接填一小段明文或者忘了Base64编码都会导致鉴权校验失败。第二层检查开启鉴权后客户端侧是否有对应的用户名密码配置。服务端开启鉴权后客户端也必须带上身份凭据否则请求会被拒。第三层检查集群各节点的鉴权参数是否完全一致。这个之前提到过token不一致会让节点间的数据同步异常服务列表时有时无。4.4 容器删掉之后配置全没了如果部署时没有切换外部MySQL也没有挂载数据目录那么删除容器后所有配置、命名空间、历史数据都会跟着容器一起消失。解决办法是把持久化切到MySQL并定期备份mysqldump -unacos -p nacos_config /opt/nacos-backup/nacos_$(date %F).sql顺便说一句就算用了MySQL备份这件事也不能省。配置中心里的数据是敏感资产建议至少每天备份一次。恢复时先重新创建数据库再导入备份文件即可。4.5 日志时间差8小时排查问题时晕头转向容器默认时区是UTC比北京时间慢8小时。Nacos日志里记录的时间全是UTC当你拿着业务系统的日志去对应Nacos的报错时间时前后会差8个小时很容易判断错问题的顺序和因果关系。解决方法是启动容器时加上-e TZAsia/Shanghai或者在compose里配置TZ: Asia/Shanghai。这是一个很小但非常影响效率的配置项强烈建议大家从一开始就加上。下面整理一张排查命令速查表建议收藏排查项命令预期结果容器状态docker ps -a --filter namenacos状态显示UpRestartCount较少容器日志docker logs --tail 200 nacos-server无ERROR关键日志端口监听ss -lntp | grep -E 8848|9848|9849三个端口都在监听MySQL连通性mysql -h 宿主机IP -P 3306 -unacos -p -e show databases能看到nacos_config库服务注册结果curl http://localhost:8848/nacos/v1/ns/instance/list?serviceName你的服务名返回注册的实例列表5. 几个提升Nacos容器易用性的细节配置最后分享几个单机容器部署中容易被忽略但能明显提升使用体验的配置项。5.1 显式设置JVM内存参数Nacos在容器内会按照默认JVM配置启动但如果你不显式指定内存参数默认堆内存可能偏大或偏小。在资源受限的环境里建议通过环境变量控制environment: JVM_XMS: 512m JVM_XMX: 512m JVM_XMN: 256m这三个参数分别控制初始堆大小、最大堆大小和新生代大小。我这里给出的是保守值如果你机器内存充足调到1GB或2GB会让Nacos在大量配置推送时表现更稳定。5.2 配置健康检查在docker compose中为Nacos配置健康检查可以让容器编排平台准确感知服务是否就绪healthcheck: test: [CMD-SHELL, curl -fsS http://localhost:8848/nacos/v1/console/health/readiness || exit 1] interval: 30s timeout: 5s retries: 3 start_period: 40sNacos暴露了健康检查端点start_period给足启动时间避免因为启动速度慢触发不必要的容器重启。5.3 配置备份与恢复的常用手段除了MySQL的mysqldump备份Nacos控制台自带了配置导入导出功能在“配置管理”里可以手动批量导出配置适合临时迁移场景。生产自动化备份还是建议走MySQL层面因为控制台的导出操作依赖人工容易漏。5.4 先想清楚再动手比任何命令都重要我个人实际部署过几套Nacos环境从单机到三节点集群都踩过一遍。最深刻的体会是端口、鉴权、持久化这三件事一定要在写第一条命令前先想清楚。单机开发用standalone加MySQL就足够不用一上来就折腾集群生产环境上集群前先想清楚你想要的到底是高可用还是单纯的性能扩展这两种诉求的架构方案并不完全相同。严格按照这个顺序操作下来我部署Nacos的成功率基本就稳定了希望这篇内容也能帮你把这件事一次做对。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑