微服务商城实战¶
单体应用出错,看一个日志文件就够;微服务出错,你面对的是注册中心、配置中心、消息队列、缓存、搜索、对象存储和一条跨十个服务的调用链。本章按依赖顺序把这些组件装起来,再用 SkyWalking 把一次请求还原出来。
你将学到¶
- mall 商城的组件拓扑与启动依赖,为什么顺序不能乱
- Nacos 集群 + MySQL 主从的部署方式与注册/配置地址
- Redis、RabbitMQ、MongoDB、MinIO、ElasticStack 的部署与健康检查
- 用 Cilium Ingress 与 MetalLB 暴露商家端
为什么需要它¶
这套案例的价值不在「装八个中间件」,而在于让你体会依赖顺序和跨命名空间寻址。mall 的每个服务启动时都要连 Nacos 拿配置、注册自己,再连 MySQL/Redis/Mongo/ES/MinIO 干活。任何一个地址写错,表现都是 CrashLoopBackOff 或启动后 500,日志里往往只有一句 Connection refused。
| 组件 | 命名空间 | 工作负载 | 端口 | 存储 |
|---|---|---|---|---|
| MySQL + Nacos | nacos |
StatefulSet ×2 与 ×3 | 3306 / 8848 | 10Gi/副本 |
| Elasticsearch + Kibana | elastic |
StatefulSet ×3 / Deployment | 9200 / 5601 | 10Gi/副本 |
| Redis + Sentinel | redis |
StatefulSet ×3 | 6379 / 5000 | 10Gi/副本 |
| RabbitMQ | rabbit |
StatefulSet ×3 | 5672 / 15672 | emptyDir |
| MongoDB / MinIO | mongo / minio |
StatefulSet ×3 / ×4 | 27017 / 9000 | 10Gi/副本 |
| SkyWalking | tracing |
Deployment | 11800 / 12800 / 8080 | 无(存 ES) |
| mall 应用 | mall |
Deployment ×7 | 8201 等 | 无 |
flowchart LR
U[商家端浏览器] --> G[mall-gateway]
G --> B[mall-auth portal admin search]
B --> N[Nacos]
B --> M[(MySQL)]
B --> R[(Redis)]
B --> Q[RabbitMQ]
B --> E[(Elasticsearch)]
B --> O[(MinIO)]
B -.agent.-> OAP[SkyWalking OAP]
OAP --> E
图:请求从网关进入业务服务,横切依赖是 Nacos、MySQL、Redis、MQ、ES、MinIO,链路数据汇入 OAP。
核心概念¶
依赖关系决定部署顺序¶
目录编号就是顺序:00-Prometheus → 01-Nacos → 02-ElasticStack → 03-Redis → 04-RabbitMQ → 05-MongoDB → 06-MinIO → 07-Skywalking,最后才是 mall-and-skywalking。两条硬依赖必须记住:
- Nacos 依赖 MySQL。配置与注册信息落在
nacosdb,MySQL 没起来 Nacos 会一直重连。仓库把 MySQL 做成主从:mysql-0写、mysql-read读,Nacos 连mysql-0.mysql。 - SkyWalking OAP 依赖 Elasticsearch。
SW_STORAGE=elasticsearch、SW_STORAGE_ES_CLUSTER_NODES=elasticsearch.elastic.svc:9200,ES 未就绪时 OAP 的 readiness 一直失败。
集群外的四项能力¶
清单假定集群已具备 Cilium(启用 Cilium Ingress)、MetalLB 与 OpenEBS 的 openebs-hostpath,可选 nfs-csi 和 Metrics Server。缺 Cilium 则 ingressClassName: cilium 不生效、域名 404;缺 MetalLB 则 LoadBalancer Service 永远 <pending>;缺 OpenEBS 则 PVC Pending、Pod 卡在 ContainerCreating;缺 Metrics Server 则 kubectl top 与 HPA 都不可用。
地址与 Ingress 的两个坑¶
跨命名空间访问有两种写法,仓库里都出现过:nacos.nacos.svc:8848(省略 cluster.local,合法)和 mysql-0.mysql(只在同命名空间成立,跨命名空间要写全 mysql-0.mysql.nacos.svc.cluster.local)。
同一个案例里混用了两套 Ingress
01-Nacos/06-nacos-ingress.yaml 同时写了 Cilium 注解和 ingressClassName: nginx;06-MinIO/04-ingress-minio.yaml 用 cilium;07-Skywalking 又回到 nginx。部署前用 kubectl get ingressclass 核对,把注解和 class 统一,否则会出现「Ingress 创建成功但不通」。
SkyWalking Agent 怎么进去¶
每个 Java 服务都用同一个套路:initContainer(apache/skywalking-java-agent:9.0.0-java8)把 /skywalking/agent 拷到 emptyDir;主容器挂载到 /skywalking;JAVA_TOOL_OPTIONS 加 -javaagent,SW_AGENT_COLLECTOR_BACKEND_SERVICES 指向 skywalking-oap.tracing.svc:11800。镜像不用改造,Agent 版本由 initContainer 控制。
资源规划与观测串联¶
资源上先看 requests:Nacos 每副本 2Gi 内存、ES 每副本 1Gi heap、MinIO 四副本各 10Gi 卷,再加 Redis 与 Mongo,完整环境建议 3 台 4C8G 起步,否则 Pod 会大面积 Pending。
观测上,00-Prometheus 靠 prometheus.io/scrape 注解抓 Nacos actuator、redis-exporter(9121)、RabbitMQ(15692)、MongoDB(9216)、ES(9114) 与 MinIO;SkyWalking 负责 trace,Grafana 用 763、10991 等面板。指标看趋势、trace 看单次请求。
动手实验¶
实验:按顺序部署基础服务,再让 mall 跑起来
目标:每个服务都有可用的 Endpoint,SkyWalking 能看到调用链,商家端能通过 Ingress 打开。
步骤 1 · 前置检查
至少要看到 cilium 或 nginx 之一、openebs-hostpath,以及 MetalLB 的 controller/speaker Running。
步骤 2 · 部署 Nacos 与 MySQL
kubectl create namespace nacos
kubectl apply -f infra-services-with-prometheus/01-Nacos/01-secrets-mysql.yaml \
-f infra-services-with-prometheus/01-Nacos/02-mysql-persistent.yaml -n nacos
kubectl get pods -n nacos -w
MySQL 主从就绪后创建 Nacos 专用账号(Secret 中密码为 magedu.com),再部署 Nacos 三副本:
kubectl exec -n nacos mysql-0 -- mysql -uroot -e \
"GRANT ALL ON nacosdb.* TO 'nacos'@'%' IDENTIFIED BY 'magedu.com'; FLUSH PRIVILEGES;"
kubectl apply -f infra-services-with-prometheus/01-Nacos/03-nacos-cfg.yaml \
-f infra-services-with-prometheus/01-Nacos/04-nacos-persistent.yaml \
-f infra-services-with-prometheus/01-Nacos/05-nacos-service.yaml -n nacos
kubectl get endpoints nacos -n nacos
三个地址说明 3 副本都通过了 readiness。若只有一两个,先看 kubectl logs nacos-1 -n nacos 里的数据库连接错误。
步骤 3 · 部署 ElasticStack
kubectl create namespace elastic
kubectl apply -f infra-services-with-prometheus/02-ElasticStack/01-elasticsearch-cluster-persistent.yaml -n elastic
kubectl rollout status statefulset/es-cluster -n elastic --timeout=600s
kubectl apply -f infra-services-with-prometheus/02-ElasticStack/02-fluentbit.yaml \
-f infra-services-with-prometheus/02-ElasticStack/03-kibana.yaml -n elastic
ES 的 initContainer 会 chown 数据目录并改 vm.max_map_count,需要 privileged;PodSecurity 为 restricted 的集群要先改节点级 sysctl。
步骤 4 · 部署 Redis 与 RabbitMQ
kubectl create namespace redis
kubectl apply -f infra-services-with-prometheus/03-Redis/ -n redis
kubectl get endpoints redis -n redis
Redis 的 master 是 redis-0.redis.redis.svc。接着部署 RabbitMQ,管理台默认 admin/magedu.com:
kubectl create namespace rabbit
kubectl apply -f infra-services-with-prometheus/04-RabbitMQ/ -n rabbit
kubectl get pods -n rabbit
mall 需要独立账号与 vhost:
kubectl exec -n rabbit rabbitmq-0 -- rabbitmqctl add_user malladmin magedu.com
kubectl exec -n rabbit rabbitmq-0 -- rabbitmqctl add_vhost /mall
kubectl exec -n rabbit rabbitmq-0 -- rabbitmqctl set_permissions -p /mall malladmin ".*" ".*" ".*"
步骤 5 · 部署 MongoDB 与 MinIO
kubectl create namespace mongo && kubectl apply -f infra-services-with-prometheus/05-MongoDB/ -n mongo
kubectl exec -n mongo mongodb-0 -- mongo --quiet --eval 'rs.status().ok'
返回 1 表示副本集已选主。再部署 MinIO:4 副本、纠删码模式,必须四个都就绪才能提供读写:
kubectl create namespace minio && kubectl apply -f infra-services-with-prometheus/06-MinIO/ -n minio
kubectl get pods -n minio
步骤 6 · 部署 SkyWalking
kubectl create namespace tracing
kubectl apply -f infra-services-with-prometheus/07-Skywalking/ -n tracing
kubectl get endpoints skywalking-oap skywalking-ui -n tracing
步骤 7 · 部署 mall 应用
kubectl create namespace mall
kubectl apply -f mall-and-skywalking/ -n mall
kubectl get pods -n mall
七个 Deployment 都应 1/1 Running。若某个服务反复重启,先看 spring.cloud.nacos.config.server-addr:示例写的是 nacos.nacos.svc:8848,只有 Nacos 在 nacos 命名空间时才成立。
这批清单的 Ingress 写的是 ingressClassName: cilium,而本环境只有 nginx。用一份补丁文件批量改:
kubectl get ingress -n mall -o name | xargs -I{} kubectl patch {} -n mall --patch-file ingress-class-patch.yaml
步骤 8 · 用 MetalLB + Cilium Ingress 暴露商家端
Service 的 EXTERNAL-IP 为 <none> 不影响访问:Cilium 会用自管的 LB IP 做入口,把域名解析过去即可。
步骤 9 · 在 SkyWalking UI 里看链路
访问 http://skywalking.magedu.com,服务列表里应出现 mall-gateway、mall-auth。点一次商家端登录再看拓扑与 Trace;没数据先查 OAP Endpoint、SW_AGENT_COLLECTOR_BACKEND_SERVICES 和 ES 里的 sw_* 索引。
验证清单¶
-
kubectl get endpoints -n nacos nacos有三个地址 -
kubectl get endpoints redis -n redis三个地址,redis-0为 master -
kubectl get pods -n mall全部1/1 Running且无重启 -
curl -I http://mall-admin-web.magedu.com返回 200
常见问题与排错¶
| 现象 | 可能原因 | 处理方式 |
|---|---|---|
Nacos CrashLoopBackOff |
MySQL 未就绪;nacosdb 或账号未创建 |
先建库建用户,再看日志里的 JDBC 报错 |
| Nacos 只有 1 个副本就绪 | peer-finder 初始化失败;PVC 不足 | 看 kubectl logs nacos-1 -n nacos;确认 SC 可动态置备 |
| SkyWalking 无数据 | Agent 未注入;OAP 地址错;ES 磁盘满 | 查启动日志里的 SkyWalking agent started |
| OAP readiness 一直失败 | Elasticsearch 未就绪或索引创建失败 | 先 curl es-cluster-0.elasticsearch.elastic.svc:9200 |
旧 API 检查
本目录的 apiVersion 基本都能在 v1.31 直接用:StatefulSet apps/v1、Ingress networking.k8s.io/v1、RBAC rbac.authorization.k8s.io/v1。若你从旧教程抄到 extensions/v1beta1 的 Ingress 或 apps/v1beta1 的 StatefulSet,API Server 会直接拒绝;batch/v1beta1 的 CronJob 也已移除,应改为 batch/v1。
进阶挑战¶
- 给 Nacos 加 Prometheus 抓取(
/nacos/actuator/prometheus),在 Grafana 做一个「注册实例数」面板。 - 把 mall-gateway 扩到 3 副本,观察 SkyWalking 拓扑里同一服务的多实例是否被正确聚合。
小结¶
- 顺序不是形式:MySQL 先于 Nacos,ES 先于 OAP,基础服务先于 mall。
- SkyWalking 的接入点是 initContainer +
-javaagent,链路能否出现取决于 OAP、Agent 地址与 ES 三者。