网络拓扑
本文档描述 TFRS Operator 管理的网络架构,包括流量入口、路由机制、mTLS 和租户隔离。
流量入口链路
外部请求经过以下链路到达后端服务:
客户端
│
▼
Cloud LB (CLB / NodePort) ← TFRCluster.spec.clusterType 决定
│
▼
Istio Ingress Gateway (Port 80) ← istio-ingress namespace
│
▼
Gateway CR (default-gateway) ← 集群统一网关
│
▼
VirtualService (cluster-routes) ← 统一路由入口
│
▼
EnvoyFilter (Cookie/QP → Header) ← 提取租户标识
│
▼
EnvoyFilter (Lua Dynamic Routing) ← 动态路由到目标服务
│
▼
Backend Service ← 租户命名空间内的服务
Gateway 架构
TFRCluster 创建一个共享的 Istio Gateway,所有租户流量通过此网关进入集群。
| 配置项 | 默认值 | 说明 |
|---|---|---|
| Gateway 名称 | default-gateway | 可通过 spec.ingress.gatewayRef 覆盖 |
| Gateway 命名空间 | istio-ingress | Istio Ingress Gateway 所在命名空间 |
| 监听端口 | 80 (HTTP) | TLS 由上游 CLB 终结 |
| Hosts | ["*"] | 可通过 spec.ingress.hosts 限制 |
集群类型适配
| 集群类型 | 入口方式 | 特殊配置 |
|---|---|---|
tke | CLB (LoadBalancer) | 通过 tkeClusterConfig.clbId 绑定腾讯云 CLB |
kind | NodePort | 使用 nodePortConfig 指定 HTTP/HTTPS 端口映射 |
docker-desktop | NodePort | 同 Kind,适配 Docker Desktop 网络 |
Cookie / QueryParam 路由机制
TFRCluster 部署两个 EnvoyFilter 实现基于 Cookie 和 QueryParam 的动态路由。
第一步:租户标识提取(EnvoyFilter envoy-filter-cookie)
从请求 Cookie 或 URL QueryParam 中提取租户标识,转换为 HTTP Header:
Cookie 来源:
| Cookie 名称 | 映射 Header | 默认 Cookie Key | 说明 |
|---|---|---|---|
tfNamespace | X-TF-Namespace | 可通过 spec.routing.cookieNames 配置 | 目标租户命名空间 |
tfRobotId | X-TF-RobotId | 可通过 spec.routing.cookieNames 配置 | 目标机器人实例 ID |
QueryParam 来源:
| QueryParam | 映射 Header | 说明 |
|---|---|---|
namespace | X-TF-Namespace | 目标租户命名空间 |
rid | X-TF-RobotId | 目标机器人实例 ID |
优先级: 当 Cookie 和 QueryParam 同时存在时,QueryParam 优先。例如
/v1/login?namespace=tenant-a&rid=robot-1会覆盖 Cookie 中的对应值。
第二步:Lua 动态路由(EnvoyFilter lua-dynamic-routing)
根据请求路径和 Header 动态选择后端服务:
| 请求路径 | 所需 Header | 路由目标 |
|---|---|---|
/v1/login | X-TF-Namespace | tfrobot-http.{namespace}:80(无论是否有 rid) |
/socket.io/ | X-TF-Namespace + X-TF-RobotId | tf-robot-{robotId}.{namespace}:8080 |
/socket.io/(缺少 rid) | X-TF-Namespace | 返回 400 JSON 错误响应 |
| 其他路径 | X-TF-Namespace | tfrobot-http.{namespace}:80 |
| 缺少路由信息 | — | 返回 401 JSON 错误响应 |
VirtualService 请求头处理
集群级 VirtualService cluster-routes 还执行以下操作:
- X-Real-IP 注入:将客户端真实 IP 写入
X-Real-IPHeader - X-Forwarded-Host 注入:保留原始请求 Host
- Underscore Header 支持:通过 Istio mesh config 允许包含下划线的 Header 名称
租户网络隔离
每个 TFRTenant 命名空间通过以下 Istio 策略实现网络隔离:
PeerAuthentication(mTLS)
apiVersion: security.istio.io/v1
kind: PeerAuthentication
metadata:
name: default
namespace: {tenant-namespace}
spec:
mtls:
mode: STRICT
所有命名空间内的服务通信强制使用 mTLS,防止未加密流量。
AuthorizationPolicy
限制仅允许以下来源的流量进入租户命名空间:
| 来源 | 说明 |
|---|---|
istio-ingress | Ingress Gateway 转发的外部流量 |
| 本命名空间 | 命名空间内服务间通信 |
spec.extraAllowedNamespaces | 额外允许的命名空间(如 Prometheus 所在命名空间) |
DestinationRule
配置客户端 mTLS 模式,确保命名空间内所有服务间通信加密:
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: default
namespace: {tenant-namespace}
spec:
host: "*.{tenant-namespace}.svc.cluster.local"
trafficPolicy:
tls:
mode: ISTIO_MUTUAL
服务 DNS 模式
租户命名空间内的关键服务遵循以下 DNS 命名模式:
| 服务 | DNS 模式 | 端口 | 说明 |
|---|---|---|---|
| TFRobot API | tfrobot-http.{ns}.svc.cluster.local | 80 | API 服务统一入口 |
| TFRobot 实例 | tf-robot-{robotId}.{ns}.svc.cluster.local | 8080 | 单个机器人实例(Socket.IO) |
| PostgreSQL | {ns}-pg-rw.{ns}.svc.cluster.local | 5432 | CNPG 读写端点 |
| Redis | redis.{ns}.svc.cluster.local | 6379 | Redis 缓存 |
| MinIO | minio.{ns}.svc.cluster.local | 9000 | 对象存储 API |
| RabbitMQ | rabbitmq.{ns}.svc.cluster.local | 5672 | AMQP 消息队列 |
| Jaeger | jaeger-collector.{ns}.svc.cluster.local | 4317 | OTLP gRPC 端点 |
| Grafana | grafana.{ns}.svc.cluster.local | 3000 | 监控仪表盘 |
网络拓扑总览
graph TB
subgraph External
Client[客户端]
CLB[Cloud LB]
end
subgraph istio-ingress
IGW[Istio Ingress Gateway]
GW[Gateway CR]
VS[VirtualService]
EFC[EnvoyFilter Cookie]
EFL[EnvoyFilter Lua]
end
subgraph tenant-ns-1[租户命名空间 A]
PA1[PeerAuthentication STRICT]
AP1[AuthorizationPolicy]
API1[TFRobot API :80]
BOT1[tf-robot-1 :8080]
PG1[PostgreSQL :5432]
RD1[Redis :6379]
MN1[MinIO :9000]
RQ1[RabbitMQ :5672]
end
subgraph tenant-ns-2[租户命名空间 B]
PA2[PeerAuthentication STRICT]
AP2[AuthorizationPolicy]
API2[TFRobot API :80]
BOT2[tf-robot-2 :8080]
PG2[PostgreSQL :5432]
end
Client --> CLB --> IGW
IGW --> GW --> VS
VS --> EFC --> EFL
EFL -->|X-TF-Namespace=A| API1
EFL -->|X-TF-Namespace=A, X-TF-RobotId=1| BOT1
EFL -->|X-TF-Namespace=B| API2
API1 -.->|mTLS| PG1
API1 -.->|mTLS| RD1
API1 -.->|mTLS| MN1
API1 -.->|mTLS| RQ1