当前位置: 首页 > news >正文

Gateway API 实战:在单节点 Kubernetes 上使用 Envoy Gateway 跑通 HTTPRoute、Header 匹配和金丝雀分流

一、前言

本文会在一个单节点 Kubernetes 测试环境中安装 Envoy Gateway,然后通过 Gateway API 完成几组 HTTP 路由实验:

1. 安装 Envoy Gateway 2. 创建 GatewayClass 3. 部署 app-v1 / app-v2 两个测试服务 4. 创建 Gateway 和 HTTPRoute 5. 验证基础路由:/ -> app-v1 6. 验证 Path 路由:/api -> app-v1,/web -> app-v2 7. 验证 Header 匹配:带 x-env: canary 的请求 -> app-v2 8. 验证 backendRefs.weight 金丝雀分流:app-v1 90%,app-v2 10%

二、实验环境与整体链路

本文实验环境是一个单节点 Kubernetes 测试集群。实验中使用的主要资源如下:

Gateway Controller:Envoy Gateway Envoy Gateway 安装命名空间:envoy-gateway-system 测试业务命名空间:gateway-demo GatewayClass:eg Gateway:app-gateway 测试域名:app.example.local 后端服务: - app-v1 - app-v2

由于本文是单节点 Kubernetes 测试环境,没有云厂商 LoadBalancer,也没有安装 MetalLB,所以 Envoy Gateway 创建出来的LoadBalancer类型 Service 的EXTERNAL-IP会是<pending>

因此本文使用kubectl port-forward的方式在本机验证 Gateway API 的转发链路。

最终请求链路如下:

curl -> kubectl port-forward -> Envoy Gateway 数据面 Service -> Envoy Proxy 数据面 Pod -> Gateway -> HTTPRoute -> Service -> Pod

三、安装 Envoy Gateway

3.1 拉取 Helm Chart

首先拉取 Envoy Gateway 的 Helm Chart:

helm pull oci://docker.io/envoyproxy/gateway-helm --version v1.8.1

如果网络可以正常访问 Docker Hub,这一步会在当前目录生成类似下面的文件:

gateway-helm-v1.8.1.tgz

如果测试机无法访问 Docker Hub,也可以在能访问外网的机器上下载后再上传到测试机。


3.2 使用 Helm 安装 Envoy Gateway

执行安装命令:

helm install envoygateway ./gateway-helm-v1.8.1.tgz \ -n envoy-gateway-system \ --create-namespace

这里需要注意两个名字:

envoygateway 是 Helm release 名称。 envoy-gateway-system 是 Envoy Gateway 安装所在的命名空间。

Helm release 名称和后面创建的 GatewayClass 名称不是一回事。

也就是说,这里的envoygateway只是 Helm 管理这次安装的 release 名字;后面我们创建的GatewayClass eg是 Gateway API 里的资源名字。


3.3 验证 Envoy Gateway Pod

执行:

kubectl -n envoy-gateway-system get pod

实验输出如下:

NAME READY STATUS RESTARTS AGE envoy-gateway-6f954cd9dd-49zm7 1/1 Running 0 26s envoygateway-gateway-helm-certgen-z9xzq 0/1 Completed 0 30s

这里有两个对象需要理解:

envoy-gateway-xxx Envoy Gateway Controller,状态 Running,说明控制平面正常运行。 envoygateway-gateway-helm-certgen-xxx Helm 安装过程中用于生成证书的 Job,Completed 是正常状态。

只要envoy-gateway-xxx1/1 Running,说明 Envoy Gateway 控制平面已经正常起来了。


3.4 验证 Gateway API CRD

执行:

kubectl get crd | grep gateway.networking.k8s.io

实验输出如下:

backendtlspolicies.gateway.networking.k8s.io gatewayclasses.gateway.networking.k8s.io gateways.gateway.networking.k8s.io grpcroutes.gateway.networking.k8s.io httproutes.gateway.networking.k8s.io listenersets.gateway.networking.k8s.io referencegrants.gateway.networking.k8s.io tcproutes.gateway.networking.k8s.io tlsroutes.gateway.networking.k8s.io udproutes.gateway.networking.k8s.io

这说明 Gateway API 相关 CRD 已经安装到集群中。

对于 Gateway API 来说,CRD 非常关键。只有 CRD 存在,Kubernetes 才认识下面这些资源:

