Spring Cloud Alibaba 云上实战(三):Docker Compose 一键编排 MySQL 8.4 + Redis 7 + Nacos 2.4.3(含 MySQL 持久化踩坑全记录)
系列第 3 篇。在 weblog-mw01(华为云 ECS,192.168.0.79)上落地课程第 1 周"基于 Docker Compose 一键编排部署各类核心中间件"和"集成 Nacos 配置中心":一套 compose 起 MySQL + Redis + Nacos,Nacos 数据持久化到 MySQL,并用 curl 完成"发布配置 → 读回配置"闭环验证。
一、为什么这三个放一台
- Nacos 的配置持久化依赖 MySQL(derby 内嵌库只适合开发试用,重启丢配置的历史教训太多),两者同机用 compose 内网互联,链路最短;
- Redis 与 MySQL 都是"数据面",CPU 消耗低、磁盘 IO 为主,8C16G 的机器带这三个实例绰绰有余;
- 生产上要做的只是把 mysql:8.4 换成主从/托管实例、Nacos 换 3 节点集群,编排思路完全一致。
二、compose 文件逐段精讲
name: weblog–mw
services:
mysql:
image: mysql:8.4
container_name: weblog–mysql
restart: unless–stopped
environment:
MYSQL_ROOT_PASSWORD: Root@2026
TZ: Asia/Shanghai
command: ––character–set–server=utf8mb4 ––collation–server=utf8mb4_unicode_ci
ports:
– "3306:3306"
volumes:
– mysql–data:/var/lib/mysql
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-uroot", "-pRoot@2026"]
interval: 10s
timeout: 5s
retries: 12
redis:
image: redis:7–alpine
container_name: weblog–redis
restart: unless–stopped
command: redis–server ––requirepass Weblog@2026 ––appendonly yes
ports:
– "6379:6379"
volumes:
– redis–data:/data
nacos:
image: nacos/nacos–server:v2.4.3
container_name: weblog–nacos
restart: unless–stopped
depends_on:
mysql:
condition: service_healthy # 关键:MySQL 健康后才起 Nacos
environment:
MODE: standalone
SPRING_DATASOURCE_PLATFORM: mysql
MYSQL_SERVICE_HOST: mysql # compose 服务名即 DNS
MYSQL_SERVICE_PORT: "3306"
MYSQL_SERVICE_USER: root
MYSQL_SERVICE_PASSWORD: Root@2026
MYSQL_SERVICE_DB_NAME: nacos_config
MYSQL_SERVICE_DB_PARAM: "characterEncoding=utf8&connectTimeout=5000&socketTimeout=5000&useSSL=false&allowPublicKeyRetrieval=true"
NACOS_AUTH_ENABLE: "false"
JVM_XMS: 512m
JVM_XMX: 512m
ports:
– "8848:8848" # HTTP 控制台/OpenAPI
– "9848:9848" # 2.x gRPC 通道(客户端必须能通!)
几个值得展开的设计点:
① depends_on: condition: service_healthy:Nacos 启动就要连 MySQL。如果只写 depends_on: mysql,只能保证"容器启动"不能保证"服务就绪"——MySQL 首次初始化要 20~30 秒,Nacos 抢跑必然连接失败。healthcheck + service_healthy 是 compose 编排有依赖服务时的标准答案。
② 8848 和 9848 必须一起暴露:Nacos 2.x 客户端用 gRPC 长连接(主端口+1000 = 9848)。只开 8848 的经典症状:控制台能访问,客户端注册/拉配置时超时报错。我们后面跨机联调前专门做了端口预检,9848 通了才敢起应用。
③ utf8mb4 要在 command 里显式声明:MySQL 8 默认 utf8mb4,但要保证 collation 一致(utf8mb4_unicode_ci),否则不同建表语句可能混出 0x255 排序规则的坑。
三、Nacos 建表:从镜像里"偷" SQL 的骚操作
Nacos 官方镜像不带自动建库,需要手动执行 mysql-schema.sql(12 张表:config_info、users、roles…)。但去 GitHub 下载 SQL 文件在国内服务器上大概率超时。其实 SQL 就在镜像里,docker create + docker cp 三步拿出来:
# 1. 创建一个"只创建不运行"的容器拿到文件系统
cid=$(docker create nacos/nacos-server:v2.4.3)
# 2. 把建表SQL拷出来
docker cp "$cid":/home/nacos/conf/mysql-schema.sql /tmp/mysql-schema.sql
# 3. 清理临时容器
docker rm "$cid"
# 建库 + 灌 schema
docker exec -i weblog-mysql mysql -uroot -pRoot@2026 <<'SQL'
CREATE DATABASE IF NOT EXISTS nacos_config DEFAULT CHARACTER SET utf8mb4;
CREATE DATABASE IF NOT EXISTS weblog DEFAULT CHARACTER SET utf8mb4;
SQL
docker exec -i weblog-mysql mysql -uroot -pRoot@2026 nacos_config < /tmp/mysql-schema.sql
实测结果:
-rw-r–r– 1 root root 11042 Sep 11 2024 /tmp/mysql-schema.sql # 11KB,12张表
nacos tables: 13 # show tables 输出13行(12表+表头)
这个技巧对所有"镜像里有初始化资源但官方文档让你去网上下"的中间件都适用(XXL-JOB 的 tables_xxl_job.sql、Skywalking 的 OAP 初始化脚本同理)。
四、踩坑实录:Nacos 连不上 MySQL 8.4(重启循环)
Nacos 起来后一直 Restarting (1),看日志:
Caused by: com.mysql.cj.exceptions.UnableToConnectException:
Public Key Retrieval is not allowed
at …CachingSha2PasswordPlugin.nextAuthenticationStep(…)
根因:MySQL 8.x 默认认证插件是 caching_sha2_password,首连时客户端需要向服务端取 RSA 公钥,而 JDBC 默认禁止公钥检索(防中间人)。Nacos 的 JDBC URL 由 MYSQL_SERVICE_DB_PARAM 环境变量拼出来,默认参数里没有 allowPublicKeyRetrieval。
修复:compose 里给 Nacos 加一行:
MYSQL_SERVICE_DB_PARAM: "characterEncoding=utf8&connectTimeout=5000&socketTimeout=5000&useSSL=false&allowPublicKeyRetrieval=true"
docker compose up -d nacos 重建后:
nacos console http: 200
— nacos readiness: OK
同一个坑还出现在:任何 Spring Boot 应用连 MySQL 8、Kafka Connect 的 JDBC Source、Canal……只要看到 Public Key Retrieval is not allowed,闭眼加 allowPublicKeyRetrieval=true&useSSL=false。
五、验证闭环:发布配置 → 落库 → 读回
Nacos 就绪后,不用开控制台,直接用 OpenAPI 完成配置闭环:
# 发布 weblog-demo.yaml 到 DEFAULT_GROUP
curl -s -X POST 'http://localhost:8848/nacos/v1/cs/configs' \\
–data-urlencode 'dataId=weblog-demo.yaml' \\
–data-urlencode 'group=DEFAULT_GROUP' \\
–data-urlencode 'content=weblog:
welcome: "hello-from-nacos-config-center"
env: huawei-cloud-demo'
# → true
# 读回
curl -s 'http://localhost:8848/nacos/v1/cs/configs?dataId=weblog-demo.yaml&group=DEFAULT_GROUP'
# weblog:
# welcome: "hello-from-nacos-config-center"
# env: huawei-cloud-demo
一个细节:发布后立刻 GET 偶尔返回 config data not exist——Nacos 写内存和异步落库之间有毫秒级窗口,去 MySQL 里查 config_info 表确认行已存在、稍后重试 GET 即可读到。这个"读己之写"的小延迟在生产排障时容易造成误判,值得记住。
再看 MySQL 侧的持久化证据:
— DB config_info rows: weblog-demo.yaml / DEFAULT_GROUP / tenant ''
配置真的落在 nacos_config.config_info 表里,容器重建也不丢。
六、最终状态与验收清单
NAME IMAGE STATUS PORTS
weblog-mysql mysql:8.4 Up 3 minutes (healthy) 0.0.0.0:3306->3306/tcp
weblog-nacos nacos/nacos-server:v2.4.3 Up 10 seconds 0.0.0.0:8848->8848/tcp, 0.0.0.0:9848->9848/tcp
weblog-redis redis:7-alpine Up 3 minutes 0.0.0.0:6379->6379/tcp
| MySQL 健康 + utf8mb4 + 业务库 weblog | ✅ |
| Redis 密码模式 + AOF + PING → PONG | ✅ |
| Nacos readiness OK + 配置发布/读回 | ✅ |
| Nacos 配置持久化到 config_info 表 | ✅ |
| 业务表 t_visit_log 初始化 | ✅ |
七、避坑总结
写在最后
持久层与配置中心就位。下一篇在 weblog-mw02 上编排 Kafka 3.9 KRaft(脱离 ZooKeeper)+ Elasticsearch 8.15,包括 KRaft 的 CLUSTER_ID 生成、advertised.listeners 的容器网络陷阱、ES 的 vm.max_map_count 内核参数,以及中文检索验证。
系列导航:
- ✅ 一:4台华为云ECS从规划到初始化
- ✅ 二:Docker 安装配置与镜像加速避坑
- ✅ 三:Docker Compose 一键编排 MySQL + Redis + Nacos(本篇)
- ⏭ 四:Kafka KRaft + Elasticsearch 容器化部署
- ✅ 五:JDK17 + Gradle8 标准化构建环境与多模块工程
- ⏭ 六:一个 Spring Boot 微服务的跨机全链路联调
网硕互联帮助中心





评论前必须登录!
注册