五、Istio管理网格外部服务

发布于:2025-08-12 ⋅ 阅读:(16) ⋅ 点赞:(0)

因语雀与csdn markdown 格式有区别,请查看原文:
https://www.yuque.com/dycloud/pss8ys

一、Egress Listener 流量策略

前面学习了 sidecar 自动注入原理、inbound Listener、outbound Listener 等概念,也知道了 EgressListener 的流量策略是有两个:<font style="color:#DF2A3F;">ALLOW_ANY</font><font style="color:#DF2A3F;">REGISTRY_ONLY</font>,这里来详细的学习一下 这两种策略的区别

1.1 ALLOW_ANY 和 REGISTRY_ONLY 定义

  • <font style="color:#DF2A3F;">ALLOW_ANY</font>(默认模式):允许 Pod 访问任何外部服务(不管是否在服务注册表中),对于未注册的目标,Sidecar 执行透传(<font style="color:#DF2A3F;">Passthrough</font>),但这些外部目标流量无法纳入到治理体系中,实施如<font style="color:#DF2A3F;">retry</font><font style="color:#DF2A3F;">timeout</font><font style="color:#DF2A3F;">fault injection</font>一类的功能。
  • <font style="color:#DF2A3F;">REGISTRY_ONLY</font>(限制模式):只允许访问明确注册的服务(Kubernetes Service 或 ServiceEntry),拒绝所有未注册的外部服务(返回 HTTP 502 或者 TCP 连接错误)。

1.2 查看当前策略

<font style="color:#DF2A3F;">Egress Listener </font>流量的策略配置由 Istio 的全局配置 MeshConfig 控制,配置在 <font style="color:#DF2A3F;">istio-system</font> 命名空间的 <font style="color:#DF2A3F;">istio ConfigMap</font>

查看当前全局策略:

[root@k8s-master01 ~]# kubectl get configmap istio -n istio-system  -o yaml 
...
outboundTrafficPolicy:
  mode: ALLOW_ANY
  egressProxy: # 可选出口代理配置
...

查看 Sidecar 级别的策略:

[root@k8s-master01 ~]# kubectl get sidecar -n app client -o yaml | grep outboundTrafficPolicy
      {"apiVersion":"networking.istio.io/v1beta1","kind":"Sidecar","metadata":{"annotations":{},"name":"client","namespace":"app"},"spec":{"egress":[{"hosts":["./*"],"port":{"name":"frontend","number":80,"protocol":"HTTP"}}],"outboundTrafficPolicy":{"mode":"REGISTRY_ONLY"},"workloadSelector":{"labels":{"app":"client"}}}}
  outboundTrafficPolicy:

1.3 修改策略配置

全局策略修改:

[root@k8s-master01 ~]# kubectl edit configmap istio -n istio-system
data:
  mesh: |-
    outboundTrafficPolicy:
      mode: REGISTRY_ONLY  # 修改此处
[root@k8s-master01 ~]# kubectl get configmap istio -n istio-system -o jsonpath='{.data.mesh}' | grep -A 2 outboundTrafficPolicy
outboundTrafficPolicy:
  mode: REGISTRY_ONLY  
accessLogFile: /dev/stdout

命名空间级覆盖

apiVersion: networking.istio.io/v1
kind: Sidecar
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"networking.istio.io/v1beta1","kind":"Sidecar","metadata":{"annotations":{},"name":"client","namespace":"app"},"spec":{"egress":[{"hosts":["./*"],"port":{"name":"frontend","number":80,"protocol":"HTTP"}}],"outboundTrafficPolicy":{"mode":"REGISTRY_ONLY"},"workloadSelector":{"labels":{"app":"client"}}}}
  creationTimestamp: "2025-08-05T07:41:14Z"
  generation: 2
  name: client
  namespace: app
  resourceVersion: "7432144"
  uid: 05872ea2-2a25-432a-b2d4-1402e555bf3c
spec:
  egress:
  - hosts:
    - ./*
    port:
      name: frontend
      number: 80
      protocol: HTTP
  outboundTrafficPolicy:
    mode: REGISTRY_ONLY
  workloadSelector:
    labels:
      app: client

1.4 ALLOW_ANY 模式详解

1.4.1 处理流程

  • 业务容器 发起请求 external.com:80。
  • iptables 把流量重定向到本地 Envoy 代理(15001端口)。
  • Envoy 检查注册表(即 Istio 下发的集群、服务路由规则)。
    • 如果目标已在注册表中(如有 ServiceEntry 或 K8s Service),走“智能路由”(可做流控、灰度、限流等)。
    • 如果目标未注册,则创建 ORIGINAL_DST 集群,即透明代理:Envoy 将请求直接转发到原IP:Port(sidecar不干预,全部经过 passthrough)。
  • 响应路径反向返回给业务容器。

这里设计到几个概念,ORIGINAL_DST 集群、TCP 协议透传,下面来学习下

1.4.2 透传(Passthrough)

当 Sidecar 代理到未注册的外部目标时,直接使用原始请求转发而不进行任何处理。

特点:

  • 不修改请求内容(TCP 转发)
  • 不应用任何流量策略(如重试、超时、负载均衡等)
  • 不收集应用层指标(仅基础 TCP 指标)
  • 类似于网络中的透明代理,只负责转发,不干预内容。
  • <font style="color:#DF2A3F;">ORIGINAL_DST</font> 模式下,原始报文中的 IP 和端口信息会被完整保留。
信息元素 是否保留 说明
源 IP 地址 ✅ 完全保留 Pod 的实际 IP 地址
源端口 ✅ 完全保留 应用程序分配的原始端口
目标 IP 地址 ✅ 完全保留 应用程序指定的目标 IP
目标端口 ✅ 完全保留 应用程序指定的目标端口
协议类型 ✅ 完全保留 TCP/UDP 等传输层协议

透传的触发条件:

  • 仅在 **<font style="color:#DF2A3F;">ALLOW_ANY</font>** 模式下生效
  • 目标服务**未**在Istio服务注册表中注册(即不是Kubernetes Service或ServiceEntry)

1.4.3 ORIGINAL_DST 集群

  • **<font style="color:#DF2A3F;">ORIGINAL_DST</font>** 是Envoy支持的一种特殊集群类型。
  • 当使用这种集群时,Envoy会将流量转发到**原始目标地址**(即未被iptables重定向前的目标地址)。
  • 在Istio中,它用于处理未注册外部流量的透传。
特性 说明
目标获取 通过Linux内核的 <font style="color:#DF2A3F;">SO_ORIGINAL_DST</font>选项获取原始目标
负载均衡 无负载均衡,每个请求直连原始目标
协议处理 仅TCP层转发,不解析应用层协议
连接管理 不应用连接池、健康检查等高级功能

[root@k8s-master01 ~]# istioctl  proxy-config route frontend-7c55c868cf-6mpj7 -n app  --name 8080  -o yaml 
...
    - '*'
    includeRequestAttemptCount: true
    name: allow_any
    routes:
    - match:
        prefix: /
      name: allow_any
      route:
        cluster: PassthroughCluster
        maxGrpcTimeout: 0s
        timeout: 0s

1.5 REGISTRY_ONLY 模式详解

1.5.1 处理流程

1. **App 发起出站请求 **unregistered.com

  • 流量被 iptables 劫持到本地 Envoy(sidecar)。

2. Envoy 检查本地服务注册表缓存

  • Envoy 在内存中缓存了 Istiod 下发的服务注册数据(如集群、目标域名/IP)。
  • 分两种情况:
    • 已缓存且目标注册:直接正常路由出站
    • 已缓存但目标未注册立刻返回 502 错误,不再向 Istiod 查询

3. 缓存未命中——Envoy 请求 Istiod 服务发现(xDS接口)

  • Envoy 没见过这个目标,向 Istiod 发起 xDS 查询,请求目标主机的配置

4. Istiod 检查 **<font style="color:#DF2A3F;">ServiceEntry</font>**/K8s Service

  • 如果注册表中有目标(unregistered.com已登记):
    • 返回目标的集群信息,Envoy补全本地缓存,进入正常路由流程
  • 如目标未注册
    • Istiod 返回“空配置”(无可达目标),Envoy 依照标准处理