GatewayClass Gateway HTTPRoute ReferenceGrant GRPCRoute TCPRoute TLSRoute UDPRoute

本文主要使用这三个核心资源:

GatewayClass Gateway HTTPRoute

四、创建 GatewayClass

4.1 GatewayClass 的作用

GatewayClass是集群级资源,用来表示一类 Gateway 由哪个 Gateway Controller 处理。

可以这样理解:

GatewayClass = 选择使用哪种 Gateway Controller

本文使用 Envoy Gateway,所以 GatewayClass 的controllerName写成:

gateway.envoyproxy.io/gatewayclass-controller

这是 Envoy Gateway 对应的 controllerName。


4.2 创建 GatewayClass YAML

创建文件:

cat > 00-gatewayclass.yaml <<'EOF' apiVersion: gateway.networking.k8s.io/v1 kind: GatewayClass metadata: name: eg spec: controllerName: gateway.envoyproxy.io/gatewayclass-controller EOF

应用:

kubectl apply -f 00-gatewayclass.yaml

检查:

kubectl get gatewayclass

实验输出:

NAME CONTROLLER ACCEPTED AGE eg gateway.envoyproxy.io/gatewayclass-controller True 5s

这里重点看:

ACCEPTED=True

这说明 Envoy Gateway Controller 已经接受了这个 GatewayClass。后续 Gateway 里写:

gatewayClassName: eg

就表示这个 Gateway 交给 Envoy Gateway 处理。


五、部署 app-v1 / app-v2 测试服务

为了隔离实验资源,先创建一个测试命名空间。后续 Deployment、Service、Gateway、HTTPRoute 都放在这个命名空间中。

kubectl create ns gateway-demo

为了测试不同路由规则,这里部署两个简单 HTTP 服务:

app-v1 返回:hello from app-v1 app-v2 返回:hello from app-v2

5.1 创建测试应用 YAML

创建文件:

cat > 01-apps.yaml <<'EOF' apiVersion: apps/v1 kind: Deployment metadata: name: app-v1 namespace: gateway-demo spec: replicas: 1 selector: matchLabels: app: app-v1 template: metadata: labels: app: app-v1 spec: tolerations: - key: "node-role.kubernetes.io/control-plane" operator: "Exists" effect: "NoSchedule" - key: "node-role.kubernetes.io/master" operator: "Exists" effect: "NoSchedule" containers: - name: app image: hashicorp/http-echo:1.0 args: - "-text=hello from app-v1" ports: - containerPort: 5678 --- apiVersion: v1 kind: Service metadata: name: app-v1 namespace: gateway-demo spec: selector: app: app-v1 ports: - name: http port: 8080 targetPort: 5678 --- apiVersion: apps/v1 kind: Deployment metadata: name: app-v2 namespace: gateway-demo spec: replicas: 1 selector: matchLabels: app: app-v2 template: metadata: labels: app: app-v2 spec: tolerations: - key: "node-role.kubernetes.io/control-plane" operator: "Exists" effect: "NoSchedule" - key: "node-role.kubernetes.io/master" operator: "Exists" effect: "NoSchedule" containers: - name: app image: hashicorp/http-echo:1.0 args: - "-text=hello from app-v2" ports: - containerPort: 5678 --- apiVersion: v1 kind: Service metadata: name: app-v2 namespace: gateway-demo spec: selector: app: app-v2 ports: - name: http port: 8080 targetPort: 5678 EOF

5.2 应用测试服务

执行:

kubectl apply -f 01-apps.yaml

检查 Deployment、Pod、Service:

kubectl -n gateway-demo get deploy,pod,svc

实验输出:

NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/app-v1 1/1 1 1 15s deployment.apps/app-v2 1/1 1 1 15s NAME READY STATUS RESTARTS AGE pod/app-v1-6dbdb7dc7-947vw 1/1 Running 0 15s pod/app-v2-6f5444c457-7l25x 1/1 Running 0 15s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/app-v1 ClusterIP 10.103.180.185 <none> 8080/TCP 15s service/app-v2 ClusterIP 10.96.61.62 <none> 8080/TCP 15s

继续检查后端端点:

kubectl -n gateway-demo get endpoints

实验输出:

Warning: v1 Endpoints is deprecated in v1.33+; use discovery.k8s.io/v1 EndpointSlice NAME ENDPOINTS AGE app-v1 10.244.0.252:5678 15s app-v2 10.244.0.253:5678 15s

