灵雀云 Alauda 容器云平台 · 售前演示用 Service Mesh 微服务 Demo。项目基于 Spring Boot 构建,使用 Kubernetes Service 作为稳定服务入口,由平台 Service Mesh 数据面透明接管服务间流量,直观展示 App + Sidecar 部署模型、服务调用拓扑、实际命中的版本与 Pod、业务数据和可选中间件状态。
OpenJDK 版本:eclipse-temurin 21.0.11_10
Spring Boot 版本:3.2.5
容器编排:Kubernetes
微服务治理:Service Mesh
| 技术 | 角色 |
|---|---|
| OpenJDK 21 | Java 运行时 |
| Spring Boot 3.2 | 应用框架 |
| Kubernetes Service | 服务发现与稳定访问入口 |
| Service Mesh Sidecar | 服务间流量透明代理 |
| Spring Boot Actuator | 提供 Kubernetes 健康探针端点 |
| Redis(可选) | Consumer 聚合结果缓存 |
| MySQL 8(可选) | Provider 业务数据持久化 |
| Kafka(可选) | Consumer 异步访问事件上报 |
| Thymeleaf | Consumer Dashboard 页面 |
浏览器
│ HTTP
▼
Consumer Pod
┌──────────────────────────────┐
│ Consumer App :8080 │ Sidecar │
└────────────────────┬─────────┘
│ Service Mesh 数据面流量
┌──────────┴──────────┐
▼ ▼
provider-a Service provider-b Service
:8081 :8082
│ │
▼ ▼
Provider A Pod Provider B Pod
┌────────────────────┐ ┌────────────────────┐
│ Sidecar │ 商品服务 │ │ Sidecar │ 库存服务 │
└────────────────────┘ └────────────────────┘
│ │
MySQL(可选) MySQL(可选)
Consumer ── Redis(可选缓存)
Consumer ── Kafka(可选事件上报)
应用本身不集成注册中心、客户端负载均衡、熔断框架或特定 Service Mesh SDK:
- Consumer 只调用
provider-a和provider-bKubernetes Service; - Sidecar Proxy 透明接管服务之间的入站和出站流量;
- 灰度路由、超时、重试、熔断、故障注入、mTLS 和访问控制由平台 Service Mesh 配置;
- 应用负责业务逻辑、明确的调用超时、错误展示、健康状态端点和中间件降级;
- 应用不访问 Kubernetes API,不需要额外 ServiceAccount 或 RBAC。
| 服务 | 端口 | 说明 |
|---|---|---|
consumer |
8080 | 对外入口、Dashboard、Provider 聚合调用、Redis 缓存和 Kafka 事件上报 |
provider-a |
8081 | 商品服务,提供商品目录、价格和版本/Pod 元数据 |
provider-b |
8082 | 库存服务,提供库存汇总、库存明细和版本/Pod 元数据 |
| 路径 | 说明 |
|---|---|
GET / |
渲染 Service Mesh Dashboard |
GET /api/overview |
返回 Consumer、Provider、业务数据、中间件和采样实例总览 |
GET /api/calls/provider-a |
绕过 Redis,真实调用一次商品服务 |
GET /api/calls/provider-b |
绕过 Redis,真实调用一次库存服务 |
| 路径 | 说明 |
|---|---|
GET /info |
返回服务版本、Pod、IP、节点和请求追踪信息 |
GET /api/products |
返回商品目录和数据源状态 |
GET /data |
兼容聚合接口 |
| 路径 | 说明 |
|---|---|
GET /info |
返回服务版本、Pod、IP、节点和请求追踪信息 |
GET /api/inventories |
返回库存汇总、库存明细和数据源状态 |
GET /data |
兼容聚合接口 |
页面使用原生 HTML、CSS 和 JavaScript,不依赖外部 CDN,适合私有云和离线环境演示。
- Service Mesh 架构拓扑:展示 Browser、Consumer Pod、Provider Service、Provider Pod 和 App + Sidecar 数据路径;
- Service 与采样实例:按 Service 展示 Consumer 当前入口,以及最近真实调用命中的 Provider 版本、Pod 和 IP;
- 集群概览 KPI:服务总数、采样实例、调用正常和调用异常;
- 技术栈卡片:展示 Java、Spring Boot、Service Mesh、Sidecar Proxy、Service DNS 和 Kubernetes;
- 动态中间件卡片:启用 Redis、MySQL 或 Kafka 后自动展示对应技术卡片;
- 服务详情卡片:展示 Consumer、商品服务和库存服务的状态、实例信息与业务数据;
- 版本与 Pod 可视化:每次请求展示实际命中的服务版本、Pod、IP 和调用耗时;
- 实时刷新:页面每 5 秒调用一次
/api/overview,持续产生真实的服务间访问流量; - 局部降级:单个 Provider 调用失败时,页面仍可展示其他服务和明确的 DOWN 状态。
Consumer 通过对 Provider Service 并发探测多次(默认 8 次)并按 Pod 去重,主动聚合出当前命中的实例列表,无需调用 Kubernetes API 或额外 RBAC 权限。探测依靠 Service 的负载均衡把请求分发到不同 Pod;为避免 HTTP keep-alive 连接复用导致多次请求黏在同一后端,探测请求显式设置
Connection: close,使每次请求都经负载均衡重新选路。受探测次数和负载均衡策略影响,展示的实例数接近但不保证等于集群内的全量 Pod 数;持续访问可进一步收敛。
三个服务是相互独立的 Maven 工程,不提供根级聚合 POM。每个服务拥有自己的 pom.xml、Maven Wrapper、源码、测试、Dockerfile 和制品目录。
平台流水线采用分阶段构建:
Git 源码
│
▼
Maven 构建节点
├─ 使用 Nexus Maven 仓库下载依赖
├─ 分别编译和测试三个服务
└─ 生成 target/*.jar
│
│ Workspace / PVC / Jenkins Workspace
▼
镜像构建节点
├─ 不执行 Maven
├─ 不下载 Maven 依赖
├─ Dockerfile COPY target/*.jar
└─ 构建并推送容器镜像
Dockerfile 约定的制品名称:
consumer/target/consumer-1.0.jar
providera/target/provider-a-1.0.jar
providerb/target/provider-b-1.0.jar
本地源码验证:
cd consumer
./mvnw clean verify
cd ../providera
./mvnw clean verify
cd ../providerb
./mvnw clean verify三个 Dockerfile 使用统一基础镜像:
eclipse-temurin:21.0.11_10-jdk-alpine-3.23
流水线准备好 target 制品后,各服务独立构建镜像:
docker build -t service-mesh-demo/consumer:1.0 consumer
docker build -t service-mesh-demo/provider-a:1.0 providera
docker build -t service-mesh-demo/provider-b:1.0 providerbDockerfile 只负责运行时镜像封装,不执行 Maven 构建。
镜像已推送至 Docker Hub,无需本地构建即可直接拉取使用(tag servicemesh-1.0.0):
docker pull kevinlee822/consumer:servicemesh-1.0.0
docker pull kevinlee822/providera:servicemesh-1.0.0
docker pull kevinlee822/providerb:servicemesh-1.0.0| 服务 | 镜像地址 |
|---|---|
consumer |
kevinlee822/consumer:servicemesh-1.0.0 |
provider-a |
kevinlee822/providera:servicemesh-1.0.0 |
provider-b |
kevinlee822/providerb:servicemesh-1.0.0 |
注:Provider 镜像名与 Maven 模块名一致(
providera/providerb,无连字符)。拉取后若需用本地构建时的名称,可用docker tag重命名。
Redis、Kafka 和 MySQL 默认全部关闭。没有任何外部中间件时,三个服务仍可正常启动:
- Consumer 实时调用两个 Provider;
- Provider A 使用内存商品数据;
- Provider B 使用内存库存数据;
- Dashboard 完整展示拓扑、服务状态和业务数据。
本地启动:
java -jar providera/target/provider-a-1.0.jar
java -jar providerb/target/provider-b-1.0.jar
PROVIDER_A_BASE_URL=http://localhost:8081 \
PROVIDER_B_BASE_URL=http://localhost:8082 \
java -jar consumer/target/consumer-1.0.jar访问:
http://localhost:8080
| 环境变量 | 默认值 | 说明 |
|---|---|---|
PROVIDER_A_BASE_URL |
http://provider-a:8081 |
商品服务 Kubernetes Service 地址 |
PROVIDER_B_BASE_URL |
http://provider-b:8082 |
库存服务 Kubernetes Service 地址 |
HTTP_CONNECT_TIMEOUT |
2s |
HTTP 连接超时 |
HTTP_READ_TIMEOUT |
5s |
HTTP 读取超时 |
PROVIDER_PROBE_COUNT |
8 |
发现多实例时对 Provider Service 的并发探测次数,依靠负载均衡分发到不同 Pod 后按 Pod 名去重聚合 |
Consumer 不执行自动重试,便于平台 Service Mesh 治理策略的效果被准确观察。为发现 Provider 的多个 Pod 实例,Consumer 在 /api/overview 时会并发探测 Provider Service 多次(次数由 PROVIDER_PROBE_COUNT 控制),探测请求禁用 keep-alive 并按 Pod 名去重,整个过程不调用 Kubernetes API、无需额外 RBAC。
| 环境变量 | 默认值 | 说明 |
|---|---|---|
ENABLE_REDIS |
false |
是否启用 Redis |
REDIS_MODE |
空 | 空=单机,或 sentinel、cluster |
REDIS_HOST |
localhost |
单机地址 |
REDIS_PORT |
6379 |
单机端口 |
REDIS_PASSWORD |
空 | Redis 密码 |
REDIS_DATABASE |
0 |
Redis 数据库编号 |
REDIS_CACHE_KEY |
service-mesh-demo:overview |
聚合缓存键 |
REDIS_SENTINEL_MASTER |
mymaster |
Sentinel Master 名称 |
REDIS_SENTINEL_NODES |
空 | Sentinel 节点,逗号分隔 |
REDIS_CLUSTER_NODES |
空 | Cluster 节点,逗号分隔 |
Redis 读取、写入或反序列化失败时,Consumer 自动回退到实时 Provider 调用。缓存有效期为 10 秒。/api/calls/{service} 始终绕过缓存。
| 环境变量 | 默认值 | 说明 |
|---|---|---|
ENABLE_KAFKA |
false |
是否启用 Kafka |
KAFKA_SERVER |
localhost:9092 |
Broker 地址 |
KAFKA_TOPIC |
consumer-access-event |
事件 Topic |
Kafka 事件异步发送,发送失败不会影响主 HTTP 调用。
| 环境变量 | 默认值 | 说明 |
|---|---|---|
APP_VERSION |
v1 |
服务版本,用于灰度和流量路由展示 |
APP_DISPLAY_NAME |
商品服务/库存服务 | 页面显示名称 |
APP_THEME_COLOR |
服务默认色 | 星级和版本视觉标识 |
STAR_COUNT |
5 |
星级数量 |
POD_NAME |
local |
Pod 名称,可由 Downward API 注入 |
POD_NAMESPACE |
local |
Pod 命名空间 |
POD_IP |
自动获取 | Pod IP |
NODE_NAME |
local |
Kubernetes 节点名称 |
同一个 Provider 镜像可以通过不同的 APP_VERSION 和 APP_THEME_COLOR 部署为 v1、v2 等多个版本。
| 环境变量 | 默认值 | 说明 |
|---|---|---|
ENABLE_MYSQL |
false |
是否启用 MySQL |
MYSQL_HOST |
localhost |
MySQL 地址 |
MYSQL_PORT |
3306 |
MySQL 端口 |
MYSQL_DATABASE |
provider_a_db / provider_b_db |
Provider 独立数据库 |
MYSQL_USERNAME |
root |
MySQL 用户名 |
MYSQL_PASSWORD |
空 | MySQL 密码 |
数据库需要预先创建。Provider 启动时会幂等创建业务表和演示数据。数据库连接、初始化或查询失败时,服务继续运行并自动回退到内存数据。
Provider 响应中的关键字段:
{
"dataSource": "memory",
"mysql": {
"configured": false,
"available": false,
"lastError": ""
}
}Spring Boot Actuator 只用于提供应用健康状态 HTTP 端点,探针的执行和故障处理由 Kubernetes 负责。
三个服务均提供:
| 路径 | 说明 |
|---|---|
/actuator/health |
应用综合健康状态 |
/actuator/health/liveness |
Liveness Probe 检查端点 |
/actuator/health/readiness |
Readiness Probe 检查端点 |
- Kubernetes Liveness Probe 定期访问 Liveness 端点;连续失败时可以重启容器;
- Kubernetes Readiness Probe 定期访问 Readiness 端点;失败时将 Pod 从 Service 的可用 Endpoint 中移除;
- Redis、Kafka 和 MySQL 均为可降级中间件,其不可用状态不会导致 Liveness 失败和无意义的容器重启;
- 应用支持优雅停机,默认关闭的中间件不影响应用启动和健康状态。
应用只读取 Spring Boot 配置和环境变量,不直接调用 Kubernetes API。部署时建议:
- 使用 ConfigMap 注入 Service 地址、功能开关和普通连接配置;
- 使用 Secret 注入 MySQL、Redis、Kafka 等敏感凭据;
- 使用 Downward API 注入 Pod 名称、命名空间、Pod IP 和节点名称;
- 为 Provider v1/v2 工作负载配置统一的
app标签和不同的version标签; - 由平台完成 Sidecar 注入和 Service Mesh 治理策略配置。
本仓库只提供应用源码和容器构建文件,不包含 Kubernetes、Istio 或平台专有 YAML。
增加 Provider 副本后访问 Dashboard。Consumer 会对 Provider Service 并发探测多次并按 Pod 去重,右侧“Service 与采样实例”区域会展示当前负载均衡实际命中的多个 Pod 实例及其版本、IP 和调用耗时;缩容后实例会随之减少。
使用同一 Provider 镜像部署 v1、v2,通过 APP_VERSION 和主题色区分版本。在平台设置流量权重后,Dashboard 可展示实际命中的版本分布。
在平台对 Provider 设置延迟或 HTTP 错误。Dashboard 会展示调用耗时、DOWN 状态和错误信息,另一个 Provider 仍可正常显示。
Consumer 只设置基础 HTTP 超时,不执行自动重试。平台策略生效后,可通过调用状态、耗时以及平台可观测页面验证治理结果。
在平台启用 mTLS 或服务访问控制。应用代码和镜像无需修改,由 Sidecar 数据面执行安全策略。
停止本地 Java 进程即可结束 Demo。本项目默认不创建数据库、Redis 或 Kafka 实例;启用外部中间件时,其数据清理由对应平台或中间件管理员处理。