5. Envoy 依实际配置处理请求

  • 目标未注册:Envoy 返回 502(Bad Gateway)给应用层
  • 目标已注册:Envoy 按配置发送请求,响应正常

1.5.2 BlackHoleCluster 集群

BlackHoleCluster 是 Envoy 代理中的一种特殊集群类型,在 Istio REGISTRY_ONLY 模式下有以下功能:

  • 丢弃所有发送到该集群的流量
  • 实现严格的出口流量控制
  • 当目标未在 Istio 注册表中注册时才会触发。
特性 BlackHoleCluster 标准集群
端点数量 0 (空列表) ≥1
流量处理 立即丢弃 正常路由
响应类型 协议感知拒绝 成功响应
配置方式 动态生成 静态/动态
监控指标 明确拒绝计数 成功/失败统计

1.5.3 协议特定的拒绝行为

协议类型 拒绝信号 客户端表现 Wireshark 特征
HTTP/1.x 502 Bad Gateway <font style="color:rgb(251, 71, 135);">curl: (52) Empty reply</font> [RST] 包
HTTP/2 GOAWAY 帧 <font style="color:rgb(251, 71, 135);">curl: (92) HTTP/2 stream 0 was not closed</font> HTTP/2 GOAWAY
HTTPS TLS Alert <font style="color:rgb(251, 71, 135);">curl: (35) OpenSSL SSL_connect: SSL_ERROR_SYSCALL</font> TLS Alert 21
gRPC UNAVAILABLE <font style="color:rgb(251, 71, 135);">status=14 UNAVAILABLE</font> gRPC 状态码
Raw TCP Connection reset <font style="color:rgb(251, 71, 135);">connect: connection reset by peer</font> [RST, ACK] 包

二、ServiceEntry

2.1 ServiceEntry 定义

ServiceEntry 是将外部服务注册到 Istio 服务网格中的 CRD 资源,他可以扩展服务网格的发现范围、定义外部服务的协议和端口特性、控制网格对外部服务的访问策略等等。

  • <font style="color:#DF2A3F;">ServiceEntry CR</font>就用于向Istio内部维护的服务注册表(Registry)上手动添加注册项(即Entry)从而将那些未能自动添加至网格中的服务,以手动形式添加至网格中
  • 向Istio的服务注册表添加一个<font style="color:#DF2A3F;">ServiceEntry</font>后,网格中的Envoy可以流量发送给该Service,其行为与访问网格中原有的服务并无本质上的不同;
  • 有了ServiceEntry,用户也就能像治理网格内部流量一样来治理那些访问到网格外部的服务的流量。

2.2 ServiceEntry 功能介绍

  • 重定向和转发访问外部目标的流量,例如哪些访问网格外部的传统服务的流量
  • 可以为外部目标添加高级流量治理功能,如 <font style="color:#DF2A3F;">retry</font>(重试)、<font style="color:#DF2A3F;">timeout</font>(超时)、<font style="color:#DF2A3F;">fault injection</font>(故障注入)和<font style="color:#DF2A3F;"> circuit breaker</font>(熔断)等一类功能。
  • 可以将 VM 添加到网格中,从而能够在 VM 上运行网格的服务。
  • 可以将不同集群中的服务添加到网格中,让 k8s 配置多集群的 istio 网格。

这里需要注意点是,访问外部服务时,之前学习的 Sidecar Envoy 本身就可以支持将这些外部的流量直接通过 <font style="color:#DF2A3F;">Passthrough</font> 到外部的端点上,所以 <font style="color:#DF2A3F;">ServiceEntry</font> 并不是一个必须添加的资源

使用 ServiceEntry 是为了能够更好的对外部流量进行 Istio 自带的高级流量治理功能,具体的治理机制还是要靠之前学习的 <font style="color:#DF2A3F;">VirtualService</font><font style="color:#DF2A3F;">DestinationRule</font> 来实现。

2.3 ServiceEntry 处理的服务类型

ServiceEntry 主要解决两类服务的集成问题:

  • <font style="color:#DF2A3F;">MESH_EXTERNAL</font>:网格外部的服务
    • Kubernetes 集群外部的服务(虚拟机、物理机)
    • 非 Istio 管理的 Kubernetes 命名空间中的服务
  • <font style="color:#DF2A3F;">MESH_INTERNAL</font>:网格内部但没有自动注册的服务
    • 网格内运行但未注册到 istio 服务注册表的服务
    • 需要特殊处理的服务端点

2.4 ServiceEntry CR 资源定义

ServiceEntry本身用于描述要引入的外部服务的属性,主要包括服务的DNS名称、IP地址、端口、协议和相关的端点等;

  • 端点的获取方式有三种:
    • DNS名称解析
    • 静态指定:直接指定要使用端点
    • 使用**<font style="color:#DF2A3F;">workloadSelector</font>**:基于标签选择器匹配Kubernetes Pod,或者由**<font style="color:#DF2A3F;">WorkloadEntry</font>** CR引入到网格中的外部端点
apiVersion: networking.istio.io/v1beta1
kind: ServiceEntry
metadata:
  name: external-service
spec:
  hosts:
  - api.external.com # 关键标识符
  location: MESH_EXTERNAL # 或 MESH_INTERNAL
  ports:
  - number: 443
    name: https
    protocol: HTTPS
  resolution: DNS # 端点解析方式
  endpoints: # 静态端点列表
  - address: 192.168.1.10
    ports:
      https: 8443
  workloadSelector: # 动态端点选择器
    labels:
      app: legacy-backend

2.4.1 <font style="color:rgb(251, 71, 135);">hosts</font> 字段

  • 作用:服务标识符,用于 <font style="color:#DF2A3F;">VirtualService</font><font style="color:#DF2A3F;">DestinationRule</font> 匹配
  • 协议特定行为
    • HTTP 流量:匹配 <font style="color:rgb(251, 71, 135);">Host</font>/<font style="color:rgb(251, 71, 135);">Authority</font>
    • TLS 流量:匹配 SNI(Server Name Indication)
    • TCP 流量:仅通过端口匹配