六、创建 Gateway

6.1 Gateway 的作用

Gateway用来描述具体的入口配置,例如:

使用哪个 GatewayClass 监听哪个端口 使用什么协议 匹配哪个 hostname 允许哪些 Route 绑定

本文创建一个名为app-gateway的 Gateway,监听 HTTP 80 端口,并匹配app.example.local


6.2 创建 Gateway YAML

创建文件:

cat > 02-gateway.yaml <<'EOF' apiVersion: gateway.networking.k8s.io/v1 kind: Gateway metadata: name: app-gateway namespace: gateway-demo spec: gatewayClassName: eg listeners: - name: http port: 80 protocol: HTTP hostname: "app.example.local" allowedRoutes: namespaces: from: Same EOF

应用:

kubectl apply -f 02-gateway.yaml

6.3 Gateway 字段解释

gatewayClassName: eg

表示这个 Gateway 使用前面创建的 GatewayClasseg

也就是交给 Envoy Gateway Controller 处理。

listeners: - name: http

定义一个 listener,名字叫http。后面的 HTTPRoute 可以通过:

sectionName: http

精确绑定到这个 listener。

port: 80 protocol: HTTP

表示这个 listener 处理 HTTP 80 端口流量。

hostname: "app.example.local"

表示这个 listener 只匹配 Host 为app.example.local的请求。

allowedRoutes: namespaces: from: Same

表示只允许和 Gateway 同 namespace 的 Route 绑定。因为这个 Gateway 在gateway-demo命名空间,所以只有gateway-demo命名空间里的 HTTPRoute 可以绑定到它。


6.4 检查 Gateway

执行:

kubectl -n gateway-demo get gateway

实验输出:

NAME CLASS ADDRESS PROGRAMMED AGE app-gateway eg False 2m1s

这里可以看到:

ADDRESS 为空 PROGRAMMED=False

这不一定表示 Gateway YAML 写错。继续查看详情:

kubectl -n gateway-demo describe gateway app-gateway

关键状态如下:

Reason: Accepted Status: True Type: Accepted Reason: AddressNotAssigned Status: False Type: Programmed

这说明:

Gateway 已经被 Envoy Gateway 接受。 但是 Gateway 没有分配到外部地址。

由于本文是单节点 Kubernetes,没有云厂商 LoadBalancer,也没有 MetalLB,所以 Envoy Gateway 创建出来的 LoadBalancer Service 无法获得 EXTERNAL-IP。

因此这里的Programmed=False是因为:

Reason: AddressNotAssigned Message: No addresses have been assigned to the Gateway

这不是 Gateway YAML 错误。再看 listener 状态:

Listeners: Attached Routes: 0 Programmed=True Accepted=True ResolvedRefs=True

这说明:

Gateway 的 listener 配置已经成功翻译并发送到数据面。 只是当前还没有 HTTPRoute 绑定到这个 listener。

七、创建基础 HTTPRoute:/ 转发到 app-v1

7.1 HTTPRoute 的作用

HTTPRoute用来描述 HTTP 请求如何匹配,以及匹配后转发到哪个后端 Service。

可以简单理解为:

Gateway 负责入口。 HTTPRoute 负责路由规则。 Service 负责后端访问入口。 Pod 才是真正处理请求的应用实例。

本文先创建一个最简单的 HTTPRoute:

app.example.local/ -> app-v1:8080

7.2 创建基础 HTTPRoute YAML

创建文件:

cat > 03-route-basic.yaml <<'EOF' apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: app-route-basic namespace: gateway-demo spec: parentRefs: - name: app-gateway sectionName: http hostnames: - "app.example.local" rules: - matches: - path: type: PathPrefix value: / backendRefs: - name: app-v1 port: 8080 EOF

应用:

kubectl apply -f 03-route-basic.yaml

7.3 HTTPRoute 字段解释

parentRefs: - name: app-gateway sectionName: http

表示这条 HTTPRoute 绑定到:

Gateway app-gateway 的 http listener

这里的sectionName: http对应 Gateway 中 listener 的名字:

listeners: - name: http
hostnames: - "app.example.local"

表示这条 HTTPRoute 只匹配 Host 为app.example.local的请求。

matches: - path: type: PathPrefix value: /

