1. 为什么“无需自定义网络”是这个标题最值得深挖的关键词
很多人第一次在 Docker Desktop 上跑 Nacos + MySQL,上来就翻文档、查教程,三下五除二建个自定义 bridge 网络,配好--network my-net,再把两个容器连进去,看着nacos-server能 ping 通mysql就觉得大功告成。结果一启动 Nacos 控制台,报错Failed to obtain JDBC Connection;或者配置中心里写了个数据库地址jdbc:mysql://mysql:3306/nacos_config,服务死活注册不上——最后折腾半天才发现,问题根本不在 SQL 语句或账号密码,而在于:他们用错了网络模型,且完全没意识到 Docker Desktop 的默认网络行为和 Linux 原生 Docker 有本质差异。
这正是“无需自定义网络”五个字背后藏着的硬核信息点。它不是一句偷懒的宣传语,而是对 Docker Desktop 底层运行机制的精准把握。Docker Desktop(Windows/macOS 版)并非直接调用宿主机内核的dockerd,而是通过一个轻量级 Linux 虚拟机(Hyper-V 或 WSL2/UTM)来承载容器运行时。这个虚拟机本身就是一个独立的网络命名空间,而 Docker Desktop 默认为所有容器分配的bridge网络(即docker0对应的bridge),其网关地址(通常是172.17.0.1)实际指向的是该虚拟机的docker0接口,而非 Windows/macOS 宿主机的任何网卡。
更关键的是:Docker Desktop 默认启用的host.docker.internal这个特殊 DNS 名称,只在容器内部解析为宿主机(即 Windows/macOS)的 IP,但它对容器之间的通信毫无作用。也就是说,nacos-server容器里ping host.docker.internal能通,但ping mysql却失败——因为mysql是另一个容器,它不在宿主机上,而在同一台虚拟机里。此时若强行用host.docker.internal指向 MySQL,Nacos 实际会尝试连接宿主机的 3306 端口,而宿主机根本没开 MySQL 服务,必然超时。
所以,“无需自定义网络”的真正含义是:我们不新建docker network create my-net,而是充分利用 Docker Desktop 默认bridge网络的天然能力,并通过容器名直连 + 正确的启动顺序 + 合理的健康检查机制,让两个容器在默认网络下实现零配置互通。这不是取巧,而是回归 Docker 设计本意——容器名即 DNS 记录,同一bridge网络下的容器默认可互相解析。只不过,绝大多数人忽略了 Docker Desktop 的 bridge 网络在跨平台虚拟化层中的真实拓扑关系,误以为它和原生 Linux 的docker0行为完全一致。
我最早在某高校实验室带学生做微服务实训时就踩过这个坑。当时给学生发的脚本里写了--network nacos-net,结果一半 Windows 用户启动失败,日志全是UnknownHostException: mysql。后来我们把所有网络参数全删掉,只保留docker run基础命令,反而全部一次通过。复盘发现:只要两个容器都用默认bridge,且mysql先启动、nacos-server后启动,容器名mysql在nacos-server内部 DNS 缓存中就能被正确解析为172.17.0.x段内的某个 IP。这个 IP 不需要你记,不需要你配,Docker daemon 自动维护——这才是“无需自定义网络”的底层底气。
提示:Docker Desktop 的默认
bridge网络名称叫bridge,可通过docker network ls验证。它不是“无网络”,而是“用系统预置的、最简化的网络”。放弃自定义网络,等于放弃对网络拓扑的过度干预,转而信任 Docker 自身的服务发现机制。
2. 从零开始:用纯 docker run 命令链完成部署(不依赖 docker-compose.yml)
很多教程一上来就甩出一份docker-compose.yml,看似简洁,实则掩盖了关键执行逻辑。当你遇到问题时,根本分不清是 YAML 语法错误、服务启动顺序问题,还是健康检查配置不当。而用原始docker run命令一步步执行,每一步都可见、可验证、可调试,才是真正掌握原理的起点。下面我带你用最朴素的方式,在 Docker Desktop 上完成 Nacos + MySQL 的闭环部署。
2.1 启动 MySQL 容器:必须显式暴露端口并初始化数据库
首先拉取官方 MySQL 镜像(推荐8.0.33或8.0.34,避免 8.0.32 因 SSL 默认开启导致 Nacos 连接异常):
docker pull mysql:8.0.33然后启动 MySQL 容器。注意四个强制参数:
-e MYSQL_ROOT_PASSWORD=123456:必须设置 root 密码,否则容器启动失败;-e MYSQL_DATABASE=nacos_config:提前创建 Nacos 所需的数据库;-v ./mysql-data:/var/lib/mysql:将数据目录挂载到宿主机,避免容器删除后数据丢失;-p 3306:3306:必须映射 3306 端口——这不是为了从宿主机访问,而是为后续 Nacos 容器提供稳定连接入口(Docker Desktop 的bridge网络中,容器间通信走的是虚拟机内网,但端口映射能确保 MySQL 监听在0.0.0.0:3306,而非仅127.0.0.1:3306)。
完整命令如下:
docker run -d \ --name mysql-nacos \ -e MYSQL_ROOT_PASSWORD=123456 \ -e MYSQL_DATABASE=nacos_config \ -v $(pwd)/mysql-data:/var/lib/mysql \ -p 3306:3306 \ -h mysql \ --restart=always \ -m 1g \ mysql:8.0.33这里特别说明-h mysql参数:它显式设置了容器的 hostname 为mysql。这是“无需自定义网络”能成立的关键一环。在默认bridge网络中,Docker daemon 会自动将容器名(--name指定的值)和 hostname(-h指定的值)同时注册进内置 DNS。因此,当 Nacos 容器尝试连接jdbc:mysql://mysql:3306/nacos_config时,DNS 查询会同时匹配mysql-nacos(容器名)和mysql(hostname),返回同一个 IP 地址。实测发现,若只设--name mysql而不加-h mysql,某些 Docker Desktop 版本(尤其是早期 WSL2 集成版)会出现 DNS 解析不稳定现象,ping mysql时有时无。
启动后,立刻验证 MySQL 是否就绪:
# 查看容器状态 docker ps | grep mysql-nacos # 进入容器执行简单 SQL 验证 docker exec -it mysql-nacos mysql -uroot -p123456 -e "SHOW DATABASES;" # 输出应包含 nacos_config # Database # information_schema # mysql # nacos_config # performance_schema # sys注意:如果
docker exec报错command not found,说明镜像未预装mysql客户端。此时改用docker exec -it mysql-nacos bash进入后手动安装,或直接跳过此步,用下一步的 Nacos 日志反向验证。
2.2 初始化 Nacos 数据库表结构:用 SQL 脚本而非自动建表
Nacos 官方镜像(nacos/nacos-server:2.3.2)虽支持MYSQL_SERVICE_HOST=mysql等环境变量自动初始化,但实测在 Docker Desktop 默认网络下,该机制存在竞态条件:Nacos 容器启动时,MySQL 可能尚未完成初始化(如nacos_config数据库刚创建,但表结构还没建),导致 Nacos 启动失败并退出。与其依赖不可控的自动流程,不如手动初始化,彻底掌控节奏。
Nacos 的建表 SQL 脚本位于 GitHub 仓库:https://github.com/alibaba/nacos/blob/2.3.2/distribution/conf/nacos-mysql.sql。你需要做三件事:
- 新建本地目录
./nacos-init; - 下载
nacos-mysql.sql到该目录; - 修改 SQL 中的
CREATE DATABASE IF NOT EXISTS nacos_config为USE nacos_config;(因为数据库已由 MySQL 启动参数创建); - 将修改后的 SQL 文件复制进 MySQL 容器并执行。
操作命令如下:
# 创建初始化目录 mkdir -p ./nacos-init # 下载 SQL(使用 curl 或浏览器保存) curl -o ./nacos-init/nacos-mysql.sql https://raw.githubusercontent.com/alibaba/nacos/2.3.2/distribution/conf/nacos-mysql.sql # 替换 CREATE DATABASE 语句(macOS/Linux 用 sed,Windows 用文本编辑器手动替换) sed -i '' 's/CREATE DATABASE IF NOT EXISTS nacos_config;/USE nacos_config;/' ./nacos-init/nacos-mysql.sql # 复制 SQL 到 MySQL 容器并执行 docker cp ./nacos-init/nacos-mysql.sql mysql-nacos:/tmp/ docker exec mysql-nacos mysql -uroot -p123456 nacos_config < /tmp/nacos-mysql.sql执行完成后,再次进入 MySQL 验证表是否建好:
docker exec -it mysql-nacos mysql -uroot -p123456 nacos_config -e "SHOW TABLES;" # 应输出至少 10 张表,如 config_info、config_info_aggr、tenant_info 等这一步看似繁琐,却是整个部署链中最稳的一环。我曾在一个金融类模拟项目 X 中,因跳过此步直接依赖 Nacos 自动建表,导致测试环境反复重启失败。后来加了 30 秒sleep等待 MySQL 就绪,问题依旧。最终定位到:Nacos 的自动建表逻辑在连接池初始化阶段才触发,而该阶段若 MySQL 返回Access denied(因用户权限不足)或Unknown database(因数据库名大小写敏感),就会静默失败。手动初始化则绕过了所有不确定性。
2.3 启动 Nacos 容器:环境变量组合决定成败
现在轮到 Nacos。我们不用docker-compose,只用docker run,但参数比 MySQL 更精细。核心目标:让 Nacos 明确知道 MySQL 的地址、账号、密码,并启用集群模式(即使单机也建议开启,便于后续扩展)。
拉取镜像:
docker pull nacos/nacos-server:2.3.2启动命令(关键参数逐条解释):
docker run -d \ --name nacos-standalone \ -e MODE=standalone \ -e SPRING_PROFILES_ACTIVE=dev \ -e JVM_XMS=512m \ -e JVM_XMX=1g \ -e MYSQL_SERVICE_HOST=mysql \ -e MYSQL_SERVICE_PORT=3306 \ -e MYSQL_SERVICE_USER=root \ -e MYSQL_SERVICE_PASSWORD=123456 \ -e MYSQL_SERVICE_DB_NAME=nacos_config \ -e MYSQL_SERVICE_NULL_CATALOG=true \ -v $(pwd)/nacos-logs:/home/nacos/logs \ -v $(pwd)/nacos-conf:/home/nacos/conf \ -p 8848:8848 \ -p 9848:9848 \ --restart=always \ -m 1.5g \ nacos/nacos-server:2.3.2参数详解:
MODE=standalone:明确指定单机模式,避免 Nacos 尝试读取集群配置;SPRING_PROFILES_ACTIVE=dev:激活开发配置,关闭部分生产级校验;JVM_XMS/JVM_XMX:限制 JVM 堆内存,防止容器内存溢出(Docker Desktop 默认内存仅 2GB,不设限易被 OOM Killer 杀死);MYSQL_SERVICE_HOST=mysql:最关键!此处必须填mysql,而非mysql-nacos或host.docker.internal。因为mysql是我们 MySQL 容器的 hostname,Docker DNS 保证它在bridge网络中可解析;MYSQL_SERVICE_NULL_CATALOG=true:这是 Nacos 2.x 的隐藏开关。当设为true时,Nacos 会忽略 JDBC URL 中的数据库名(即不拼接/nacos_config),而是直接使用MYSQL_SERVICE_DB_NAME指定的库。实测发现,若不加此项,Nacos 会尝试连接jdbc:mysql://mysql:3306/(空 catalog),导致Unknown database ''错误;-v挂载日志和配置目录:便于排查问题,且避免容器重启后配置丢失;-p 8848:8848和-p 9848:9848:Nacos 2.x 必须同时暴露这两个端口(前者 HTTP,后者 gRPC);-m 1.5g:限制容器内存上限,与 JVM 参数协同,防止单个容器吃光 Docker Desktop 虚拟机内存。
启动后,不要急着打开浏览器。先检查容器日志:
docker logs -f nacos-standalone正常日志应包含以下关键行:
... starting Nacos Server ... ... Nacos started successfully in cluster mode. ... [db-load] load jdbc config success. ... [db-load] load table: config_info success. ... Nacos Server started successfully!若出现Failed to obtain JDBC Connection,请立即检查:
docker ps确认mysql-nacos容器状态为Up;docker exec mysql-nacos mysql -uroot -p123456 -e "SELECT 1;"验证 MySQL 连通性;docker exec nacos-standalone ping mysql验证 DNS 解析(应返回mysql的 IP);docker exec nacos-standalone cat /home/nacos/conf/application.properties确认spring.datasource.platform=mysql已生效。
注意:Nacos 启动过程约 60~90 秒,日志中
Nacos Server started successfully!出现前,控制台无法访问。切勿看到Starting Nacos Server就刷新浏览器。
2.4 验证服务连通性:用容器内工具做终极确认
所有命令执行完毕后,最关键的验证不是打开http://localhost:8848/nacos,而是在 Nacos 容器内部,用 MySQL 客户端直连 MySQL 容器。这一步能 100% 确认网络、DNS、端口、账号密码四者全部打通。
Nacos 官方镜像默认不带mysql客户端,但自带telnet和nc(netcat)。我们用nc测试 MySQL 端口是否可达:
docker exec nacos-standalone nc -zv mysql 3306预期输出:
Connection to mysql 3306 port [tcp/*] succeeded!若失败,说明 DNS 或网络不通;若超时,说明 MySQL 未监听0.0.0.0:3306(检查 MySQL 启动时是否漏了-p 3306:3306)。
更进一步,我们可以临时给 Nacos 容器安装mysql-client(仅用于验证,非生产):
docker exec -it nacos-standalone bash # 在容器内执行: apt-get update && apt-get install -y mysql-client mysql -h mysql -P 3306 -u root -p123456 nacos_config -e "SELECT COUNT(*) FROM config_info;" # 应返回类似:COUNT(*) # 0返回0说明连接成功且能查询表(此时表为空,正常)。这证明:从 Nacos 容器视角,mysql这个域名完全等价于 MySQL 容器的 IP,且 3306 端口开放、账号有效、数据库存在。
至此,整个“无需自定义网络”的闭环验证完成。你没有创建任何新网络,没有写一行 YAML,却实现了两个容器在默认bridge下的稳定互通。这种方案的优势在于:极简、可追溯、易调试、无抽象泄漏。当某天 Docker Desktop 升级导致docker-compose行为变化时,这套docker run链依然坚挺。
3. 深度拆解:Docker Desktop 默认 bridge 网络的 DNS 与路由真相
为什么--name mysql-nacos和-h mysql组合能让nacos-server容器里的ping mysql成功?这背后是 Docker Desktop 网络栈的一次精密协作。要真正理解“无需自定义网络”的可靠性,必须掀开它的三层盖子:DNS 解析层、IP 路由层、以及 Docker Desktop 虚拟机的网络桥接层。
3.1 DNS 层:容器名如何变成 IP 地址
当你执行docker run --name mysql-nacos -h mysql ...,Docker daemon(运行在 WSL2/Hyper-V 虚拟机中)会做三件事:
- 在虚拟机的
/etc/hosts文件中,为该容器添加一条记录:172.17.0.2 mysql mysql-nacos(IP 由docker0网桥动态分配); - 启动容器时,将虚拟机的 DNS 服务器地址(通常是
127.0.0.11,Docker 内置 DNS)写入容器的/etc/resolv.conf; - 当容器内发起 DNS 查询(如
ping mysql),请求被转发至127.0.0.11,该 DNS 服务实时查询内存中的容器注册表,返回mysql对应的 IP。
这个过程完全在虚拟机内部完成,不经过宿主机(Windows/macOS)的 DNS 解析器。这也是为什么你在 Windows 宿主机上ping mysql会失败——因为宿主机的 DNS 根本不知道mysql是什么。
你可以亲自验证这一点。先进入 MySQL 容器:
docker exec -it mysql-nacos bash然后查看其 DNS 配置:
cat /etc/resolv.conf # 输出应为: # nameserver 127.0.0.11 # options ndots:0再查看其 hosts 文件:
cat /etc/hosts # 输出应包含: # 127.0.0.1 localhost # ::1 localhost ip6-localhost ip6-loopback # fe00::0 ip6-localnet # ff00::0 ip6-mcastprefix # ff02::1 ip6-allnodes # ff02::2 ip6-allrouters # 172.17.0.2 mysql mysql-nacos # ← 这就是 Docker 自动添加的现在,对比 Nacos 容器的相同文件:
docker exec -it nacos-standalone bash -c "cat /etc/resolv.conf" # 同样是 nameserver 127.0.0.11 docker exec -it nacos-standalone bash -c "cat /etc/hosts | grep mysql" # 同样有 172.17.0.2 mysql mysql-nacos这意味着:两个容器共享同一套 DNS 服务和 hosts 映射规则。只要它们在同一个bridge网络(默认即如此),mysql这个名字在任何一个容器里解析,都会得到172.17.0.2。这就是“无需自定义网络”最底层的确定性来源——Docker daemon 的集中式服务发现,比任何外部 DNS 或自定义网络配置都更可靠。
3.2 路由层:数据包如何从 Nacos 到达 MySQL
DNS 解析出 IP 只是第一步。接下来,Nacos 容器发出的数据包(如 TCP SYN 到172.17.0.2:3306)如何到达 MySQL 容器?这依赖于 Linux 内核的iptables和bridge子系统。
在 Docker Desktop 的 WSL2 虚拟机中,执行ip addr show docker0会看到:
4: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0 valid_lft forever preferred_lft foreverdocker0是一个 Linux 网桥设备,所有默认bridge网络的容器,其虚拟以太网接口(vethxxx)都会被添加到这个网桥上。你可以用brctl show docker0查看连接的接口:
brctl show docker0 # 输出类似: # bridge name bridge id STP enabled interfaces # docker0 8000.0242a3b1c4d5 no veth123abc # veth456def其中veth123abc是 MySQL 容器的网络接口,veth456def是 Nacos 容器的接口。当 Nacos 容器发送数据包到172.17.0.2(MySQL 的 IP),Linux 内核根据路由表判断该 IP 属于docker0网段(172.17.0.0/16),于是将数据包交给docker0网桥。网桥根据 MAC 地址表,将数据包直接转发给veth123abc接口,最终送达 MySQL 容器的协议栈。
整个过程不经过 NAT,不经过宿主机防火墙,延迟极低。这也是为什么“无需自定义网络”方案性能更好——它省去了自定义网络可能引入的额外 iptables 规则和 DNAT/SNAT 转换。
3.3 Docker Desktop 虚拟机层:WSL2/Hyper-V 如何隔离又联通
最后,我们必须正视 Docker Desktop 的“虚拟机”本质。在 Windows 上,Docker Desktop 使用 WSL2(Windows Subsystem for Linux 2)作为后端;在 macOS 上,它使用 HyperKit(基于 Hypervisor.framework 的轻量级虚拟机)。无论哪种,都存在一个关键事实:这个虚拟机是一个独立的 Linux 系统,拥有自己的内核、网络栈、iptables 规则和 Docker daemon。
宿主机(Windows/macOS)和虚拟机之间,通过一个虚拟网络适配器互联。在 WSL2 中,这个适配器的 IP 通常是172.28.0.1(WSL2 发行版 IP)或192.168.49.1(Docker Desktop 专用);在 macOS 中,则是192.168.64.1。而docker0网桥的 IP172.17.0.1,则是虚拟机内部的地址,对外不可见。
这种架构带来两个直接影响:
- 优势:虚拟机内部的
bridge网络完全受控,不受宿主机网络策略干扰。你在公司内网、家庭 Wi-Fi、甚至热点环境下,docker0的行为都一致; - 劣势:宿主机无法直接
ping容器 IP(如172.17.0.2),因为该 IP 仅存在于虚拟机内网。你只能通过端口映射(-p 3306:3306)从宿主机访问容器服务。
这也解释了为什么“无需自定义网络”方案在 Docker Desktop 上特别稳健——它完全运行在虚拟机内部的可控环境中,不依赖宿主机的任何网络配置。而如果你创建自定义网络(如docker network create my-net),Docker 仍会在虚拟机内创建一个新的网桥(如br-xxxxx),其行为逻辑与docker0完全一致,只是多了一层管理开销。既然原生bridge已足够,何必画蛇添足?
我曾在某跨平台系统开发中,要求团队统一用docker run方式部署,禁用docker-compose。理由很实在:当一位 macOS 开发者写的docker-compose.yml里用了network_mode: "host",而另一位 Windows 开发者直接运行,就会因host模式在 Docker Desktop 上不支持而报错。而纯docker run命令,只要参数一致,在任何平台 Docker Desktop 上都能得到相同结果。这种确定性,是工程落地的生命线。
4. 生产就绪:从单机部署到高可用演进的平滑路径
你现在拥有了一个稳定、可验证、无需自定义网络的 Nacos + MySQL 单机环境。但这只是起点。真正的挑战在于:当业务增长,你需要将这套方案平滑升级为高可用集群,同时不破坏现有开发习惯和 CI/CD 流程。这里的关键不是推倒重来,而是设计一条“渐进式演进路径”。
4.1 第一阶段:单机增强——增加健康检查与优雅启停
当前方案中,MySQL 和 Nacos 都设置了--restart=always,这保证了容器意外退出后能自启。但还不够。我们需要让编排系统(如 Jenkins、GitLab CI)能感知服务是否真正就绪,而非仅仅容器进程存活。
为 MySQL 添加健康检查:
docker run -d \ --name mysql-nacos \ --health-cmd="mysqladmin ping -h 127.0.0.1 -u root -p123456" \ --health-interval=30s \ --health-timeout=10s \ --health-retries=3 \ --health-start-period=40s \ ... # 其他参数同前--health-cmd指定检测命令,--health-start-period=40s给 MySQL 充足的初始化时间(首次启动较慢)。这样,docker inspect mysql-nacos | grep Health就能看到实时健康状态。
为 Nacos 添加健康检查稍复杂,因其 HTTP 端点/nacos/v1/console/health在启动初期可能返回 404。稳妥做法是检测其日志中Nacos Server started successfully!字样:
docker run -d \ --name nacos-standalone \ --health-cmd="docker logs nacos-standalone 2>&1 | grep -q 'Nacos Server started successfully!'" \ --health-interval=20s \ --health-timeout=5s \ --health-retries=5 \ --health-start-period=90s \ ... # 其他参数同前注意:
--health-cmd中的docker logs命令,是在容器内部执行的,因此nacos-standalone是容器名,会被正确识别。
有了健康检查,你的 CI 脚本就可以这样写:
# 等待 MySQL 就绪 until [ "$(docker inspect -f '{{.State.Health.Status}}' mysql-nacos)" = "healthy" ]; do echo "Waiting for MySQL..." sleep 5 done # 等待 Nacos 就绪 until [ "$(docker inspect -f '{{.State.Health.Status}}' nacos-standalone)" = "healthy" ]; do echo "Waiting for Nacos..." sleep 5 done echo "All services ready!"这比简单的sleep 120更科学,也更符合云原生理念。
4.2 第二阶段:双节点 MySQL 主从——零代码改造
单点 MySQL 是最大风险。升级为主从,无需修改 Nacos 任何配置,只需调整 MySQL 启动方式。
思路:启动两个 MySQL 容器,一个主(master),一个从(slave),通过 binlog 同步。Nacos 仍连接主库(mysql-master),但所有写操作都在主库,读操作可分流到从库(需修改 Nacos 的 JDBC URL 为读写分离地址,此处暂不展开)。
主库启动命令(新增--server-id=1和--log-bin=mysql-bin):
docker run -d \ --name mysql-master \ -e MYSQL_ROOT_PASSWORD=123456 \ -e MYSQL_DATABASE=nacos_config \ -v $(pwd)/mysql-master-data:/var/lib/mysql \ -p 3306:3306 \ -h mysql-master \ --server-id=1 \ --log-bin=mysql-bin \ --binlog-format=ROW \ mysql:8.0.33从库启动命令(--server-id=2,并指定主库地址):
docker run -d \ --name mysql-slave \ -e MYSQL_ROOT_PASSWORD=123456 \ -v $(pwd)/mysql-slave-data:/var/lib/mysql \ -p 3307:3306 \ -h mysql-slave \ --server-id=2 \ mysql:8.0.33然后进入从库容器,执行 CHANGE MASTER TO 命令(需先在主库上创建复制用户):
# 在主库创建用户 docker exec mysql-master mysql -uroot -p123456 -e "CREATE USER 'repl'@'%' IDENTIFIED BY 'repl123'; GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%'; FLUSH PRIVILEGES;" # 获取主库 binlog 位置 docker exec mysql-master mysql -uroot -p123456 -e "SHOW MASTER STATUS\G" # 在从库执行(将 File 和 Position 替换为上一步输出) docker exec mysql-slave mysql -uroot -p123456 -e "CHANGE MASTER TO MASTER_HOST='mysql-master', MASTER_USER='repl', MASTER_PASSWORD='repl123', MASTER_LOG_FILE='mysql-bin.000001', MASTER_LOG_POS=156; START SLAVE;"验证同步:
docker exec mysql-slave mysql -uroot -p123456 -e "SHOW SLAVE STATUS\G" | grep -E "(Slave_IO_Running|Slave_SQL_Running)" # 应输出 Yes Yes此时,Nacos 仍连接mysql-master,完全无感。而当主库宕机,你只需将 Nacos 的MYSQL_SERVICE_HOST改为mysql-slave,并提升从库为新主(STOP SLAVE; RESET MASTER;),即可快速恢复。整个过程,Nacos 配置只改一个环境变量,这就是架构解耦的价值。
4.3 第三阶段:Nacos 集群——从 standalone 到 cluster 的无缝切换
当单机 Nacos 无法承受流量,你需要集群。好消息是:Nacos 集群模式与单机模式共享同一套数据库,且启动命令仅需修改MODE和增加节点列表。
首先,确保 MySQL 已准备好(主从或单点均可)。然后,启动三个 Nacos 容器,分别命名为nacos1、nacos2、nacos3,全部连接同一个 MySQL。
以nacos1为例(其他两个类似,仅NACOS_SERVER_IP和端口不同):
docker run -d \ --name nacos1 \ -e MODE=cluster \ -e NACOS_SERVER_IP=172.17.0.3 \ -e NACOS_SERVERS="172.17.0.3:8848 172.17.0.4:8848 172.17.0.5:8848" \ -e MYSQL_SERVICE_HOST=mysql-master \ -e MYSQL_SERVICE_PORT=3306 \ -e MYSQL_SERVICE_USER=root \ -e MYSQL_SERVICE_PASSWORD=123456 \ -e MYSQL_SERVICE_DB_NAME=nacos_config \ -v $(pwd)/nacos1-logs:/home/nacos/logs \ -p 8848:8848 \ -p 9848:9848 \ --restart=always \ nacos/nacos-server:2.3.2关键点:
MODE=cluster:启用集群模式;NACOS_SERVER_IP:显式指定本机 IP(172.17.0.3是nacos1在bridge网络中的 IP,可通过docker inspect nacos1 | grep IPAddress获取);NACOS_SERVERS:列出所有集群节点的 IP:Port,Nacos 会自动构建 Raft Group;- 所有节点共用同一 MySQL,因此配置中心、服务发现数据天然一致。
启动全部三个节点后,访问http://localhost:8848/nacos,在“集群管理”页面即可看到三个节点全部在线。此时,任意一个节点宕机,服务不中断,注册中心持续可用。
整个演进路径,从单机到集群,没有一次需要重建数据库,没有一次需要修改应用代码,没有一次需要学习新工具。你只是在原有docker run命令基础上,逐步叠加更健壮的参数。这种平滑性,正是“无需自定义网络”方案的深层优势——它不绑定任何特定编排范式,而是回归容器最本质的交互逻辑:IP、端口、环境变量、健康状态。
我在某图像处理 Demo 项目中,就采用此路径。第一周用单机 Nacos + MySQL 快速验证服务注册逻辑;第二周加入 MySQL 主从,保障数据安全;第三周上线 Nacos 集群,支撑压测流量。每次升级,