示例:

hosts:
- "*.example.com" # 通配符支持
- "api.external.com"

2.4.2 <font style="color:#DF2A3F;">location</font> 类型

类型 场景 流量特征
<font style="color:rgb(251, 71, 135);">MESH_EXTERNAL</font> 外部API、云服务 出口流量,通常需要加密
<font style="color:rgb(251, 71, 135);">MESH_INTERNAL</font> 网格内未注册服务 内部流量,可应用完整网格策略

2.4.3 <font style="color:#DF2A3F;">resolution</font> 解析方式

模式 工作原理 适用场景 Envoy 等效模式
<font style="color:rgb(251, 71, 135);">NONE</font> 假设地址已解析 已有负载均衡器 ORIGINAL_DST
<font style="color:rgb(251, 71, 135);">STATIC</font> 使用endpoints字段中指定 的静态IP地址作为与服务关系的实例 固定IP服务 STATIC
<font style="color:rgb(251, 71, 135);">DNS</font> 通过异步查询DNS来解析IP地址;类似于Envoy Cluster发现Endpoint的<font style="color:#DF2A3F;">STRICT_DNS</font> 动态DNS服务 STRICT_DNS
<font style="color:rgb(251, 71, 135);">DNS_ROUND_ROBIN</font> 通过异步查询DNS来解析IP地址,但与前者不同的是,仅在需要启动新连接时使用返回的第 一个IP地址,而不依赖于DNS解析的完整结果;类似于Envoy Cluster发现Endpoint的<font style="color:#DF2A3F;">LOGICAL_DNS</font> 大型服务 LOGICAL_DNS

2.4.3 三种端点发现机制

静态端点示例:

endpoints:
- address: 192.168.1.10
  ports:
    https: 8443 # 覆盖服务级端口
  labels:
    env: prod
- address: 192.168.1.11
  ports:
    https: 8444

workloadSelector 示例

workloadSelector:
  labels:
    app: legacy-app
    env: prod

2.5 ServiceEntry 的集成机制

2.5.1 配置生成流程

ServiceEntry之于Istio来说,其功能类似于自动发现并注册的Service对象,主要负责于网格中完成如下功能:

  • 基于指定的端口创建Listener,若已存在相应的侦听器,则于侦听器上基于hosts的定义,生成<font style="color:#DF2A3F;">VirtualHost</font>
  • 基于解析(resolution)得到的端点创建Cluster
  • 生成Route Rule,设定侦听器将接收到的发往相应VirtualHost的流量,路由至生成的Cluster

2.5.1.1 Listener 生成
  • 基于 <font style="color:rgb(251, 71, 135);">ports</font> 创建新监听器
  • 或扩展现有监听器的 VirtualHost
  • 示例配置
{
  "name": "0.0.0.0_443",
  "filter_chains": [{
    "filters": [{
      "name": "envoy.filters.network.http_connection_manager",
      "typed_config": {
        "route_config": {
          "virtual_hosts": [{
            "name": "api.external.com:443",
            "domains": ["api.external.com"]
          }]
        }
      }
    }]
  }]
}

2.5.1.2 Cluster 生成
  • 基于 <font style="color:rgb(251, 71, 135);">resolution</font> 和端点信息创建
{
  "name": "outbound|443||api.external.com",
  "type": "STRICT_DNS",
  "load_assignment": {
    "cluster_name": "api.external.com",
    "endpoints": [{
      "lb_endpoints": [{
        "endpoint": {
          "address": {
            "socket_address": {
              "address": "api.external.com",
              "port_value": 443
            }
          }
        }
      }]
    }]
  }
}

2.5.1.3 Route 生成

将流量路由到生成的 Cluster

{
  "name": "api.external.com",
  "domains": ["api.external.com"],
  "routes": [{
    "match": {"prefix": "/"},
    "route": {
      "cluster": "outbound|443||api.external.com"
    }
  }]
}

2.5.2 自定义流量管理

  • 可自定义VirtualService修改<font style="color:#DF2A3F;">ServiceEntry</font>默认生成的<font style="color:#DF2A3F;">Routes</font>
    • 通过指定的<font style="color:#DF2A3F;">hosts</font>(主机名)适配到要修改的Route的位置
    • 路由目标配置等可按需进行定义,包括将流量路由至其它目标
  • 可自定义<font style="color:#DF2A3F;">DestinationRule</font>修改ServiceEntry默认生成的<font style="color:#DF2A3F;">Cluster</font>
    • 通过指定的hosts(主机名)适配到要修改的Cluster
    • 常用于集群添加各种高级设定,例如<font style="color:#DF2A3F;">subset</font><font style="color:#DF2A3F;">circuit breaker</font><font style="color:#DF2A3F;"> traffic policy</font>等;
2.5.2.1 VirtualService 定制管理示例
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: custom-api-routing
spec:
  hosts:
  - api.external.com # 匹配ServiceEntry的hosts
  http:
  - match:
    - headers:
        x-env: 
          exact: canary
    route:
    - destination:
        host: api.external.com
        subset: canary
  - route:
    - destination:
        host: api.external.com
        subset: stable

2.5.2.2 DestinationRule 增强示例
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: api-policy
spec:
  host: api.external.com
  trafficPolicy:
    loadBalancer:
      simple: ROUND_ROBIN
    connectionPool:
      tcp:
        maxConnections: 100
  subsets:
  - name: canary
    labels:
      version: v2
    trafficPolicy:
      loadBalancer:
        simple: LEAST_CONN
  - name: stable
    labels:
      version: v1

2.6 ServiceEntry 配置案例

这里有一个详细的案例,包括多个Nginx服务部署在Docker Compose中)和一个Kubernetes集群中的客户端。客户端通过Istio的<font style="color:#DF2A3F;">ServiceEntry</font>访问外部<font style="color:#DF2A3F;">Nginx</font>服务

2.6.1 案例环境准备

1. Docker Compose 配置

运行三个Nginx服务,每个服务:

  • 使用特定版本的Nginx镜像(1.25-alpine或1.26-alpine)
  • 挂载自定义HTML目录(显示不同内容)
  • 在Docker网络<font style="color:#DF2A3F;">nginx_net</font>(172.31.201.0/24)中有固定IP
  • 关键:将容器80端口映射到宿主机的特定IP和端口(如 10.122.24.139:8091)

注意:宿主机的IP(10.122.24.x)是Kubernetes节点能访问的IP。