表示匹配所有以/开头的路径。

backendRefs: - name: app-v1 port: 8080

表示匹配成功后,转发到app-v1这个 Service 的 8080 端口。


7.4 检查 HTTPRoute

执行:

kubectl -n gateway-demo get httproute

实验输出:

NAME HOSTNAMES AGE app-route-basic ["app.example.local"] 24s

继续查看详情:

kubectl -n gateway-demo describe httproute app-route-basic

重点看:

Reason: Accepted Status: True Type: Accepted Reason: ResolvedRefs Status: True Type: ResolvedRefs

这说明:

Accepted=True HTTPRoute 已经成功绑定到 Gateway。 ResolvedRefs=True HTTPRoute 引用的后端 Service 已经成功解析。

也就是说,app-route-basic已经成功绑定到app-gateway,并且能够找到后端app-v1:8080


7.5 查看 Gateway 上绑定的 Route 数量

执行:

kubectl -n gateway-demo describe gateway app-gateway | grep Attached

实验输出:

Attached Routes: 1

说明app-route-basic已经成功挂到app-gatewayhttplistener 上。


八、理解 Envoy Gateway 控制面和数据面

创建 Gateway 之后,再查看 Envoy Gateway 命名空间中的 Pod:

kubectl -n envoy-gateway-system get pod

实验输出:

NAME READY STATUS RESTARTS AGE envoy-gateway-6f954cd9dd-49zm7 1/1 Running 0 68m envoy-gateway-demo-app-gateway-c2617110-5df694555c-smmfb 2/2 Running 0 83s

这里很多初学者容易迷惑:为什么多了一个envoy-gateway-demo-app-gateway开头的 Pod?

这不是重复安装了 Envoy Gateway,而是控制面数据面的区别。


8.1envoy-gateway-xxx是控制面

envoy-gateway-6f954cd9dd-49zm7

这个 Pod 是 Helm 安装时创建的 Envoy Gateway Controller。它的职责是:

监听 GatewayClass 监听 Gateway 监听 HTTPRoute 监听 Service / EndpointSlice 把 Gateway API 资源翻译成 Envoy 配置 创建和管理 Envoy 数据面 Deployment / Service

它本身一般不直接承接业务 HTTP 请求。


8.2envoy-gateway-demo-app-gateway-xxx是数据面

envoy-gateway-demo-app-gateway-c2617110-5df694555c-smmfb

这个 Pod 是 Envoy Gateway 根据我们创建的Gateway app-gateway自动创建出来的数据面 Envoy Proxy Pod。可以拆开理解这个名字:

envoy gateway-demo app-gateway c2617110 随机 Pod 后缀

其中:

gateway-demo 是 Gateway 所在 namespace app-gateway 是 Gateway 名字

所以看到这个名字,就可以判断:

这是 gateway-demo 命名空间里的 app-gateway 对应的数据面 Envoy Pod。

真正处理业务 HTTP 请求的是这个数据面 Envoy Pod。


8.3 是否每创建一个 Gateway 都会创建一个新 Pod

默认情况下,Envoy Gateway 通常会为每个 Gateway 创建一套独立的 Envoy Proxy 数据面资源。

也就是说,创建一个 Gateway,Envoy Gateway Controller 监听到它后,默认会创建一套对应的数据面资源,例如:

Deployment Pod Service

不过 Envoy Gateway 也支持合并模式,可以把多个 Gateway 的 listener 合并到同一套 Envoy Proxy fleet 中。本文没有配置合并模式,所以使用的是默认模式。

可以简单记住:

默认模式: 一个 Gateway -> 一套独立 Envoy 数据面 合并模式: 多个 Gateway -> 可以合并到一套 Envoy 数据面

8.4 控制面 Service 和数据面 Service 的区别

执行:

kubectl -n envoy-gateway-system get svc

可以看到类似:

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) envoy-gateway ClusterIP 10.97.106.78 <none> 18000/TCP,18001/TCP,18002/TCP,19001/TCP,9443/TCP envoy-gateway-demo-app-gateway-c2617110 LoadBalancer 10.99.157.94 <pending> 80:31738/TCP

这里也有两个 Service:

envoy-gateway 控制面 Service,给 Envoy Gateway Controller 自己使用。 envoy-gateway-demo-app-gateway-c2617110 数据面 Service,给外部流量进入 Gateway 使用。

