Istio保姆级入门指南:像搭积木一样理解服务网格,每个组件掰开讲
前言:先别急着记命令,搞清楚这四个问题
很多人在学Istio时,会一头扎进配置YAML里,背VirtualService怎么写、DestinationRule怎么配。但学了半天,还是不清楚:
1
2
3
4
|
• 为什么我的Pod里多了一个叫 istio-proxy 的容器?
• Pilot和Sidecar之间到底怎么通信的?
• 我在K8s里配的Service好好的,为什么还要ServiceEntry?
• mTLS加密听起来很安全,但我怎么知道它真的在工作?
|
本文的思路是先理解本质,再动手操作。我们把Istio拆成5块积木,一块一块地讲,每一块都配上生活中的比喻,确保你学完能用自己的话解释给别人听。
积木一:服务网格是什么——让微服务"互相通话"这件事变简单
1.1 没有服务网格时,微服务通信有多痛苦
想象一个大型写字楼,有100家公司,每家公司之间要互相传递文件。传统方式是:每家公司自己雇一个快递员,负责把所有文件送到其他公司。
1
2
3
4
5
|
写字楼A(微服务A)
↓ 快递员A:去B公司送合同
↓ 快递员A:去C公司送发票
↓ 快递员A:去D公司送报表
↓ 快递员A:去E公司……(快递员A累死了)
|
应用到微服务世界里,这个"快递员"就是在业务代码里写的HTTP/gRPC客户端。每次调用另一个服务,代码里就要写:
- 连接超时怎么设?
- 请求失败了要不要重试?重试几次?
- 被调用的服务挂了怎么办?要不要熔断?
- 调用方要验证调用者的身份吗?怎么验证?
- 日志要不要记录调用链路?Trace ID怎么传?
这些问题在每个微服务里都要写一遍。一旦某天要改(比如超时时间从2秒改成5秒),就要改100个服务的代码。
1.2 服务网格的做法:把"快递业务"外包出去
服务网格的思路是:不在每家公司内部养快递员了,在写字楼大厅设立一个统一的快递中心,所有公司都把文件交给快递中心,由快递中心统一配送。
1
2
3
4
5
6
|
快递中心(Service Mesh基础设施层)
↑ 统一接收
┌────────────┼────────────┐
│ │ │
公司A 公司B 公司C
(业务代码) (业务代码) (业务代码)
|
应用到这个场景:
- 每家公司门口的快递员 = Sidecar代理(Envoy),每个服务一个
- 快递中心 = Control Plane(Istiod),统一调度和管控
- 公司内部人员 = 业务代码,只管自己的业务逻辑
1.3 一句话总结积木一
服务网格 = Sidecar代理 + 控制平面。Sidecar接管所有网络通信(重试、熔断、加密、监控),业务代码不需要关心这些。
积木二:Sidecar是怎么工作的——Envoy到底在干什么
2.1 Sidecar到底是什么
在Kubernetes里,Sidecar是一个独立的容器,和业务容器部署在同一个Pod里,共享同一个网络命名空间(Network Namespace)。这意味着:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
一个Pod里的两个容器(共享Network Namespace):
┌─────────────────────────────────┐
│ Pod(共享Network NS) │
│ │
│ ┌──────────────┐ ┌──────────┐ │
│ │ 业务容器 │ │Sidecar │ │
│ │ nginx:latest │ │envoy │ │
│ │ :80 │ │:15000 │ │
│ │ │ │:15090 │ │
│ │ (处理业务) │ │(处理网络)│ │
│ └──────┬───────┘ └────┬─────┘ │
│ │ │ │
│ └────────┬───────┘ │
│ ↓ │
│ 共享网络栈 │
│ lo/eth0 │
└──────────────────────────────────┘
|
关键点:两个容器共享同一张网卡(eth0)。业务容器发出的请求,表面上是发给了nginx:80,实际上是先到了Envoy,由Envoy决定怎么转发。
2.2 Envoy的工作原理:用"门卫"来理解
把Envoy Sidecar想象成一个写字楼的智能门卫:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
外部请求
↓
┌─────────────────────┐
│ Envoy Sidecar │ ← 门卫
│ (Pod内的独立容器) │
│ │
│ 问自己三个问题: │
│ 1. 你是谁?(身份验证)│
│ 2. 你要去哪?(路由) │
│ 3. 路上小心点(监控) │
└──────────┬──────────┘
↓
业务容器 nginx
|
Envoy处理每个请求的过程,就相当于回答三个问题:
问题一:你是谁?
→ 你是通过mTLS证书证明身份的合法服务,还是来历不明的请求?(这是安全层)
问题二:你要去哪?
→ 你的目标服务是哪个版本?要不要做灰度流量分流?有没有超时设置?
→ 这个路由规则是Istiod通过xDS协议推送过来的(这是流量管理层)
问题三:你的请求是什么样的?
→ 延迟多少毫秒?返回状态码多少?有没有报错?(这是可观测性)
2.3 Envoy的"三层过滤器"——用安检来理解
想象机场安检的过程:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
乘客过安检(请求经过Envoy):
第一道安检:人身检查(Network Filter)
→ 你是人还是机器?(识别协议:HTTP/gRPC/TCP/MongoDB)
→ 如果是HTTP,进入第二道安检
→ 如果是TCP直接放行(或者MongoDB专用安检通道)
第二道安检:手提行李检查(HTTP Filter Chain)
→ 你的Header里有没有可疑内容?
→ 需不需要限流?
→ 需不需要改写URL(rewrite)?
第三道安检:登机口分配(Router Filter)
→ 你应该上哪个航班?(路由到哪个后端服务)
→ 这次航班满了吗?(熔断)
→ 这次航班有没有延误?(超时)
|
对应到Envoy的技术术语:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
# Envoy处理链(简化理解)
请求进入Envoy
│
↓
Listener Filter(监听器)—— 打开邮件,发现是挂号信还是平邮
│
↓
Network Filter(网络过滤器)—— 是HTTP信件还是快递包裹?
│
↓ (如果是HTTP)
HTTP Connection Manager
│
├─→ CORS Filter:检查跨域请求
├─→ RBAC Filter:检查访问权限
├─→ Rate Limit Filter:检查是否超速
├─→ Router Filter:查路由表,决定去哪
│ │
│ ↓
│ Cluster(目标服务池)
│ 例如:reviews 服务有v1/v2/v3三个版本
│ 路由表说5%去v2,95%去v1
│
└─→ 最终转发到目标服务
|
2.4 生活中的Envoy理解
| Envoy里的概念 |
生活中的比喻 |
| Listener(监听器) |
写字楼的收发室前台 |
| Filter Chain(过滤器链) |
安检X光机 + 人工检查 |
| Route(路由) |
分拣员,看快递单决定哪个柜台处理 |
| Cluster(集群) |
某个部门的全体员工名单 |
| Endpoint(端点) |
具体某个员工工位 |
| Load Balancer(负载均衡) |
分诊台护士,分配到哪个医生 |
| Circuit Breaker(熔断) |
自动跳闸保护,整层楼不会因为一台空调着火而全停 |
积木三:Pilot——Istiod的流量大脑
3.1 Pilot到底是什么
如果说Sidecar是执行者(真正处理每个请求),那么Pilot就是指挥官(告诉Sidecar该怎么处理请求)。
Pilot的工作是把我们在Kubernetes里写的YAML配置(如VirtualService、DestinationRule),翻译成Envoy能理解的配置格式(xDS),然后推送给每个Sidecar。
3.2 xDS协议——指挥官和士兵的"暗号"
xDS是Envoy定义的一组API协议,全称是"X Discovery Service"。Istio用gRPC流式推送配置给每个Sidecar。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
xDS的核心四个协议(每个士兵需要知道四件事):
1. LDS(Listener Discovery Service)—— 你要听哪个端口?
→ "每个士兵请监听15001端口(VirtualInbound)"
2. RDS(Route Discovery Service)—— 收到请求后走哪条路?
→ "收到/api/reviews的请求,5%去v2,95%去v1"
3. CDS(Cluster Discovery Service)—— 你认识哪些服务?
→ "reviews服务有三个版本v1/v2/v3,IP分别是...每个版本权重是多少"
4. EDS(Endpoint Discovery Service)—— 这些服务的具体地址是什么?
→ "v1版本现在有两台机器:10.0.0.21:80 和 10.0.0.22:80"
辅助协议:
5. EDS(扩展)—— 加上健康状态
→ "10.0.0.23这台机器最近不健康,暂时不要派请求过去"
|
3.3 Pilot的工作流程:配VShopment之后发生了什么
我们写一个VirtualService:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: reviews
spec:
hosts:
- reviews
http:
- route:
- destination:
host: reviews
subset: v1
weight: 95
- destination:
host: reviews
subset: v2
weight: 5
|
这个YAML在Pilot眼里是这样的:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
步骤1:读取YAML
→ 发现有一个VirtualService,名字是reviews
→ 目标是reviews服务
→ 95%权重去v1,5%去v2
步骤2:翻译成Envoy配置
→ 转换成RouteConfiguration格式
→ 告诉reviews的Sidecar:"收到发给我的请求,95%打v1标签的Pod,5%打v2标签的Pod"
步骤3:通过xDS推送给目标Pod
→ Pilot通过gRPC连接到reviews所有Pod的Envoy
→ 流式推送新的路由规则
→ Envoy热加载配置(不需要重启!)
步骤4:生效
→ 从下一秒开始,新的请求按新规则分配
→ 整个过程对用户无感知(Zero-Release Change)
|
3.4 Pilot的"服务发现"
Pilot会监听Kubernetes的API Server,实时感知:
1
2
3
4
5
6
7
8
9
10
|
Kubernetes API Server(Pilot实时监控):
Service/Endpoints变化事件:
✓ reviews服务新增了一个Pod(v3版本) → 立刻更新EDS配置
✓ ratings服务删除了一个Pod → 立刻剔除故障节点
✓ productpage的Label变了 → 自动重新计算路由
Pilot的处理速度:毫秒级别
Envoy的配置生效速度:秒级别(热加载)
用户感知:几乎无感知
|
积木四:Citadel——Istio的安全中心
4.1 为什么需要mTLS?先理解中间人攻击
想象一个餐厅的点餐系统:
1
2
3
4
5
6
7
8
9
10
11
|
没有mTLS的情况:
顾客 → 服务员A → 厨房
如果服务员A是坏人(中间人):
顾客 → [服务员A截获] → 厨房
↓
篡改订单:"加一份昂贵的鱼子酱"
再转发给厨房
厨师不知道这是被篡改的,照做。
账单出来,顾客才发现多了钱。
|
应用到微服务世界:如果服务A和服务B之间的网络通信是明文的,攻击者可以在中间截获、篡改、伪造请求。
4.2 mTLS的工作原理:双向身份证验证
mTLS(双向TLS)比普通HTTPS更严格:
1
2
3
4
5
6
7
|
普通HTTPS(单向认证):
客户端 → 餐厅(验证餐厅是合法的)
餐厅不需要验证客户端是谁
mTLS(双向认证):
客户端 → 餐厅(验证餐厅是合法的)
餐厅 ← 客户端(同时验证客户端也是合法的)
|
Istio的mTLS工作流程:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
Service A的Pod(Envoy A)要给Service B发请求:
1. 握手阶段(证书交换):
Envoy A → Envoy B:你好,这是我的身份证(X.509证书 + SPIFFE ID)
Envoy B → Envoy A:好的,我验证一下……这是我的身份证
双方确认:都是本大楼的合法员工(SPIFFE可信域验证)
2. 密钥协商(DHE/ECDH):
双方用对方的公钥协商出对称密钥
后续所有通信都用这个对称密钥加密
3. 加密通信:
之后的所有请求都在TLS隧道里传输
即使被截获,没有密钥也解不开
4. Citadel的作用:
Citadel = 写字楼的身份证管理处
每当有新员工入职(新建Pod),
→ 自动签发身份证(SPIFFE格式X.509证书)
→ 通知所有其他员工更新信任列表
|
4.3 SPIFFE ID——每个服务的"身份证号码"
Istio为每个Pod分配一个唯一的SPIFFE身份:
1
2
3
4
5
6
7
8
9
10
11
|
# SPIFFE ID格式:
spiffe://cluster.local/ns/{namespace}/sa/{service-account-name}
# 例子:
spiffe://cluster.local/ns/default/sa/bookinfo-reviews
↓ 翻译成人话
"这个Pod属于cluster.local这个集群的default命名空间,
使用的是bookinfo-reviews这个服务账号"
# 对应的证书CN(Common Name)字段:
CN = bookinfo-reviews
|
SPIFFE ID的作用:
- 每个服务的身份证号全球唯一
- AuthorizationPolicy里可以直接用SPIFFE ID做权限控制
- 不用记IP地址(IP会变,SPIFFE ID不变)
4.4 PeerAuthentication:mTLS的三种模式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
# Istio的安全三档(用门禁来理解):
DISABLED(不设防):
→ 大楼大门敞开,任何人都能进
→ 服务间通信明文传输
→ 危险:任何人都能截获和伪造
PERMISSIVE(宽容模式):
→ 大门有门禁,但也允许无证人员进入(员工可以不带卡)
→ mTLS加密的请求能进来
→ 不带证书的plain text请求也能进来
→ 用途:迁移阶段,逐步升级到严格mTLS
→ 危险:迁移完成后必须改成STRICT,否则等于没加密
STRICT(严格模式):⭐生产环境必须用
→ 大门必须刷卡才开(mTLS强制)
→ 没有合法身份证件(证书)的请求直接被拒绝
→ Envoy会在握手阶段就拒绝连接,不进入业务逻辑层
→ 最佳实践:新部署的服务一律开启STRICT
|
4.5 AuthorizationPolicy:谁可以访问谁
mTLS告诉你"你是谁",AuthorizationPolicy告诉你"你可以做什么"。
1
2
3
4
5
6
7
8
9
10
|
生活比喻:公司的门禁卡权限系统
普通门禁卡 → 可以开公司大门
管理员门禁卡 → 可以开大门 + 财务室 + 服务器机房
访客卡 → 只能开大门,在前台登记
对应到Istio:
→ productpage的身份证 → 可以访问reviews服务
→ reviews的身份证 → 不可以访问ratings服务(安全边界)
→ 外部未授权请求 → 直接拒绝,连Envoy层都进不去
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
# AuthorizationPolicy示例:reviews服务只允许productpage访问
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: reviews-access
spec:
selector:
matchLabels:
app: reviews
rules:
# 第一条:只允许productpage的身份
- from:
- source:
principals: # 身份证号码验证
- "cluster.local/ns/default/sa/bookinfo-productpage"
to:
- operation:
methods: ["GET"] # 只能查,不能改
paths: ["/reviews/*"] # 只能访问reviews路径
# 第二条:允许健康检查(不用身份验证)
- to:
- operation:
paths: ["/health", "/ready"]
|
积木五:可观测性——让服务的行为可见
5.1 三个问题:指标、日志、追踪
没有可观测性,网络出问题时的状态是:
1
2
3
4
5
6
7
8
9
|
用户打电话投诉:"网站打不开了"
运维工程师:
→ 登录Server A检查,OK
→ 登录Server B检查,OK
→ 登录数据库检查,OK
→ 查看日志,每台都有日志但不知道哪台出问题
→ 打电话给开发,开发说:"可能是网络问题"
→ 运维说:"我认为是代码问题"
→ 扯皮ing……
|
有可观测性之后的状态是:
1
2
3
4
5
6
7
|
运维打开Kiali/Grafana:
→ 产品页服务:绿色(正常)
→ 评论服务:红色(异常)
→ ratings服务:黄色(延迟高)
→ 具体问题:reviews→ratings的调用延迟从5ms飙升到3000ms
→ 点击查看Jaeger追踪:某次调用中ratings服务在处理某个请求时GC卡顿
→ 30分钟定位到根因并修复
|
5.2 指标(Metrics)——速度计
指标回答"服务整体运行得好不好"。
1
2
3
4
5
6
7
8
9
|
日常生活中的指标:
→ 汽车仪表盘:速度、转速、油量、温度
→ 你不需要知道发动机内部构造,只需要知道数字正不正常
Istio中的核心指标:
→ 每秒请求数(QPS):服务忙不忙
→ 请求成功率:100个请求里有几个失败了
→ 请求延迟P99:99%的请求在多少毫秒内完成
→ 并发连接数:有多少请求正在处理
|
Istio自动采集的三个经典指标:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
# 1. 请求总量(QPS)
istio_requests_total
labels: service, destination_service, response_code
→ "reviews服务在过去5分钟收到了5000个请求,99个返回500"
# 2. 请求延迟分布
istio_request_duration_milliseconds_bucket
labels: service, le (less than or equal)
→ "95%的reviews请求在50ms内完成"
→ "99%的reviews请求在200ms内完成"
# 3. 流量健康
istio_requests_total{response_code="503"}
→ 如果503错误突然飙升,说明服务开始不健康
|
5.3 日志(Logs)——行车记录仪
日志回答"刚才具体发生了什么"。
1
2
3
4
5
6
7
8
9
10
11
|
生活中的日志:
→ 行车记录仪:记录每一秒的画面
→ 医院的病历本:每次就诊的详细记录
Istio的Envoy日志包含:
→ 请求时间(UTC时间戳)
→ 客户端IP → 服务端IP
→ 请求方法(GET/POST)和路径
→ HTTP状态码(200/404/500)
→ 请求耗时(毫秒)
→ upstream服务(实际处理请求的服务)
|
1
2
3
4
5
6
7
8
|
# 查看reviews Pod的Envoy访问日志
kubectl logs -n default reviews-v1-xxxxx -c istio-proxy
# 输出示例:
[2026-05-04T10:23:15.234Z] "GET /reviews/1 HTTP/1.1"
200 - 15 - "-" "Python-urllib/3.0" "a3f2b8c9"
"reviews", "10.0.0.21:9080"
→ 一次成功的请求,耗时15ms,trace ID是a3f2b8c9
|
5.4 追踪(Traces)——全程录像
追踪回答"这个请求经过了哪些服务,每个服务花了多长时间"。
1
2
3
4
5
6
7
8
|
生活中的追踪:
→ 快递追踪:包裹从广州发出 → 中转到上海 → 到达北京
→ 每到一站记录:几点几分到的,处理了多久
Istio的分布式追踪:
→ productpage收到请求 → 调用reviews → reviews调用ratings → ratings调用details
→ 每个环节记录:开始时间、结束时间、发生在这个服务内的处理时间
→ 生成唯一的Trace ID,贯穿整个调用链
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
Jaeger追踪界面(一次productpage请求的完整链路):
Trace ID: abc123def456
Span 1: productpage(总耗时:85ms)
├─ Span 2: reviews(耗时:60ms)
│ ├─ Span 3: ratings(耗时:25ms)
│ │ └─ Span 4: details(耗时:10ms)
│ └─ (reviews在调用ratings时等待了35ms,这35ms在干什么?)
│ → 可以展开看ratings服务的内部详情(SQL查询、外部API调用等)
└─ (productpage自身处理耗时:25ms)
根因分析:
→ ratings服务的Span 3显示25ms,但其中10ms是details调用
→ 另有15ms是ratings在等待某个数据源(可能是Redis慢查询)
→ 结论:ratings服务的Redis连接池配置太小,高并发时等待时间长
|
综合实验:亲手验证Istio的每个积木
实验1:验证Sidecar拦截——请求到底有没有经过Envoy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
# 目标:证明所有流量都经过Sidecar,没有"漏网之鱼"
# 步骤1:在productpage Pod的Envoy上开启debug日志
kubectl exec -it -n default productpage-v1-xxxxx -c istio-proxy -- \
pilot-agent request GET 'logs?debug=1&level=debug'
# 步骤2:在另一个窗口发送请求
for i in {1..20}; do
curl -s http://productpage:9080/productpage > /dev/null
done
# 步骤3:查看Envoy日志——每条请求都被记录了
kubectl logs -n default productpage-v1-xxxxx -c istio-proxy \
--tail=50 | grep "reviews"
# 预期输出:每一条reviews的请求都被Envoy记录了下来
# 说明:即使业务代码只写了 reviews.GET(),
# 实际上请求先到了Envoy,Envoy才转发给reviews服务
|
实验2:验证Pilot配置推送——修改VS后Envoy发生了什么
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
|
# 目标:证明Pilot实时将配置推送给Sidecar,不需要重启Pod
# 步骤1:当前流量100%在v1
kubectl apply -f - <<'EOF'
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: reviews
spec:
hosts:
- reviews
http:
- route:
- destination:
host: reviews
subset: v1
weight: 100
EOF
# 步骤2:发送10个请求,全部应该打到v1
for i in {1..10}; do
curl -s http://productpage:9080/productpage | grep -o "reviews-v[1-3]"
sleep 0.2
done
# 预期:10个reviews-v1
# 步骤3:一键改成5%流量去v2(不用动任何Pod!)
kubectl apply -f - <<'EOF'
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: reviews
spec:
hosts:
- reviews
http:
- route:
- destination:
host: reviews
subset: v1
weight: 95
- destination:
host: reviews
subset: v2
weight: 5
EOF
# 步骤4:立即再次发送10个请求
for i in {1..10}; do
curl -s http://productpage:9080/productpage | grep -o "reviews-v[1-3]"
sleep 0.2
done
# 预期:大约9个v1,1个v2(5%概率)
# 关键观察:
# ① 没有任何Pod被重启
# ② 没有任何Pod被重新部署
# ③ Pilot通过xDS在秒级将新配置推送给所有reviews Pod的Sidecar
# ④ Envoy热加载配置,无需重启
|
实验3:验证mTLS——明文请求被拒绝
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
# 目标:开启STRICT mTLS后,没有证书的请求会被Envoy直接拒绝
# 步骤1:开启严格mTLS
kubectl apply -n default -f - <<'EOF'
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: default
spec:
mtls:
mode: STRICT
EOF
# 步骤2:用没有mTLS的curl测试(模拟外部入侵者)
kubectl run -n default --rm -it --image=curlimages/curl --restart=Never \
-- curl -s http://reviews.default.svc.cluster.local:9080/reviews/1
# 预期结果:请求被拒绝!
# HTTP状态码:503(Service Unavailable)
# Envoy日志:TLS handshake failed
# 说明:外部plain text请求没有合法证书,被Envoy直接拒绝了
# 步骤3:用mesh内的有证书Pod测试(模拟合法服务间调用)
kubectl exec -it -n default productpage-v1-xxxxx -c istio-proxy -- \
curl -s http://reviews:9080/reviews/1
# 预期结果:成功返回JSON
# 说明:两个Sidecar之间用mTLS加密通信,Envoy验证证书后放行
|
实验4:验证可观测性——Kiali看拓扑图
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
# 目标:用图形化方式看到服务之间的真实调用关系
# 步骤1:安装Kiali(如果还没装)
kubectl apply -f samples/addons/kiali.yaml
# 步骤2:端口转发
kubectl port-forward -n istio-system svc/kiali 20001:20001 &
# 步骤3:浏览器打开
# http://localhost:20001
# Kiali界面说明:
# ┌─────────────────────────────────────────┐
# │ Graph 视图 │
# │ │
# │ productpage ────────→ reviews │
# │ │ │ │
# │ ↓ ↓ │
# │ details ratings │
# │ ↓ │
# │ details │
# │ │
# │ 线条粗细 = QPS高低 │
# │ 颜色 = 健康状态(绿=正常,红=异常) │
# │ 点击任意服务 → 详情面板 │
# └─────────────────────────────────────────┘
# 步骤4:点击reviews服务
# → 看到三个版本的流量分布(v1:xxx%, v2:xxx%, v3:xxx%)
# → 看到每个版本的请求成功率(P99延迟)
# → 看到入口流量和出口流量的详细数据
|
积木串联:完整理解Istio的请求生命周期
把五块积木串起来,就是一次请求的完整旅程:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
用户点击"查看评论"
↓
① 请求到达productpage Pod
② Envoy拦截请求(Listener:15006/15001)
→ "你是谁?"(mTLS证书验证)
→ 通过 → 进入HTTP Filter Chain
→ 不通过 → Envoy直接返回403
③ 业务容器处理,调用reviews服务
→ 代码里写的是:requests.get("http://reviews:9080/reviews/1")
→ 实际:请求先发到本地Envoy Sidecar
④ Envoy查询本地路由配置(RDS)
→ VirtualService说:5%去v2,95%去v1
→ Envoy决定目标:v1版本(根据随机+权重算法)
⑤ Envoy查询v1版本的Pod IP(EDS)
→ 有两个Pod:10.0.0.21(v1-1)和10.0.0.22(v1-2)
→ 负载均衡:选择10.0.0.21
⑥ Envoy转发请求(mTLS加密)
→ 源IP:productpage Pod IP
→ 目标IP:10.0.0.21
→ 内容:加密的HTTP请求
⑦ reviews-v1 Pod的Envoy接收请求
→ 验证productpage的身份(SPIFFE ID)
→ AuthorizationPolicy检查:productpage有权访问reviews → 放行
⑧ reviews业务容器处理,返回响应
⑨ reviews Envoy记录指标
→ istio_requests_total{reviews, v1} += 1
→ istio_request_duration_milliseconds_bucket{le=50} += 1
→ 生成Trace ID,附加到响应header(X-B3-TraceId)
⑩ 响应返回给productpage,productpage继续调用ratings(重复④-⑨)
⑪ Jaeger收集所有span,生成完整调用链
⑫ Grafana展示dashboard,P50/P90/P99延迟一目了然
⑬ Kiali实时更新拓扑图,颜色变红说明有问题
|
常见误区纠正
| 误区 |
正确理解 |
| “Istio会拖慢网络” |
Envoy在数据面直连处理,延迟增加约1-3ms,对大多数应用可忽略。Ambient模式下仅0.3ms |
| “Sidecar占用很多内存” |
每个Sidecar约50-100MB,在现代容器环境中占比很小(大多数Pod内存1-2GB) |
| “Istio配置太复杂,不需要” |
复杂是相对的。用Ansible/Terraform可以模板化管理,配置复杂度远低于在每个服务里手写重试/熔断/鉴权逻辑 |
| “测试环境不需要mTLS” |
恰恰相反,测试环境应开启mTLS,发现问题比生产环境便宜得多 |
| “Kiali只是好看的图” |
Kiali的拓扑图是排查故障最快的方式,比翻日志高效10倍 |
| “服务少,不需要Istio” |
Istio的价值在于统一治理。当服务数量超过5个,网格化管理就开始体现优势 |
关联文章:
- 《Istio服务网格完全指南:从原理到生产环境实验教程》——面向生产环境的高级特性与完整部署
- 《企业网络路由协议选型与核心技术指南》——服务网格底层的网络基础设施