【SkyWalking从入门到精通】第17篇:SkyWalking实战环境搭建:打造你的微服务沙场
上一篇【第16篇】SkyWalking UI使用手册:学会阅读指挥中心的作战地图
下一篇【第18篇】用SkyWalking观察微服务的各个维度:从宏观到微观的侦察术
前16篇我们学会了SkyWalking的所有理论——基因改造针、指挥中心、档案馆、作战地图。但理论再好,不上战场都是纸上谈兵。
今天我们要打造一个真实的微服务沙场——用Spring Cloud搭建5个微服务,配上SkyWalking的完整监控链路,让所有理论在实践中运转起来。
1. 实战集群架构设计
1.1 微服务架构
我们模拟一个电商系统,包含5个核心服务:
┌──────────────────────────────────────────────────────────────────┐
│ 实战环境 - 电商微服务架构 │
│ │
│ ┌─────── User ────────┐ │
│ │ user-gateway │ ← Spring Cloud Gateway (网关) │
│ │ 端口: 8080 │ │
│ └─────────────────────┘ │
│ │ │
│ │ 路由分发 │
│ ▼ │
│ ┌──── user-service ────┐ ← 用户服务 │
│ │ 端口: 8081 │ │
│ │ 功能: 注册/登录/查询 │ │
│ └──────────────────────┘ │
│ │ │
│ ├──→ ┌─── order-service ──┐ ← 订单服务 │
│ │ │ 端口: 8082 │ │
│ │ │ 功能: 下单/查询 │ │
│ │ └────────────────────┘ │
│ │ │ │
│ │ ├──→ ┌── payment-service ──┐ ← 支付服务 │
│ │ │ │ 端口: 8083 │ │
│ │ │ │ 功能: 支付/退款 │ │
│ │ │ └─────────────────────┘ │
│ │ │ │
│ │ └──→ ┌── inventory-service ──┐ ← 库存服务 │
│ │ │ 端口: 8084 │ │
│ │ │ 功能: 库存查询/扣减 │ │
│ │ └────────────────────────┘ │
│ │
│ ┌─── 基础设施 ────────────────────────────────────────┐ │
│ │ Nacos: 服务注册与发现 (8848) │ │
│ │ MySQL: 业务数据库 (3306) │ │
│ │ Redis: 缓存 (6379) │ │
│ │ RocketMQ: 消息队列 (9876) │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
│ ┌─── SkyWalking ──────────────────────────────────────┐ │
│ │ OAP Server: 数据分析 (11800/12800) │ │
│ │ ES: 数据存储 (9200) │ │
│ │ UI: 可视化 (8080-sw) │ │
│ └──────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────┘
1.2 调用链路设计
一个下单请求的典型链路:
用户下单请求的完整链路:
user-gateway (路由)
→ user-service (验证用户身份)
→ order-service (创建订单)
→ inventory-service (扣减库存)
→ payment-service (发起支付)
→ MySQL (写入支付记录)
→ RocketMQ (发送订单通知)
1.3 技术选型
| 组件 | 技术 | 版本 |
|---|---|---|
| 网关 | Spring Cloud Gateway | 3.1.x |
| 服务框架 | Spring Boot | 2.7.x |
| 注册中心 | Nacos | 2.2.x |
| 数据库 | MySQL | 8.0 |
| 缓存 | Redis | 7.x |
| 消息队列 | RocketMQ | 5.x |
| 监控 | SkyWalking | 9.3.0 |
| 存储 | Elasticsearch | 8.12 |
2. 各服务的Agent配置
2.1 服务名规划
服务名是Agent最重要的配置——它决定了应用在SkyWalking中的身份标识。规划原则:
┌──────────────────────────────────────────────────────────────────┐
│ 服务名规划原则 │
│ │
│ 1. 使用业务语义名,不使用技术名 │
│ 好的: user-service, order-center │
│ 差的: springboot-app1, svc-8082 │
│ │
│ 2. 同一服务的多个实例用相同名字 │
│ 实例1: user-service │
│ 实例2: user-service (相同名字,SkyWalking自动区分实例) │
│ │
│ 3. 不同层次用不同命名风格 │
│ 网关层: xxx-gateway │
│ 业务层: xxx-service │
│ 基础层: xxx-center │
│ │
│ 4. 避免特殊字符和空格 │
│ user-service ✓ │
│ User Service × │
│ user.service × │
└──────────────────────────────────────────────────────────────────┘
我们的服务名规划:
| 服务 | Agent服务名 | 端口 |
|---|---|---|
| user-gateway | ecommerce-gateway | 8080 |
| user-service | user-service | 8081 |
| order-service | order-service | 8082 |
| payment-service | payment-service | 8083 |
| inventory-service | inventory-service | 8084 |
2.2 各服务Agent配置
每个服务的Agent配置核心参数:
# ==================== user-gateway ====================
agent.service_name=ecommerce-gateway
collector.backend_service=skywalking-oap:11800
agent.sample_n_per_3_secs=-1
logging.level=WARN
# ==================== user-service ====================
agent.service_name=user-service
collector.backend_service=skywalking-oap:11800
agent.sample_n_per_3_secs=-1
logging.level=WARN
# ==================== order-service ====================
agent.service_name=order-service
collector.backend_service=skywalking-oap:11800
agent.sample_n_per_3_secs=-1
logging.level=WARN
# ==================== payment-service ====================
agent.service_name=payment-service
collector.backend_service=skywalking-oap:11800
agent.sample_n_per_3_secs=-1
logging.level=WARN
# ==================== inventory-service ====================
agent.service_name=inventory-service
collector.backend_service=skywalking-oap:11800
agent.sample_n_per_3_secs=-1
logging.level=WARN
2.3 网关服务的特殊处理
Spring Cloud Gateway是基于WebFlux的响应式框架,需要额外激活Gateway插件:
# 激活Gateway插件
mv optional-plugins/apm-spring-cloud-gateway-2.x-plugin.jar plugins/
# 同时需要激活WebFlux插件(如果Gateway使用WebFlux)
mv optional-plugins/apm-spring-webflux-5.x-plugin.jar plugins/
2.4 Agent配置的统一管理
在Docker Compose环境中,使用共享Agent卷 + 环境变量覆盖:
# docker-compose.yml - Agent配置
services:
user-service:
image: ecommerce/user-service:latest
environment:
- SW_AGENT_NAME=user-service
- SW_AGENT_COLLECTOR_BACKEND_SERVICES=skywalking-oap:11800
- SW_LOGGING_LEVEL=WARN
volumes:
- skywalking-agent:/skywalking-agent:ro
command: >
java -javaagent:/skywalking-agent/skywalking-agent.jar
-jar /app/user-service.jar
3. Kubernetes部署时Agent挂载方式
3.1 为什么K8s需要特殊处理
在Docker Compose中,我们可以直接把Agent目录挂载进去。但在K8s中,应用镜像通常不包含Agent——需要一种优雅的方式把Agent注入容器。
3.2 initContainer方式(推荐)
initContainer是K8s的标准机制——在主容器启动前,先运行一个初始化容器,把Agent文件复制到共享卷中:
┌──────────────────────────────────────────────────────────────────┐
│ K8s initContainer Agent挂载流程 │
│ │
│ Pod启动顺序: │
│ │
│ 1. initContainer运行 │
│ ┌───────────────────────────────────────────┐ │
│ │ skywalking-agent-init │ │
│ │ - 从Agent镜像复制文件到共享卷 │ │
│ │ - cp -r /skywalking-agent /agent-volume │ │
│ │ - 容器退出 │ │
│ └───────────────────────────────────────────┘ │
│ │ │
│ │ 文件已复制到共享卷 │
│ ▼ │
│ 2. 主容器运行 │
│ ┌───────────────────────────────────────────┐ │
│ │ user-service │ │
│ │ - 挂载共享卷到/skywalking-agent │ │
│ │ - -javaagent:/skywalking-agent/agent.jar │ │
│ │ - 应用启动 │ │
│ └───────────────────────────────────────────┘ │
│ │
│ 共享卷 (emptyDir): │
│ initContainer写入 → 主容器读取 → Agent文件在两个容器间共享 │
└──────────────────────────────────────────────────────────────────┘
3.3 完整K8s Deployment示例
# Kubernetes Deployment - user-service with SkyWalking Agent
apiVersion: apps/v1
kind: Deployment
metadata:
name: user-service
labels:
app: user-service
spec:
replicas: 2
selector:
matchLabels:
app: user-service
template:
metadata:
labels:
app: user-service
spec:
# initContainer: 复制Agent文件
initContainers:
- name: skywalking-agent-init
image: apache/skywalking-java-agent:9.3.0-jdk11
command: ["sh", "-c", "cp -r /skywalking-agent /agent"]
volumeMounts:
- name: agent-volume
mountPath: /agent
# 主容器: 运行应用
containers:
- name: user-service
image: ecommerce/user-service:latest
env:
- name: SW_AGENT_NAME
value: "user-service"
- name: SW_AGENT_COLLECTOR_BACKEND_SERVICES
value: "skywalking-oap:11800"
- name: SW_LOGGING_LEVEL
value: "WARN"
volumeMounts:
- name: agent-volume
mountPath: /skywalking-agent
command:
- java
- -javaagent:/skywalking-agent/skywalking-agent.jar
- -jar
- /app/user-service.jar
ports:
- containerPort: 8081
# 共享卷
volumes:
- name: agent-volume
emptyDir: {}
3.4 ConfigMap管理公共配置
# SkyWalking公共配置 ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
name: skywalking-agent-config
data:
SW_AGENT_COLLECTOR_BACKEND_SERVICES: "skywalking-oap:11800"
SW_LOGGING_LEVEL: "WARN"
SW_AGENT_SAMPLE_N_PER_3_SECS: "-1"
所有服务都可以引用这个ConfigMap:
# Deployment中引用ConfigMap
envFrom:
- configMapRef:
name: skywalking-agent-config
env:
- name: SW_AGENT_NAME
value: "user-service" # 每个服务单独设置
3.5 Sidecar方式(备选)
除了initContainer,还可以用Sidecar方式挂载Agent——一个Pod中运行两个容器:
# Sidecar方式(不推荐,资源浪费)
spec:
containers:
- name: user-service
image: ecommerce/user-service:latest
command: ["java", "-javaagent:/shared/skywalking-agent.jar", "-jar", "app.jar"]
volumeMounts:
- name: shared
mountPath: /shared
- name: skywalking-agent-sidecar
image: apache/skywalking-java-agent:9.3.0-jdk11
# Sidecar容器只提供Agent文件
volumeMounts:
- name: shared
mountPath: /shared
volumes:
- name: shared
emptyDir: {}
Sidecar方式的问题是——Sidecar容器会一直运行,浪费资源。initContainer方式只在启动时运行一次,更高效。
4. Docker Compose完整实战环境
4.1 完整docker-compose.yml
# docker-compose.yml - 完整实战环境
version: '3.8'
services:
# ==================== 基础设施 ====================
# Nacos注册中心
nacos:
image: nacos/nacos-server:v2.2.3
environment:
MODE: standalone
ports:
- "8848:8848"
# MySQL数据库
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: root123
MYSQL_DATABASE: ecommerce
ports:
- "3306:3306"
volumes:
- mysql-data:/var/lib/mysql
# Redis缓存
redis:
image: redis:7-alpine
ports:
- "6379:6379"
# Elasticsearch
elasticsearch:
image: elasticsearch:8.12.0
environment:
- discovery.type=single-node
- "ES_JAVA_OPTS=-Xms1g -Xmx1g"
- xpack.security.enabled=false
ports:
- "9200:9200"
volumes:
- es-data:/usr/share/elasticsearch/data
# ==================== SkyWalking ====================
# OAP Server
skywalking-oap:
image: apache/skywalking-oap-server:9.3.0
environment:
- SW_STORAGE=elasticsearch
- SW_CLUSTER_NODES=elasticsearch:9200
- SW_CORE_RECORD_DATA_TTL=3
- SW_CORE_OTHER_METRICS_DATA_TTL=7
depends_on:
- elasticsearch
ports:
- "11800:11800"
- "12800:12800"
# SkyWalking UI
skywalking-ui:
image: apache/skywalking-ui:9.3.0
environment:
- SW_OAP_ADDRESS=skywalking-oap:12800
depends_on:
- skywalking-oap
ports:
- "9090:8080"
# ==================== 业务服务 ====================
# 用户网关
user-gateway:
build:
context: ./user-gateway
dockerfile: Dockerfile
environment:
- SW_AGENT_NAME=ecommerce-gateway
- SW_AGENT_COLLECTOR_BACKEND_SERVICES=skywalking-oap:11800
- SW_LOGGING_LEVEL=WARN
- NACOS_ADDR=nacos:8848
depends_on:
- nacos
- skywalking-oap
ports:
- "8080:8080"
# 用户服务
user-service:
build:
context: ./user-service
dockerfile: Dockerfile
environment:
- SW_AGENT_NAME=user-service
- SW_AGENT_COLLECTOR_BACKEND_SERVICES=skywalking-oap:11800
- SW_LOGGING_LEVEL=WARN
- NACOS_ADDR=nacos:8848
- MYSQL_HOST=mysql
- REDIS_HOST=redis
depends_on:
- nacos
- mysql
- redis
- skywalking-oap
ports:
- "8081:8081"
# 订单服务
order-service:
build:
context: ./order-service
dockerfile: Dockerfile
environment:
- SW_AGENT_NAME=order-service
- SW_AGENT_COLLECTOR_BACKEND_SERVICES=skywalking-oap:11800
- SW_LOGGING_LEVEL=WARN
- NACOS_ADDR=nacos:8848
- MYSQL_HOST=mysql
depends_on:
- nacos
- mysql
- skywalking-oap
ports:
- "8082:8082"
# 支付服务
payment-service:
build:
context: ./payment-service
dockerfile: Dockerfile
environment:
- SW_AGENT_NAME=payment-service
- SW_AGENT_COLLECTOR_BACKEND_SERVICES=skywalking-oap:11800
- SW_LOGGING_LEVEL=WARN
- NACOS_ADDR=nacos:8848
- MYSQL_HOST=mysql
depends_on:
- nacos
- mysql
- skywalking-oap
ports:
- "8083:8083"
# 库存服务
inventory-service:
build:
context: ./inventory-service
dockerfile: Dockerfile
environment:
- SW_AGENT_NAME=inventory-service
- SW_AGENT_COLLECTOR_BACKEND_SERVICES=skywalking-oap:11800
- SW_LOGGING_LEVEL=WARN
- NACOS_ADDR=nacos:8848
- MYSQL_HOST=mysql
- REDIS_HOST=redis
depends_on:
- nacos
- mysql
- redis
- skywalking-oap
ports:
- "8084:8084"
volumes:
mysql-data:
es-data:
4.2 业务服务的Dockerfile模板
每个服务的Dockerfile需要包含Agent挂载:
# user-service/Dockerfile
FROM openjdk:11-jre-slim
# 复制应用jar包
COPY target/user-service.jar /app/user-service.jar
# 复制SkyWalking Agent
COPY skywalking-agent /skywalking-agent
# 激活Gateway插件(如果需要)
# RUN mv /skywalking-agent/optional-plugins/apm-xxx-plugin.jar /skywalking-agent/plugins/
ENTRYPOINT ["java", \
"-javaagent:/skywalking-agent/skywalking-agent.jar", \
"-jar", "/app/user-service.jar"]
5. 验证追踪数据正常上报
5.1 启动环境
# 启动所有服务
docker-compose up -d
# 查看服务状态
docker-compose ps
# 查看OAP日志
docker-compose logs skywalking-oap | tail -20
# 查看Agent日志
docker-compose logs user-service | grep "skywalking"
5.2 验证步骤
┌──────────────────────────────────────────────────────────────────┐
│ 追踪数据验证流程 │
│ │
│ 步骤一:验证OAP正常启动 │
│ └──→ curl http://localhost:12800/api/status │
│ └──→ 返回200表示OAP正常 │
│ │
│ 步骤二:验证UI可访问 │
│ └──→ 打开 http://localhost:9090 │
│ └──→ 能看到Dashboard表示UI正常 │
│ │
│ 步骤三:发送测试请求 │
│ └──→ curl http://localhost:8080/api/users/1 │
│ └──→ curl http://localhost:8080/api/orders/create │
│ └──→ 多发几个请求,确保有足够数据 │
│ │
│ 步骤四:查看UI中的拓扑图 │
│ └──→ 打开UI → General → Service │
│ └──→ 拓扑图应显示5个服务节点和它们的调用关系 │
│ │
│ 步骤五:查看Trace数据 │
│ └──→ 打开UI → Trace │
│ └──→ 应能看到刚才发送的请求的Trace │
│ └──→ Trace中应包含多个Span(网关→用户→订单→库存→支付) │
│ │
│ 步骤六:查看Agent日志 │
│ └──→ docker-compose logs user-service │
│ └──→ 日志中应包含TraceID信息 │
│ └──→ 格式: TID:xxx PROC:xxx │
└──────────────────────────────────────────────────────────────────┘
5.3 常见问题排查
| 问题 | 检查方法 | 常见原因 |
|---|---|---|
| UI看不到服务 | 检查OAP日志 | Agent没连上OAP(检查backend_service地址) |
| 拓扑图不显示链路 | 检查调用是否经过 | 服务之间没有互相调用 |
| Trace不完整 | 检查Agent插件 | 缺少必要的插件(如Gateway插件) |
| 数据延迟显示 | 检查OAP聚合周期 | 聚合周期是500ms,数据不会立即出现 |
| 只有部分Span | 检查采样率 | 采样率过低导致部分请求未被追踪 |
5.4 应用日志中的TraceID
如果Agent正常工作,应用日志中会自动输出TraceID:
# 查看user-service日志中的TraceID
docker-compose logs user-service | grep "TID"
# 日志格式示例:
# 2026-07-02 14:30:00 INFO [TID:a3b2c1d4e5] UserService.getUser - userId=123
# 2026-07-02 14:30:00 INFO [TID:a3b2c1d4e5] UserService.queryDB - SQL=SELECT...
在Spring Boot中,需要添加logback的TraceID输出格式:
<!-- logback-spring.xml -->
<configuration>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<!-- %tid输出TraceID -->
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%tid] %-5level %logger - %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="CONSOLE"/>
</root>
</configuration>
6. 小结
实战环境搭建是把理论变成实践的关键一步:
- 集群架构:5个微服务 + 基础设施 + SkyWalking全链路
- 服务名规划:业务语义命名,同服务多实例同名
- Agent配置:环境变量覆盖方式,统一管理
- K8s挂载:initContainer方式是标准做法,比Sidecar更高效
- Docker Compose:完整的本地实战环境
- 数据验证:OAP状态 → UI访问 → 发请求 → 看拓扑 → 看Trace → 看日志
下一篇文章,我们将用这个实战环境来观察微服务的各个维度——从告警出发,一步步定位问题。
上一篇【第16篇】SkyWalking UI使用手册:学会阅读指挥中心的作战地图
下一篇【第18篇】用SkyWalking观察微服务的各个维度:从宏观到微观的侦察术
更多推荐
所有评论(0)