业务流量应该打到数据面 Service,而不是控制面 Service。所以后面 port-forward 的对象是:

service/envoy-gateway-demo-app-gateway-c2617110

而不是:

service/envoy-gateway

九、使用 port-forward 验证基础路由

9.1 为什么需要 port-forward

由于本文是单节点 Kubernetes,没有云厂商 LoadBalancer,也没有安装 MetalLB,所以数据面 Service 的EXTERNAL-IP是:

<pending>

这表示外部地址没有分配成功。为了在本机验证 Gateway API 转发链路,可以使用kubectl port-forwardport-forward可以理解成:

在本机端口和 Kubernetes 集群内部某个 Pod/Service 端口之间建立一条临时转发通道。

9.2 执行 port-forward

先设置变量:

export ENVOY_SERVICE=envoy-gateway-demo-app-gateway-c2617110

执行端口转发:

kubectl -n envoy-gateway-system port-forward service/${ENVOY_SERVICE} 8888:80

这条命令的含义是:

把当前机器的 127.0.0.1:8888 转发到 envoy-gateway-system 命名空间下 envoy-gateway-demo-app-gateway-c2617110 这个 Service 的 80 端口。

格式可以理解为:

本地端口:目标端口

所以:

8888:80

表示:

本机 8888 -> 集群内目标 Service/Pod 的 80

该命令会一直占用当前终端。不要关闭这个终端。


9.3 curl 验证基础路由

重新开一个终端,执行:

curl -s -H "Host: app.example.local" http://127.0.0.1:8888/

实验输出:

hello from app-v1

这说明请求已经成功到达app-v1。这里必须带:

-H "Host: app.example.local"

原因是 Gateway 和 HTTPRoute 都配置了:

hostname: "app.example.local" hostnames: - "app.example.local"

如果直接访问:

curl http://127.0.0.1:8888/

请求里的 Host 会是:

127.0.0.1:8888

它不匹配app.example.local,路由就可能不会命中。


9.4 基础路由链路

基础路由成功后,请求链路如下:

curl -H "Host: app.example.local" http://127.0.0.1:8888/ | v kubectl port-forward | v Envoy Gateway 数据面 Service | v Envoy 数据面 Pod | | Envoy 根据 Gateway listener 和 HTTPRoute 规则匹配请求 v Service app-v1:8080 | v app-v1 Pod:5678 | v hello from app-v1

十、实验一:Path 路由

基础路由已经跑通后,开始测试 Path 路由。目标:

/api -> app-v1 /web -> app-v2

为了避免多个 HTTPRoute 同时存在导致测试结果不清晰,先删除基础 Route:

kubectl -n gateway-demo delete httproute app-route-basic

10.1 创建 Path 路由 YAML

创建文件:

cat > 04-route-path.yaml <<'EOF' apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: app-route-path namespace: gateway-demo spec: parentRefs: - name: app-gateway sectionName: http hostnames: - "app.example.local" rules: - matches: - path: type: PathPrefix value: /api backendRefs: - name: app-v1 port: 8080 - matches: - path: type: PathPrefix value: /web backendRefs: - name: app-v2 port: 8080 EOF

应用:

kubectl apply -f 04-route-path.yaml

检查:

kubectl -n gateway-demo get httproute kubectl -n gateway-demo describe httproute app-route-path

10.2 测试 Path 路由

测试/api

curl -s -H "Host: app.example.local" http://127.0.0.1:8888/api

输出:

hello from app-v1

测试/web

curl -s -H "Host: app.example.local" http://127.0.0.1:8888/web

输出:

hello from app-v2

说明:

/api 成功转发到 app-v1 /web 成功转发到 app-v2

这里使用的是:

type: PathPrefix

表示按路径前缀匹配。例如:

/api /api/ /api/v1

都属于/api前缀。


十一、实验二:Header 匹配

接下来测试基于请求头的匹配。目标:

普通请求 -> app-v1 带 x-env: canary 的请求 -> app-v2

这类能力可以用于测试版本访问、灰度验证等场景。先删除上一条 Path Route:

kubectl -n gateway-demo delete httproute app-route-path

11.1 创建 Header 匹配 YAML

创建文件:

