Istio保姆级入门指南:像搭积木一样理解服务网格,每个组件掰开讲

从零开始,用生活化的比喻和逐行图解拆解Istio的每个组件——Sidecar怎么工作的?Pilot是什么?为什么需要mTLS?一次讲清楚,不留盲区。

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%去v295%去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服务网格完全指南:从原理到生产环境实验教程》——面向生产环境的高级特性与完整部署
  • 《企业网络路由协议选型与核心技术指南》——服务网格底层的网络基础设施
CC BY-NC-SA 4.0
comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计