2. Kubernetes 客户端配置

  • Deployment:创建一个Pod,添加hostAliases将nginx.dujie.comnginx解析到172.29.1.201(注意:这里只写了一个IP,但ServiceEntry会覆盖这个解析
  • Service:为客户端Pod创建ClusterIP服务(非必须,本案例中客户端不需要被访问)

2.6.2 创建命名空间并添加自动注入

kubectl create ns entry 
kubectl label namespace entry istio-injection=enabled

2.6.3 创建 Client 资源

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: client
  name: client
  namespace: entry
spec:
  replicas: 1
  selector:
    matchLabels:
      app: client
      version: v1.2
  template:
    metadata:
      labels:
        app: client
        version: v1.2
    spec:
      hostAliases:
      - hostnames: ["nginx.dujie.com", "nginx"]
        ip: '172.29.1.201'
      containers:
      - image: ikubernetes/admin-box:v1.2
        name: admin-box
        command: ['/bin/sh', '-c', 'sleep INFINITE']
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: client
  name: client
  namespace: entry
spec:
  ports:
  - name: http-80
    appProtocol: http
    port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: client
    version: v1.2
  type: ClusterIP

2.6.4 ServiceEntry 资源配置

apiVersion: networking.istio.io/v1beta1
kind: ServiceEntry
metadata:
  name: nginx-external
  namespace: entry
spec:
  hosts:
  - nginx.dujie.com
  - nginx
  addresses:  # 定义服务的虚拟IP列表
  - "10.122.24.139"
  # Service Port
  ports:
  - number: 80
    name: http
    protocol: HTTP
  location: MESH_EXTERNAL
  resolution: STATIC
  endpoints:
  - address: "10.122.24.139"
    ports:
      http: 8091
  - address: "10.122.24.139"
    ports:
      http: 8092
  - address: "10.122.24.139"
    ports:
      http: 8093

**<font style="color:rgb(251, 71, 135);">addresses</font>** 字段

  • ****定义该服务的虚拟IP地址(VIP)列表
  • 覆盖DNS解析:当应用访问 <font style="color:#DF2A3F;">nginx.dujie.com</font> 时,Istio 会强制解析为这些IP(而不是真实DNS记录)
  • 流量劫持:Envoy Sidecar 会拦截目标为这些IP的流量

为什么需要

  • 如果外部服务有多个IP,但DNS只返回一个(如轮询解析),用此字段确保所有IP都被识别
  • 避免DNS污染:即使客户端缓存了旧IP,流量也会被正确劫持

**<font style="color:#DF2A3F;">endpoints</font>** 字段

  • 作用:定义服务的实际后端实例(Endpoint)列表
  • 关键属性
  • <font style="color:#DF2A3F;">address</font>:后端实例的真实IP
  • <font style="color:#DF2A3F;">ports</font>:实例暴露的实际端口(可不同于服务的虚拟端口)

2.6.5 DestinationRule 配置

apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: nginx-external
  namespace: entry
spec:
  host: nginx.dujie.com
  trafficPolicy:
    loadBalancer:
      consistentHash:
        httpHeaderName: x-user
    connectionPool:
      tcp:
        maxConnections: 10000
        connectTimeout: 10ms
        tcpKeepalive:
          time: 7200s
          interval: 75s
      http:
        http2MaxRequests: 1000
        maxRequestsPerConnection: 10
    outlierDetection:
      maxEjectionPercent: 50
      consecutive5xxErrors: 5
      interval: 2m
      baseEjectionTime: 1m
      minHealthPercent: 40

2.6.6 VirtualService 配置准备

apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: nginx-external
  namespace: entry
spec:
  hosts:
  - nginx.dujie.com
  http:
  - name: falut-injection
    match:
    - headers:
        X-Testing:
          exact: "true"
    route:
    - destination:
        host: nginx.dujie.com
    fault:
      delay:
        percentage:
          value: 5
        fixedDelay: 2s
      abort:
        percentage:
          value: 5
        httpStatus: 555
  - name: nginx-external
    route:
    - destination:
        host: nginx.dujie.com

2.6.6 Docker-compose 配置

version: '3.3'

services:
  nginx2501:
    image: nginx:1.25-alpine
    volumes:
      - ./html/nginx2501:/usr/share/nginx/html/
    networks:
      nginx_net:
        ipv4_address: 172.31.201.11
        aliases:
        - nginx
    expose:
      - "80"
    ports:
      - "10.122.24.139:8091:80"

  nginx2502:
    image: nginx:1.25-alpine
    volumes:
      - ./html/nginx2502:/usr/share/nginx/html/
    networks:
      nginx_net:
        ipv4_address: 172.31.201.12
        aliases:
        - nginx
    expose:
      - "80"
    ports:
      - "10.122.24.139:8092:80"

  nginx2601:
    image: nginx:1.26-alpine
    volumes:
      - ./html/nginx2601:/usr/share/nginx/html/
    networks:
      nginx_net:
        ipv4_address: 172.31.201.13
        aliases:
        - nginx
        - canary
    expose:
      - "80"
    ports:
      - "10.122.24.139:8093:80"

networks:
  nginx_net:
    driver: bridge
    ipam:
      config:
        - subnet: 172.31.201.0/24

docker-compose 中每个容器都会挂在不同的 index 目录

[root@k8s-master01 /usr/local/src]# cat nginx2501/index.html 
<title>nginx.dujie.com</title>
Nginx 2501 ~~
[root@k8s-master01 /usr/local/src]# cat nginx2502/index.html 
<title>nginx.dujie.com</title>
Nginx 2502 ~~
[root@k8s-master01 /usr/local/src]# cat nginx2601/index.html 
<title>nginx.dujie.com</title>
Nginx 2601 ~~

2.6.7 测试

2.6.7.1 测试基本访问

会轮流返回

[root@k8s-master01 /usr/local/src]# kubectl get pods -n entry 
NAME                      READY   STATUS    RESTARTS   AGE
client-78c98df4f6-2x6lk   2/2     Running   0          86m
[root@k8s-master01 /usr/local/src]# kubectl exec -it -n entry  client-78c98df4f6-2x6lk  -- bash 
root@client-78c98df4f6-2x6lk /# while true; do CONTENT=$(curl -s -H "x-canary: true" nginx.dujie.com); echo $CONTENT; sleep 0.$RANDOM; done
<title>nginx.dujie.com</title> Nginx 2501 ~~
<title>nginx.dujie.com</title> Nginx 2601 ~~
<title>nginx.dujie.com</title> Nginx 2501 ~~
<title>nginx.dujie.com</title> Nginx 2502 ~~
<title>nginx.dujie.com</title> Nginx 2601 ~~
<title>nginx.dujie.com</title> Nginx 2501 ~~
<title>nginx.dujie.com</title> Nginx 2601 ~~
<title>nginx.dujie.com</title> Nginx 2501 ~~
<title>nginx.dujie.com</title> Nginx 2502 ~~
<title>nginx.dujie.com</title> Nginx 2501 ~~
<title>nginx.dujie.com</title> Nginx 2502 ~~
2.6.7.2 测试会话保持

可以看到请求头中携带 x-user 字段的请求都会被转发到同一台后端节点

root@client-78c98df4f6-2x6lk /# while true; do CONTENT=$(curl -s -H "x-user: dujie" nginx.dujie.com); echo $CONTENT; sleep 0.$RANDOM; done
<title>nginx.dujie.com</title> Nginx 2601 ~~
<title>nginx.dujie.com</title> Nginx 2601 ~~
<title>nginx.dujie.com</title> Nginx 2601 ~~
<title>nginx.dujie.com</title> Nginx 2601 ~~
<title>nginx.dujie.com</title> Nginx 2601 ~~
<title>nginx.dujie.com</title> Nginx 2601 ~~
<title>nginx.dujie.com</title> Nginx 2601 ~~
<title>nginx.dujie.com</title> Nginx 2601 ~~
<title>nginx.dujie.com</title> Nginx 2601 ~~
<title>nginx.dujie.com</title> Nginx 2601 ~~

2.6.7.3 测试故障注入

可以看到下面的会有 5%的请求被返回 555,5%的请求会延迟 2 秒

root@client-78c98df4f6-2x6lk /# while true; do CONTENT=$(curl -s -H "X-Testing: true" nginx.dujie.com); echo $CONTENT; sleep 0.$RANDOM; done
<title>nginx.dujie.com</title> Nginx 2501 ~~

<title>nginx.dujie.com</title> Nginx 2502 ~~
<title>nginx.dujie.com</title> Nginx 2502 ~~
<title>nginx.dujie.com</title> Nginx 2601 ~~
<title>nginx.dujie.com</title> Nginx 2501 ~~
<title>nginx.dujie.com</title> Nginx 2502 ~~
<title>nginx.dujie.com</title> Nginx 2501 ~~
<title>nginx.dujie.com</title> Nginx 2502 ~~
<title>nginx.dujie.com</title> Nginx 2501 ~~
<title>nginx.dujie.com</title> Nginx 2501 ~~
<title>nginx.dujie.com</title> Nginx 2501 ~~
<title>nginx.dujie.com</title> Nginx 2502 ~~
<title>nginx.dujie.com</title> Nginx 2501 ~~
<title>nginx.dujie.com</title> Nginx 2601 ~~
<title>nginx.dujie.com</title> Nginx 2601 ~~
<title>nginx.dujie.com</title> Nginx 2601 ~~
<title>nginx.dujie.com</title> Nginx 2501 ~~
<title>nginx.dujie.com</title> Nginx 2501 ~~
<title>nginx.dujie.com</title> Nginx 2502 ~~
fault filter abort
<title>nginx.dujie.com</title> Nginx 2501 ~~
<title>nginx.dujie.com</title> Nginx 2502 ~~
<title>nginx.dujie.com</title> Nginx 2501 ~~
<title>nginx.dujie.com</title> Nginx 2501 ~~
<title>nginx.dujie.com</title> Nginx 2501 ~~
<title>nginx.dujie.com</title> Nginx 2501 ~~
2.6.7.4 查看端点信息

这里也可以看到三个节点已经被 istio 的 endpoint 管理了

[root@k8s-master01 ~]# istioctl  proxy-config endpoint client-78c98df4f6-2x6lk  --cluster "outbound|80||nginx.dujie.com" -n entry 
ENDPOINT               STATUS      OUTLIER CHECK     CLUSTER
10.122.24.139:8091     HEALTHY     OK                outbound|80||nginx.dujie.com
10.122.24.139:8092     HEALTHY     OK                outbound|80||nginx.dujie.com
10.122.24.139:8093     HEALTHY     OK                outbound|80||nginx.dujie.com

三、WorkloadEntry 和 WorkloadGroup

上面已经通过 ServiceEntry 可以实现将服务网格外的应用通过 Istio 服务网格来管理了,而 ServiceEntry 他有一些局限性:

  • 静态配置:端点(IP)变更需要手动更新
  • 无实例管理:无法感知端点健康状态
  • 无身份:难以对端点实施mTLS
  • 不适合VM接入:无法将VM作为网格内服务提供者

痛点总结:ServiceEntry 适合访问外部服务,但不适合将外部工作负载(如VM)作为网格内服务提供者
所以 Istio 提供了 WorkloadEntry 来解决以上 ServiceEntry 无法处理的痛点。

特性 ServiceEntry WorkloadEntry
目标 定义外部服务 注册工作负载实例
层级 服务级别 端点级别
使用场景 访问外部API/DB 将VM纳入网格
关联关系 独立存在 需关联Service
动态性 静态配置 支持动态注册

3.1 WorkloadEntry 定义及资源规范

<font style="color:#DF2A3F;">workloadEntry</font> 是用于标识非 Kubernetes 工作负载的 Istio 资源对象。他可以将虚拟机、物理机或者外部服务等**非容器化工作负载**注册到 Istio 服务网格中的端点上。

  • 将 VM/物理机作为服务端点集成到服务网格
  • 使非容器工作负载能参与服务发现
  • 应用相同的流量管理策略(路由、负载均衡、熔断)
  • 实施一致的安全策略(mTLS、RBAC)
  • 实现统一监控(指标、日志、追踪)

资源规范:

apiVersion: networking.istio.io/v1beta1
kind: WorkloadEntry
metadata:
  name: vm-nginx  # 资源名称
  namespace: prod # 必须与关联Service相同
spec:
  # --- 核心配置 ---
  address: 192.168.1.100  # 工作负载IP(必需)
  labels:                 # 标签用于服务选择(必需)
    app: nginx
    env: prod
    version: v1
  
  # --- 高级配置 ---
  serviceAccount: nginx-sa   # 服务账户(用于mTLS)
  network: "cloud-vpc"       # 网络标识(多网络场景)
  ports:                     # 端口别名映射
    http: 8080
    https: 8443
  locality: us-west1/zone1   # 地理位置(地域感知)
  weight: 1                  # 流量权重(默认1)

字段 必填 说明
<font style="color:rgb(251, 71, 135);">address</font> 工作负载的 IP 地址
<font style="color:rgb(251, 71, 135);">labels</font> 用于服务选择的标签
<font style="color:rgb(251, 71, 135);">serviceAccount</font> 推荐 身份标识(用于 mTLS)
<font style="color:rgb(251, 71, 135);">ports</font> 可选 端口别名映射(如 http:8080)
<font style="color:rgb(251, 71, 135);">network</font> 多网络必需 网络标识(需与网格配置匹配)
<font style="color:rgb(251, 71, 135);">locality</font> 推荐 地域信息(格式:region/zone)
<font style="color:rgb(251, 71, 135);">weight</font> 可选 流量权重(默认1)

3.2 WorkloadGroup 定义及资源规范

WorkloadGroup<font style="color:#DF2A3F;">WorkloadEntry</font>模板和分组机制,用于自动化管理一组相似的非容器工作负载。它定义了工作负载的公共配置,并支持通过 <font style="color:rgb(251, 71, 135);">istioctl</font> 自动配置工作负载。

  • 批量管理:统一配置一组相似工作负载
  • 自动注册:通过 <font style="color:rgb(251, 71, 135);">istioctl</font> 自动生成配置文件
  • 配置标准化:确保工作负载配置一致性
  • 健康检查:定义统一健康检查标准
  • 简化运维:减少手动配置错误

资源规范:

apiVersion: networking.istio.io/v1alpha3
kind: WorkloadGroup
metadata:
  name: nginx-vms  # 工作组名称
  namespace: prod  # 命名空间
spec:
  # --- 公共元数据 ---
  metadata:
    labels:        # 应用到所有工作负载的标签
      app: nginx
      env: prod
    annotations:   # 应用到所有工作负载的注解
      backup: "daily"
  
  # --- WorkloadEntry 模板 ---
  template:
    serviceAccount: nginx-sa
    network: "cloud-vpc"
    ports:
      http: 8080
    locality: us-west1/zone1
  
  # --- 健康检查配置 ---
  probe:
    periodSeconds: 10       # 检查间隔
    initialDelaySeconds: 5  # 初始延迟
    httpGet:                # HTTP检查
      port: 8080
      path: /healthz
    # tcpSocket:            # TCP检查(替代方案)
    #   port: 3306

字段 必填 说明
<font style="color:rgb(251, 71, 135);">metadata.labels</font> 工作负载公共标签
<font style="color:rgb(251, 71, 135);">metadata.annotations</font> 可选 工作负载注解
<font style="color:rgb(251, 71, 135);">template</font> WorkloadEntry 模板配置
<font style="color:rgb(251, 71, 135);">probe</font> 推荐 健康检查配置

3.3 WorkloadEntry 案例

基于上面 ServiceEntry 的 docker-compose 案例,现在创建两个 <font style="color:#DF2A3F;">workloadEntry</font>,客户端请求时首先通过 <font style="color:#DF2A3F;">vituralService</font> 路由到 <font style="color:#DF2A3F;">ServiceEntry</font>,再由 <font style="color:#DF2A3F;">ServiceEntry</font> 通过标签选择器选择 <font style="color:#DF2A3F;">WorkloadEntry</font>,将请求指向 10.122.24.139:8091、8092、8093 端口,最终到达容器内部,架构图如下:

3.3.1 WorkloadEntry 准备

将 Docker 服务注册为 Istio 的端点

apiVersion: networking.istio.io/v1beta1
kind: WorkloadEntry
metadata:
  name: workload-nginx2501
  namespace: entry
  labels:
    version: v1.25
spec:
  address: "10.122.24.139"
  ports:
    http: 8091
  labels:
    app: nginx
    version: v1.25
    instance-id: Nginx2501
---
apiVersion: networking.istio.io/v1beta1
kind: WorkloadEntry
metadata:
  name: workload-nginx2502
  namespace: entry
  labels:
    version: v1.25
spec:
  address: "10.122.24.139"
  ports:
    http: 8092
  labels:
    app: nginx
    version: v1.25
    instance-id: Nginx2502

3.3.2 创建 ServiceEntry

定义逻辑服务<font style="color:rgb(251, 71, 135);">nginx.dujie.com</font>,通过<font style="color:rgb(251, 71, 135);">workloadSelector</font>关联WorkloadEntry:

apiVersion: networking.istio.io/v1beta1
kind: ServiceEntry
metadata:
  name: nginx-external
  namespace: entry
spec:
  hosts:
  - nginx.dujie.com
  ports:
  - number: 80
    name: http
    protocol: HTTP
    targetPort: 8091
  location: MESH_EXTERNAL
  # NONE, STATIC, DNS, DNS_ROUND_ROBIN
  resolution: STATIC
  workloadSelector:  # 这里通过标签选择workloadEntry
    labels:
      app: nginx

3.3.3 创建 DestinationRule

配置服务级别的流量策略

apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: nginx-external
  namespace: entry
spec:
  host: nginx.dujie.com
  trafficPolicy:
    loadBalancer:
      simple: RANDOM   # 随机负载均衡
    connectionPool:  # 连接池设置
      tcp:
        maxConnections: 10000
        connectTimeout: 10ms
        tcpKeepalive:
          time: 7200s
          interval: 75s
      http:
        http2MaxRequests: 1000
        maxRequestsPerConnection: 10
    outlierDetection:  # 熔断设置 
      maxEjectionPercent: 50
      consecutive5xxErrors: 5  # 5次5xx错误触发熔断
      interval: 2m
      baseEjectionTime: 1m
      minHealthPercent: 40

3.3.4 创建 VirtualService

定义路由规则和故障注入:

apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: nginx-external
  namespace: entry
spec:
  hosts:
  - nginx.dujie.com
  http:
  - name: falut-injection
    route:
    - destination:
        host: nginx.dujie.com
    fault:
      delay:
        percentage:
          value: 20
        fixedDelay: 2s
      abort:
        percentage:
          value: 20
        httpStatus: 555

3.3.5 测试验证

查看服务部署情况

[root@k8s-master01 ~]# kubectl -n entry get serviceentry,workloadentry,destinationrule,virtualservice
NAME                                              HOSTS                 LOCATION        RESOLUTION   AGE
serviceentry.networking.istio.io/nginx-external   ["nginx.dujie.com"]   MESH_EXTERNAL   STATIC       165m

NAME                                                   AGE     ADDRESS
workloadentry.networking.istio.io/workload-nginx2501   2m58s   10.122.24.139
workloadentry.networking.istio.io/workload-nginx2502   2m58s   10.122.24.139

NAME                                                 HOST              AGE
destinationrule.networking.istio.io/nginx-external   nginx.dujie.com   165m

NAME                                                GATEWAYS   HOSTS                 AGE
virtualservice.networking.istio.io/nginx-external              ["nginx.dujie.com"]   165m
3.3.5.1 测试基础连通性
root@client-78c98df4f6-2x6lk /# while true; do CONTENT=$(curl -s  nginx.dujie.com); echo $CONTENT; sleep 0.$RANDOM; done
<title>nginx.dujie.com</title> Nginx 2501 ~~
<title>nginx.dujie.com</title> Nginx 2502 ~~
<title>nginx.dujie.com</title> Nginx 2502 ~~
<title>nginx.dujie.com</title> Nginx 2501 ~~
<title>nginx.dujie.com</title> Nginx 2502 ~~
<title>nginx.dujie.com</title> Nginx 2501 ~~
<title>nginx.dujie.com</title> Nginx 2501 ~~
<title>nginx.dujie.com</title> Nginx 2502 ~~
<title>nginx.dujie.com</title> Nginx 2501 ~~
<title>nginx.dujie.com</title> Nginx 2501 ~~
<title>nginx.dujie.com</title> Nginx 2502 ~~
<title>nginx.dujie.com</title> Nginx 2501 ~~
  1. 请求成功返回 200 OK
  2. 响应内容包含正确的 Nginx 版本信息
  3. 流量在 8091 和 8092 之间轮询
3.3.5.2 故障注入测试
[root@k8s-master01 ~]# kubectl exec -it  -n entry client-78c98df4f6-2x6lk  bash 
root@client-78c98df4f6-2x6lk /# for i in {1..20}; do   echo -n "Request $i: ";   curl -s -o /dev/null -w "%{http_code} %{time_total}s\n"   -H "Host: nginx.dujie.com"   http://nginx.dujie.com;   sleep 0.5; done
Request 1: 555 0.000795s
Request 2: 200 0.001916s
Request 3: 200 2.002204s
Request 4: 200 0.001498s
Request 5: 200 0.001286s
Request 6: 200 0.001315s
Request 7: 200 0.001337s
Request 8: 200 0.001338s
Request 9: 200 2.001179s
Request 10: 555 0.000843s
Request 11: 200 0.001459s
Request 12: 200 0.001397s
Request 13: 200 0.001349s
Request 14: 200 0.001397s
Request 15: 555 0.000790s
Request 16: 200 0.001291s
Request 17: 200 2.001349s
Request 18: 200 0.001508s
Request 19: 200 0.001303s
Request 20: 200 0.001340s
  1. 约 20% 请求响应时间 >2 秒
  2. 约 20% 请求返回 555 状态码
  3. 60% 请求正常响应

3.4 WorkloadEntry 案例 2

基于上面的案例,可以增加一个 WorkloadEntry 作为金丝雀版本

3.4.1 配置 WorloadEntry

apiVersion: networking.istio.io/v1beta1
kind: WorkloadEntry
metadata:
  name: workload-nginx2501
  namespace: entry
spec:
  address: "10.122.24.139"
  ports:
    http: 8091
  labels:
    app: nginx
    version: "v1.25"
    instance-id: Nginx2501
---
apiVersion: networking.istio.io/v1beta1
kind: WorkloadEntry
metadata:
  name: workload-nginx2502
  namespace: entry
spec:
  address: "10.122.24.139"
  ports:
    http: 8092
  labels:
    app: nginx
    version: "v1.25"
    instance-id: Nginx2502
---
apiVersion: networking.istio.io/v1beta1
kind: WorkloadEntry
metadata:
  name: workload-nginx2601
  namespace: entry
spec:
  address: "10.122.24.139"
  ports:
    http: 8093
  labels:
    app: nginx
    version: "v1.26"
    instance-id: Nginx2601

3.4.2 配置 serviceEntry

apiVersion: networking.istio.io/v1beta1
kind: ServiceEntry
metadata:
  name: nginx
  namespace: entry
spec:
  hosts:
  - nginx.dujie.com
  ports:
  - number: 80
    name: http
    protocol: HTTP
  location: MESH_EXTERNAL
  resolution: STATIC
  workloadSelector:
    labels:
      app: nginx

3.4.3 配置 destinationRule

这里配置了两个子集,一个是版本 v1.25 另一个是 v1.26

apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: nginx-external
  namespace: entry
spec:
  host: nginx.dujie.com
  trafficPolicy:
    loadBalancer:
      simple: RANDOM
    connectionPool:
      tcp:
        maxConnections: 10000
        connectTimeout: 10ms
        tcpKeepalive:
          time: 7200s
          interval: 75s
      http:
        http2MaxRequests: 1000
        maxRequestsPerConnection: 10
    outlierDetection:
      maxEjectionPercent: 50
      consecutive5xxErrors: 5
      interval: 2m
      baseEjectionTime: 1m
      minHealthPercent: 40
  subsets:
  - name: v25
    labels:
      version: "v1.25"
  - name: v26
    labels:
      version: "v1.26"

3.4.4 修改 VirtualService

这里可以基于权重或标头值进行路由分配,可自行选择

基于权重:

apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: nginx-external
  namespace: entry
spec:
  hosts:
  - nginx.dujie.com
  http:
  - name: default
    route:
    - destination:
        host: nginx.dujie.com
        subset: v26
      weight: 5
    - destination:
        host: nginx.dujie.com
        subset: v25
      weight: 95

基于标头

apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: nginx-external
  namespace: entry
spec:
  hosts:
  - nginx.dujie.com
  http:
  - name: falut-injection
    match:
    - headers:
        x-canary:
          exact: "true"
    route:
    - destination:
        host: nginx.dujie.com
        subset: v26
    fault:
      delay:
        percentage:
          value: 5
        fixedDelay: 2s
  - name: default
    route:
    - destination:
        host: nginx.dujie.com
        subset: v25
    fault:
      abort:
        percentage:
          value: 5
        httpStatus: 555

3.4.5 测试

3.4.5.1 测试基础连通性

可以看到流量会在 v1.25 版本进行负载均衡

root@client-78c98df4f6-2x6lk /# while true; do CONTENT=$(curl -s  nginx.dujie.com); echo $CONTENT; sleep 0.$RANDOM; done
<title>nginx.dujie.com</title> Nginx 2501 ~~
<title>nginx.dujie.com</title> Nginx 2501 ~~
<title>nginx.dujie.com</title> Nginx 2502 ~~
<title>nginx.dujie.com</title> Nginx 2502 ~~
<title>nginx.dujie.com</title> Nginx 2501 ~~
<title>nginx.dujie.com</title> Nginx 2501 ~~
<title>nginx.dujie.com</title> Nginx 2501 ~~
<title>nginx.dujie.com</title> Nginx 2501 ~~
<title>nginx.dujie.com</title> Nginx 2501 ~~
<title>nginx.dujie.com</title> Nginx 2502 ~~
<title>nginx.dujie.com</title> Nginx 2501 ~~
<title>nginx.dujie.com</title> Nginx 2502 ~~
<title>nginx.dujie.com</title> Nginx 2502 ~~
<title>nginx.dujie.com</title> Nginx 2502 ~~
<title>nginx.dujie.com</title> Nginx 2501 ~~
<title>nginx.dujie.com</title> Nginx 2501 ~~

3.4.5.2 验证金丝雀发布

可以看到在请求头中添加 x-canary: true 之后流量就会全部走向 v1.26 版本了

root@client-78c98df4f6-2x6lk /# while true; do CONTENT=$(curl -s -H "x-canary: true" nginx.dujie.com); echo $CONTENT; sleep 0.$RANDOM; done
<title>nginx.dujie.com</title> Nginx 2601 ~~
<title>nginx.dujie.com</title> Nginx 2601 ~~
<title>nginx.dujie.com</title> Nginx 2601 ~~
<title>nginx.dujie.com</title> Nginx 2601 ~~
<title>nginx.dujie.com</title> Nginx 2601 ~~
<title>nginx.dujie.com</title> Nginx 2601 ~~
<title>nginx.dujie.com</title> Nginx 2601 ~~
<title>nginx.dujie.com</title> Nginx 2601 ~~
<title>nginx.dujie.com</title> Nginx 2601 ~~
<title>nginx.dujie.com</title> Nginx 2601 ~~
<title>nginx.dujie.com</title> Nginx 2601 ~~

四、Egress Gateway

4.1 EgressGateway 介绍

Egress Gateway 是 Istio 中专门管理出站流量的网关组件,作为集群内服务访问外部服务的统一出口。其核心作用类似于企业网络的防火墙出口,所有内部服务访问互联网必须经过此节点。他并不是必须的配置,因为 Istio 内部每个业务 Pod 流量本身就可以直接出去,但有些中大型公司对出口网关有着非常强的合规要求,比如"业务 Pod 不能随便访问互联网",风险不可控等等,这个时候就可以使用<font style="color:#DF2A3F;"> egress gateway</font> 来强制要求所有流量都必须经过它才能出去。

4.2 EgressGateway 使用场景

4.2.1 合规与安全隔离

很多大中型企业(金融/政企/跨云)出网有非常强的合规要求。“业务 pod 随便访问互联网” :风险不可控
强制所有对外访问都经由 egress gateway,可实现:

  • 统一加密协议(如全链路 mTLS/TLS)
  • 配合防火墙/nat/dlp做敏感数据防泄漏、外联控制
  • 精确控制哪些pod、哪些服务可以访问哪些外部目标

4.2.2 审计与观测

出口监控与日志,可获得:

  • 谁在访问外部什么
  • 访问频率、性能、异常流量实时分析
  • 留痕追责、自动告警、流量快照

4.2.3 细粒度流量治理

通过 <font style="color:#DF2A3F;">egress gateway </font>可以对所有出口流量实施灰度、熔断、速率限制、出口流量转发、with/without proxy、异常检测等治理措施。

  • 地理路由
  • 协议转换
  • select 出国出口等

4.2.4 池化出口IP,对VPC/防火墙策略友好

让流量统一出几个出口IP,外部方只要信任少数网关IP就行,减少维护量和受信任面。

4.2.5 支持数据脱敏、协议安全转换

出口网关可以完成加解密、协议规范化处理,把敏感内网数据做脱敏出网等“最后一道关”。

4.3 EgressGateway 安装

因为我这里 istio 是基于 demo 配置安装的,默认会自动安装 egressGateway,而如果使用其他配置安装则需要手动安装

手动安装操作可以查看官网https://istio.io/latest/zh/docs/setup/additional-setup/customize-installation/

需要再 IstioOperator 资源的 components 中指定 egressGateways,将他的 <font style="color:#DF2A3F;">enabled</font> 设置为 true 即可

4.4 EgressGateway 案例

通过WorkloadEntry将非Kubernetes管理的Nginx实例接入Istio网格,并通过Egress Gateway控制出口流量。

4.4.1 workloadEntry 准备

apiVersion: networking.istio.io/v1beta1
kind: WorkloadEntry
metadata:
  name: workload-nginx2501
  namespace: entry
spec:
  address: "10.122.24.139"
  ports:
    http: 8091
  labels:
    app: nginx
    version: "v1.25"
    instance-id: Nginx2501
---
apiVersion: networking.istio.io/v1beta1
kind: WorkloadEntry
metadata:
  name: workload-nginx2502
  namespace: entry
spec:
  address: "10.122.24.139"
  ports:
    http: 8092
  labels:
    app: nginx
    version: "v1.25"
    instance-id: Nginx2502
---
apiVersion: networking.istio.io/v1beta1
kind: WorkloadEntry
metadata:
  name: workload-nginx2601
  namespace: entry
spec:
  address: "10.122.24.139"
  ports:
    http: 8093
  labels:
    app: nginx
    version: "v1.26"
    instance-id: Nginx2601

4.4.2 serviceEntry 准备

apiVersion: networking.istio.io/v1beta1
kind: ServiceEntry
metadata:
  name: nginx
  namespace: entry
spec:
  hosts:
  - nginx.dujie.com
  ports:
  - number: 80
    name: http
    protocol: HTTP
  location: MESH_EXTERNAL
  resolution: STATIC
  workloadSelector:
    labels:
      app: nginx

4.4.3 destinationRule 准备

apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: nginx-external
  namespace: entry
spec:
  host: nginx.dujie.com
  trafficPolicy:
    loadBalancer:
      simple: RANDOM
    connectionPool:
      tcp:
        maxConnections: 10000
        connectTimeout: 10ms
        tcpKeepalive:
          time: 7200s
          interval: 75s
      http:
        http2MaxRequests: 1000
        maxRequestsPerConnection: 10
    outlierDetection:
      maxEjectionPercent: 50
      consecutive5xxErrors: 5
      interval: 2m
      baseEjectionTime: 1m
      minHealthPercent: 40
  subsets:
  - name: v25
    labels:
      version: "v1.25"
  - name: v26
    labels:
      version: "v1.26"

4.4.4 egressGateway 准备

  • 在80端口监听HTTP流量
  • 匹配所有主机(<font style="color:rgb(251, 71, 135);">"*"</font>)
apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
  name: egress-gateway
  namespace: entry
spec:
  selector:
    app: istio-egressgateway
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - "*"

4.4.5 VirtualService 准备

apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: nginx-external
  namespace: entry
spec:
  hosts:
  - nginx.dujie.com
  gateways:
  - egress-gateway
  - mesh
  http:
  - match:
    - gateways:
      - mesh
    route:
    - destination:
        host: istio-egressgateway.istio-system.svc.cluster.local
  - match:
    - gateways:
      - egress-gateway
    route:
    - destination:
        host: nginx.dujie.com
        subset: v26
      weight: 5
    - destination:
        host: nginx.dujie.com
        subset: v25
      weight: 95

4.4.6 测试验证

[root@k8s-master01 ~]# istioctl proxy-config endpoints -n entry client-78c98df4f6-2x6lk  --cluster 'outbound|80||nginx.dujie.com' 
ENDPOINT               STATUS      OUTLIER CHECK     CLUSTER
10.122.24.139:8091     HEALTHY     OK                outbound|80||nginx.dujie.com
10.122.24.139:8092     HEALTHY     OK                outbound|80||nginx.dujie.com
10.122.24.139:8093     HEALTHY     OK                outbound|80||nginx.dujie.com

测试流量分配,v1.26 版本出现的概率在 5%

root@client-78c98df4f6-2x6lk /# while true; do CONTENT=$(curl -s  nginx.dujie.com); echo $CONTENT; sleep 0.$RANDOM; done
<title>nginx.dujie.com</title> Nginx 2501 ~~
<title>nginx.dujie.com</title> Nginx 2502 ~~
<title>nginx.dujie.com</title> Nginx 2502 ~~
<title>nginx.dujie.com</title> Nginx 2502 ~~
<title>nginx.dujie.com</title> Nginx 2501 ~~
<title>nginx.dujie.com</title> Nginx 2502 ~~
<title>nginx.dujie.com</title> Nginx 2501 ~~
<title>nginx.dujie.com</title> Nginx 2501 ~~
<title>nginx.dujie.com</title> Nginx 2501 ~~
<title>nginx.dujie.com</title> Nginx 2502 ~~
<title>nginx.dujie.com</title> Nginx 2502 ~~
<title>nginx.dujie.com</title> Nginx 2501 ~~
<title>nginx.dujie.com</title> Nginx 2502 ~~
<title>nginx.dujie.com</title> Nginx 2502 ~~

查看 egressGateway 日志,可以发现 istio 中所有的出口流量都先经过了 egressGateway 了

查看 kiali


网站公告

今日签到

点亮在社区的每一天
去签到