cat > 05-route-header.yaml <<'EOF' apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: app-route-header namespace: gateway-demo spec: parentRefs: - name: app-gateway sectionName: http hostnames: - "app.example.local" rules: - matches: - path: type: PathPrefix value: / headers: - type: Exact name: x-env value: canary backendRefs: - name: app-v2 port: 8080 - matches: - path: type: PathPrefix value: / backendRefs: - name: app-v1 port: 8080 EOF

这里把带 Header 的规则写在前面,把普通默认规则写在后面,便于理解和排查。带 x-env: canary 的请求会匹配第一条规则,普通请求会匹配后面的默认规则。

应用:

kubectl apply -f 05-route-header.yaml

检查:

kubectl -n gateway-demo get httproute kubectl -n gateway-demo describe httproute app-route-header

11.2 测试普通请求

执行:

curl -s -H "Host: app.example.local" http://127.0.0.1:8888/

输出:

hello from app-v1

普通请求没有带x-env: canary,所以命中第二条规则,转发到app-v1


11.3 测试带 Header 的请求

执行:

curl -s -H "Host: app.example.local" \ -H "x-env: canary" \ http://127.0.0.1:8888/

输出:

hello from app-v2

这说明带有:

x-env: canary

的请求命中了第一条规则,并被转发到app-v2。这里需要注意:

同一个 matches 中的 path 和 headers 是共同匹配条件。

也就是说,请求需要同时满足:

PathPrefix / Header x-env=canary

才会命中第一条规则。


十二、实验三:金丝雀分流

最后测试基于权重的流量分配。目标:

app-v1 90% app-v2 10%

先删除 Header Route:

kubectl -n gateway-demo delete httproute app-route-header

12.1 创建金丝雀分流 YAML

创建文件:

cat > 06-route-canary.yaml <<'EOF' apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: app-route-canary namespace: gateway-demo spec: parentRefs: - name: app-gateway sectionName: http hostnames: - "app.example.local" rules: - matches: - path: type: PathPrefix value: / backendRefs: - name: app-v1 port: 8080 weight: 90 - name: app-v2 port: 8080 weight: 10 EOF

应用:

kubectl apply -f 06-route-canary.yaml

检查:

kubectl -n gateway-demo get httproute kubectl -n gateway-demo describe httproute app-route-canary

12.2 测试金丝雀分流

执行 50 次请求:

for i in {1..50}; do curl -s -H "Host: app.example.local" http://127.0.0.1:8888/ done | sort | uniq -c

实验输出:

45 hello from app-v1 5 hello from app-v2

这说明流量大致按照 90/10 分到了app-v1app-v2。这里要注意,weight是相对权重,不是必须加起来等于 100。例如:

app-v1 weight=90 app-v2 weight=10

和:

app-v1 weight=9 app-v2 weight=1

表达的比例都近似是:

app-v1 90% app-v2 10%

另外,请求次数较少时,结果不一定严格等于 90/10。如果想让统计结果更稳定,可以把请求次数增加到 200 次:

for i in {1..200}; do curl -s -H "Host: app.example.local" http://127.0.0.1:8888/ done | sort | uniq -c

十三、常见问题总结

13.1 为什么 curl 必须加 Host header

因为 Gateway 里配置了:

hostname: "app.example.local"

HTTPRoute 里配置了:

hostnames: - "app.example.local"

所以 curl 测试时要带:

-H "Host: app.example.local"

否则请求 Host 是:

127.0.0.1:8888

不会匹配app.example.local


13.2 为什么 port-forward 到数据面 Service,不是 envoy-gateway Service

Envoy Gateway 安装后会有控制面 Service:

envoy-gateway

创建 Gateway 后又会出现数据面 Service:

envoy-gateway-demo-app-gateway-c2617110

它们的作用不同:

envoy-gateway 是控制面 Service,给 Envoy Gateway Controller 自己使用。 envoy-gateway-demo-app-gateway-c2617110 是数据面 Service,给外部流量进入 Gateway 使用。

业务流量应该进入数据面 Service,而不是控制面 Service。所以正确的 port-forward 是:

kubectl -n envoy-gateway-system port-forward service/envoy-gateway-demo-app-gateway-c2617110 8888:80

十四、总结

本文在单节点 Kubernetes 测试环境中完成了 Envoy Gateway 和 Gateway API 的基础实战。

完成的内容包括:

