因语雀与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 流量:仅通过端口匹配
- HTTP 流量:匹配
示例:
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.com
和nginx
解析到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 ~~
- 请求成功返回 200 OK
- 响应内容包含正确的 Nginx 版本信息
- 流量在 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
- 约 20% 请求响应时间 >2 秒
- 约 20% 请求返回 555 状态码
- 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