1. 使用 Helm 安装 Envoy Gateway 2. 检查 Gateway API CRD 3. 创建 GatewayClass 4. 部署 app-v1 / app-v2 两个测试服务 5. 创建 Gateway 6. 创建基础 HTTPRoute 7. 使用 port-forward 本机访问 Envoy Gateway 数据面 8. 验证基础路由:/ -> app-v1 9. 验证 Path 路由:/api -> app-v1,/web -> app-v2 10. 验证 Header 匹配:x-env: canary -> app-v2 11. 验证金丝雀分流:app-v1 90%,app-v2 10%

通过这次实验,可以把 Gateway API 的核心链路串起来:

GatewayClass -> Gateway -> HTTPRoute -> Service -> Pod

也可以把 Envoy Gateway 的控制面和数据面关系理清楚:

envoy-gateway-xxx -> 控制面 Controller,负责监听 Gateway API 资源并管理 Envoy 配置 envoy-gateway-demo-app-gateway-xxx -> 数据面 Envoy Proxy,负责真正接收和转发业务流量

最终请求链路如下:

真实流量链路: curl -> port-forward -> Envoy 数据面 Service -> Envoy 数据面 Pod -> Service -> Pod 配置匹配逻辑: Gateway listener -> HTTPRoute host/path/header 匹配 -> backendRefs 选择后端 Service

这篇文章只是 Gateway API 的普通 HTTP 服务实验。后续可以继续把后端app-v1/app-v2替换成 vLLM 模型服务,通过 Gateway API 暴露/v1/chat/completions接口。

http://www.jsqmd.com/news/1033056/

相关文章:

  • 2026年6月铁岭装修市场盘点:五家实力公司深度解析与选择指南 - 品牌鉴赏官2026
  • 3步告别音乐平台限制:洛雪音源终极配置手册
  • 告别手动录入:TransCad批量导入Excel交通数据的实战指南
  • 重装 Visual C++ 的完整流程-PowerShell 版
  • DeBERTa-v3-base-prompt-injection-v2:企业级大语言模型安全防护解决方案
  • ZigBee ZDP API实战:设备发现与绑定管理核心机制解析
  • 2026马桶半夜反水怎么办?24小时义乌管道疏通应急服务排行榜 - 极速版本
  • 2026年当下木方齐头锯制造商选择标准:效率、精度与长期价值的深度考量 - 品牌鉴赏官2026
  • 1.2 提示词工程 面试题
  • 【Netty源码解读和权威指南】第08篇:LengthFieldBasedFrameDecoder——Netty最强帧解码器全攻略
  • AMAT 0190-10114W发电机
  • 手把手搭建本地RAG问答系统:PDF/Word文档智能检索实战
  • 实例分享:三种算法的实际应用
  • 拒玩虚的!北京行贿罪案件辩护_受贿罪律师top5靠谱排行(2026年6月18日最新):专业能力与案例实绩对比 - 奋斗者888
  • 为什么Facade能提供静态方法访问体验?
  • 2026年天津劳动律师实力对比 5位资深律师各有专长 - 本地品牌推荐
  • 完全免费,面向个人的文件“真”搜索引擎
  • 数字电路模拟blog
  • 零碳供电所照明控制系统技术解析:标准要求与产品落地
  • 传奇 3 光通版手游官网下载:传奇 3 光通版全网唯一最新官方下载渠道
  • 电商人效率革命:对话式AI工作台PixPix操作指南(附教程)
  • 电脑自动化 AI OpenClaw 2.7.9 零基础部署分步教学(含安装包)
  • RTOS的灵魂——任务的“优先级反转与抢占”!实战讲解物联网任务调度的顶层设计思想
  • 2026年近期上海餐饮业如何选择好的牛油火锅红油定制厂家 - 品牌鉴赏官2026
  • 学生党AI学习指南:GPT、Gemini、WPS AI三工具协同实战
  • 2026豆包AI视频课:零基础+配套素材+实操闭环
  • 专访星艺装饰佛山业务负责人李泽鲲:七大维度筑牢环保家装底线,直营体系守护佛山人居健康 - Guangdong1
  • FIFA 23 Live Editor终极指南:免费开源修改器深度解析与使用教程
  • 基于C++ 实现(界面)教室管理系统
  • 2026年6月优秀的西安加固优质公司推荐几家:以恒大加固为例剖析选择逻辑 - 品牌鉴赏官2026