
Kubernetes Gateway API 是一个面向服务的、可扩展的 Kubernetes 流量管理标准,由 SIG-NETWORK 社区维护。它是 Ingress API 的演进版本,旨在解决 Ingress 在表达能力、扩展性和标准化方面的局限性。
传统 Ingress 的局限性:
Gateway API 的优势:
Gateway API 定义了一组相互关联的资源对象,每个对象都有明确的职责:
作用:定义网关的实现类型和配置模板,由基础设施提供商创建和管理。
特点:
示例:
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
name: nginx-gateway-class
spec:
controllerName: gateway.networking.k8s.io/nginx-ingress-controller
作用:表示实际的负载均衡器实例,定义监听器(Listeners)和网络端点。
特点:
示例:
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: production-gateway
namespace: web-app
spec:
gatewayClassName: nginx-gateway-class
listeners:
- name: http
port: 80
protocol: HTTP
allowedRoutes:
namespaces:
from: All
- name: https
port: 443
protocol: HTTPS
tls:
mode: Terminate
certificateRefs:
- name: tls-secret
kind: Secret
allowedRoutes:
namespaces:
from: Same
作用:定义如何将 HTTP/HTTPS 流量路由到后端服务,是最常用的路由类型。
特点:
示例:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: web-app-route
namespace: default
spec:
parentRefs:
- name: production-gateway
namespace: web-app
hostnames:
- "app.example.com"
rules:
- matches:
- path:
type: PathPrefix
value: /api
backendRefs:
- name: api-service
port: 8080
weight: 90
- name: api-service-v2
port: 8080
weight: 10
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: web-service
port: 80
作用:路由 TCP 流量到后端服务,适用于数据库、消息队列等场景。
示例:
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: TCPRoute
metadata:
name: database-route
namespace: default
spec:
parentRefs:
- name: tcp-gateway
namespace: default
rules:
- backendRefs:
- name: backend
port: 3000
作用:在 TLS 层面路由流量,支持 TLS Passthrough 模式。
示例:
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: TLSRoute
metadata:
name: tls-passthrough-route
namespace: default
spec:
parentRefs:
- name: tls-gateway
hostnames:
- "secure.example.com"
rules:
- backendRefs:
- name: secure-service
port: 443
作用:路由 UDP 流量,适用于 DNS、游戏服务器等场景。
示例:
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: UDPRoute
metadata:
name: dns-route
namespace: default
spec:
parentRefs:
- name: udp-gateway
rules:
- backendRefs:
- name: dns-service
port: 53
作用:专门用于 gRPC 流量的路由,支持 gRPC 特有的元数据和方法匹配。
示例:
apiVersion: gateway.networking.k8s.io/v1
kind: GRPCRoute
metadata:
name: grpc-service-route
namespace: default
spec:
parentRefs:
- name: production-gateway
hostnames:
- "grpc.example.com"
rules:
- matches:
- method:
service: helloworld.Greeter
method: SayHello
backendRefs:
- name: grpc-service
port: 50051
作用:跨命名空间引用的安全机制,允许一个命名空间的资源引用另一个命名空间的资源。
示例:
apiVersion: gateway.networking.k8s.io/v1beta1
kind: ReferenceGrant
metadata:
name: allow-gateway-ref
namespace: web-app
spec:
from:
- group: gateway.networking.k8s.io
kind: HTTPRoute
namespace: default
to:
- group: ""
kind: Secret
name: tls-secret
特性 | Ingress | Gateway API |
|---|---|---|
API 成熟度 | Stable (v1) | Graduating to Standard (v1) |
协议支持 | HTTP/HTTPS | HTTP, HTTPS, TCP, UDP, gRPC, TLS |
路由能力 | 基于路径和主机 | 路径、主机、Header、Query、方法等 |
流量管理 | 有限 | 权重分配、镜像、超时、重试 |
扩展机制 | 注解(非标准) | 参数化配置 + CRD |
角色分离 | 不明确 | 清晰的三层模型 |
跨命名空间 | 不支持 | 通过 ReferenceGrant 支持 |
TLS 配置 | 简单 | 灵活(Terminate/Passthrough) |
供应商兼容性 | 差异大 | 标准化程度高 |
Gateway API 遵循 Kubernetes 的标准控制器模式,采用声明式 API 设计:
用户/开发者 → Kubernetes API Server → Gateway Controller → Data Plane
↓ ↓ ↓ ↓
创建资源 存储CRD资源 监听变化并生成配置 代理处理流量
创建阶段:
运行阶段:
更新阶段:
控制平面组件:
数据平面组件:
Gateway API 强调可观测性,每个资源都有详细的 Status 字段:
Gateway Status 示例:
status:
conditions:
- type: Accepted
status: "True"
reason: Accepted
message: Gateway successfully accepted
- type: Programmed
status: "True"
reason: Programmed
message: Configuration programmed to data plane
listeners:
- name: http
attachedRoutes: 5
conditions:
- type: Ready
status: "True"
前置要求:
自建集群没有LB所以需要一个负载
# 下载应用包
wget https://raw.githubusercontent.com/metallb/metallb/v0.15.3/config/manifests/metallb-native.yaml
# 修改镜像地址
# 自行找代理
sed -i "s#quay.io#quay.chenby.cn#g" metallb-native.yaml
cat metallb-native.yaml | grep image
image: quay.chenby.cn/metallb/controller:v0.14.5
image: quay.chenby.cn/metallb/speaker:v0.14.5
# 执行部署
kubectl apply -f metallb-native.yaml
# 可以连接国际网络
# kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.15.3/config/manifests/metallb-native.yaml
cby@DESKTOP-IKRNJQE:~$ kubectl -n metallb-system get all
NAME READY STATUS RESTARTS AGE
pod/controller-9c6cff498-h7khm 1/1 Running 0 45m
pod/speaker-kp5wl 1/1 Running 0 45m
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/metallb-webhook-service ClusterIP 10.68.104.187 <none> 443/TCP 45m
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
daemonset.apps/speaker 1 1 1 1 1 kubernetes.io/os=linux 45m
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/controller 1/1 1 1 45m
NAME DESIRED CURRENT READY AGE
replicaset.apps/controller-9c6cff498 1 1 1 45m
cby@DESKTOP-IKRNJQE:~$
# 新版本metallb使用了CR(Custom Resources),这里我们通过IPAddressPool的CR,进行地址池的定义。
# 如果实例中不设置IPAddressPool选择器L2Advertisement;那么L2Advertisement默认为该实例所有的IPAddressPool相关联。
cat > metallb-config-ipaddresspool.yaml << EOF
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: first-pool
namespace: metallb-system
spec:
addresses:
- 192.168.1.15-192.168.1.19
EOF
# 进行L2关联地址池的绑定。
cat > metallb-config-L2Advertisement.yaml << EOF
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: example
namespace: metallb-system
spec:
ipAddressPools:
- first-pool
EOF
# 执行部署
kubectl apply -f metallb-config-ipaddresspool.yaml
kubectl apply -f metallb-config-L2Advertisement.yaml
# https://gateway.envoyproxy.io/docs/install/install-helm/
# 安装网关 API CRD 和 Envoy 网关
helm install eg oci://docker.io/envoyproxy/gateway-helm --version v1.7.3 -n envoy-gateway-system --create-namespace
kubectl apply -f https://github.com/envoyproxy/gateway/releases/download/v1.7.3/quickstart.yaml -n default
# 查看访问地址
cby@DESKTOP-IKRNJQE:~$ kubectl get svc -n envoy-gateway-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
envoy-default-eg-e41e7b31 LoadBalancer 10.68.120.80 192.168.1.15 80:32116/TCP 6s
envoy-gateway ClusterIP 10.68.64.83 <none> 18000/TCP,18001/TCP,18002/TCP,19001/TCP,9443/TCP 30m
cby@DESKTOP-IKRNJQE:~$
cby@DESKTOP-IKRNJQE:~$ curl --verbose --header "Host: www.example.com" http://192.168.1.15/get
* Trying 192.168.1.15:80...
* Established connection to 192.168.1.15 (192.168.1.15 port 80) from 172.30.72.41 port 39072
* using HTTP/1.x
> GET /get HTTP/1.1
> Host: www.example.com
> User-Agent: curl/8.18.0
> Accept: */*
>
* Request completely sent off
< HTTP/1.1 200 OK
< content-type: application/json
< x-content-type-options: nosniff
< date: Mon, 11 May 2026 13:51:37 GMT
< content-length: 475
<
{
"path": "/get",
"host": "www.example.com",
"method": "GET",
"proto": "HTTP/1.1",
"headers": {
"Accept": [
"*/*"
],
"User-Agent": [
"curl/8.18.0"
],
"X-Envoy-External-Address": [
"192.168.1.100"
],
"X-Forwarded-For": [
"192.168.1.100"
],
"X-Forwarded-Proto": [
"http"
],
"X-Request-Id": [
"d30d74c9-2c8e-4249-8ca6-ee24156e3317"
]
},
"namespace": "default",
"ingress": "",
"service": "",
"pod": "backend-869c8646c5-s4426"
* Connection #0 to host 192.168.1.15:80 left intact
}cby@DESKTOP-IKRNJQE:~$
其他可选实现:
cat > gatewayclass.yaml << EOF
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
name: nginx-gateway-class
spec:
controllerName: gateway.envoyproxy.io/gatewayclass-controller
EOF
应用配置:
kubectl apply -f gatewayclass.yaml
kubectl get gatewayclass
cby@DESKTOP-IKRNJQE:~$ kubectl get gatewayclass
gatewayclass.gateway.networking.k8s.io/nginx-gateway-class created
NAME CONTROLLER ACCEPTED AGE
eg gateway.envoyproxy.io/gatewayclass-controller True 19m
nginx-gateway-class gateway.envoyproxy.io/gatewayclass-controller True 18s
cby@DESKTOP-IKRNJQE:~$
创建两个简单的后端服务用于测试:
cat > demo-app.yaml << EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app-v1
spec:
replicas: 1
selector:
matchLabels:
app: web-app-v1
template:
metadata:
labels:
app: web-app-v1
spec:
containers:
- name: web-app-v1
image: registry.cn-hangzhou.aliyuncs.com/chenby/cby:nginx-v1
ports:
- containerPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app-v2
spec:
replicas: 1
selector:
matchLabels:
app: web-app-v2
template:
metadata:
labels:
app: web-app-v2
spec:
containers:
- name: web-app-v2
image: registry.cn-hangzhou.aliyuncs.com/chenby/cby:nginx-v2
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
labels:
app: web-app-v2
name: web-app-v2
spec:
selector:
app: web-app-v2
ports:
- port: 80
protocol: TCP
targetPort: 80
---
apiVersion: v1
kind: Service
metadata:
labels:
app: web-app-v1
name: web-app-v1
spec:
selector:
app: web-app-v1
ports:
- port: 80
protocol: TCP
targetPort: 80
EOF
同样创建 v2 版本,然后应用:
kubectl apply -f demo-app.yaml
测试查看
cby@DESKTOP-IKRNJQE:~$ kubectl get pod
NAME READY STATUS RESTARTS AGE
backend-869c8646c5-s4426 1/1 Running 0 20m
web-app-v1-844db9d88f-tjwzz 1/1 Running 0 22s
web-app-v2-dd8d978b8-9stzg 1/1 Running 0 22s
cby@DESKTOP-IKRNJQE:~$
cby@DESKTOP-IKRNJQE:~$
cby@DESKTOP-IKRNJQE:~$
cby@DESKTOP-IKRNJQE:~$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
backend ClusterIP 10.68.86.118 <none> 3000/TCP 21m
kubernetes ClusterIP 10.68.0.1 <none> 443/TCP 60d
web-app-v1 ClusterIP 10.68.255.182 <none> 80/TCP 27s
web-app-v2 ClusterIP 10.68.113.128 <none> 80/TCP 27s
cby@DESKTOP-IKRNJQE:~$
cby@DESKTOP-IKRNJQE:~$ curl ^[[200~10.68.255.182~^C
cby@DESKTOP-IKRNJQE:~$
cby@DESKTOP-IKRNJQE:~$
cby@DESKTOP-IKRNJQE:~$ curl 10.68.255.182
<h1 style="color: #4CAF50;">Hello V1</h1><p>时间:2026-05-11 星期一</p><p>地点:内蒙古自治区 呼和浩特市</p>
cby@DESKTOP-IKRNJQE:~$
cby@DESKTOP-IKRNJQE:~$ curl 10.68.113.128
<h1 style="color: #2196F3;">Hello V2</h1><p>时间:2026-05-11 星期一</p><p>地点:内蒙古自治区 呼和浩特市</p>
cby@DESKTOP-IKRNJQE:~$
首先创建 Gateway:
cat > gateway.yaml << EOF
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: production-gateway
namespace: web-app
spec:
gatewayClassName: nginx-gateway-class
listeners:
- name: http
port: 80
protocol: HTTP
allowedRoutes:
namespaces:
from: All
EOF
创建 HTTPRoute:
cat > httproute-basic.yaml << EOF
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: web-app-route
namespace: default
spec:
parentRefs:
- name: production-gateway
namespace: web-app
hostnames:
- "app.example.com"
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: web-app-v1
port: 80
- name: web-app-v2
port: 80
EOF
应用配置:
kubectl create namespace web-app
kubectl apply -f gateway.yaml
kubectl apply -f httproute-basic.yaml
# 验证
kubectl get gateway -n web-app
kubectl get httproute -n default
cby@DESKTOP-IKRNJQE:~$ kubectl get gateway -n web-app
NAME CLASS ADDRESS PROGRAMMED AGE
production-gateway nginx-gateway-class 192.168.1.16 True 13s
cby@DESKTOP-IKRNJQE:~$
cby@DESKTOP-IKRNJQE:~$ kubectl get httproute -n default
NAME HOSTNAMES AGE
backend ["www.example.com"] 26m
web-app-route ["app.example.com"] 56s
cby@DESKTOP-IKRNJQE:~$
获取 LoadBalancer IP 并测试:
curl -H "Host: app.example.com" http://192.168.1.16
cby@DESKTOP-IKRNJQE:~$ curl -H "Host: app.example.com" http://192.168.1.16
<h1 style="color: #2196F3;">Hello V2</h1><p>时间:2026-05-11 星期一</p><p>地点:内蒙古自治区 呼和浩特市</p>
cby@DESKTOP-IKRNJQE:~$ curl -H "Host: app.example.com" http://192.168.1.16
<h1 style="color: #4CAF50;">Hello V1</h1><p>时间:2026-05-11 星期一</p><p>地点:内蒙古自治区 呼和浩特市</p>
cby@DESKTOP-IKRNJQE:~$ curl -H "Host: app.example.com" http://192.168.1.16
<h1 style="color: #2196F3;">Hello V2</h1><p>时间:2026-05-11 星期一</p><p>地点:内蒙古自治区 呼和浩特市</p>
cby@DESKTOP-IKRNJQE:~$ curl -H "Host: app.example.com" http://192.168.1.16
<h1 style="color: #4CAF50;">Hello V1</h1><p>时间:2026-05-11 星期一</p><p>地点:内蒙古自治区 呼和浩特市</p>
cby@DESKTOP-IKRNJQE:~$ curl -H "Host: app.example.com" http://192.168.1.16
<h1 style="color: #2196F3;">Hello V2</h1><p>时间:2026-05-11 星期一</p><p>地点:内蒙古自治区 呼和浩特市</p>
cby@DESKTOP-IKRNJQE:~$ curl -H "Host: app.example.com" http://192.168.1.16
<h1 style="color: #4CAF50;">Hello V1</h1><p>时间:2026-05-11 星期一</p><p>地点:内蒙古自治区 呼和浩特市</p>
cby@DESKTOP-IKRNJQE:~$
openssl genrsa -out tls.key 2048
openssl req -new -key tls.key -out tls.csr -subj "/CN=app.example.com"
openssl x509 -req -in tls.csr -signkey tls.key -out tls.crt -days 365
kubectl create secret tls app-tls-secret \
--cert=tls.crt \
--key=tls.key \
-n web-app
rm tls.key tls.csr tls.crt
cat > gateway-with-tls.yaml << EOF
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: production-gateway
namespace: web-app
spec:
gatewayClassName: nginx-gateway-class
listeners:
- name: http
port: 80
protocol: HTTP
allowedRoutes:
namespaces:
from: All
- name: https
port: 443
protocol: HTTPS
tls:
mode: Terminate
certificateRefs:
- name: app-tls-secret
kind: Secret
group: ""
allowedRoutes:
namespaces:
from: All
EOF
应用更新:
kubectl apply -f gateway-with-tls.yaml
测试 HTTPS 访问:
curl -k -H "Host: app.example.com" https://192.168.1.16
cby@DESKTOP-IKRNJQE:~$ curl -k -H "Host: app.example.com" https://192.168.1.16
<h1 style="color: #4CAF50;">Hello V1</h1><p>时间:2026-05-11 星期一</p><p>地点:内蒙古自治区 呼和浩特市</p>
cby@DESKTOP-IKRNJQE:~$ curl -k -H "Host: app.example.com" https://192.168.1.16
<h1 style="color: #2196F3;">Hello V2</h1><p>时间:2026-05-11 星期一</p><p>地点:内蒙古自治区 呼和浩特市</p>
cby@DESKTOP-IKRNJQE:~$ curl -k -H "Host: app.example.com" https://192.168.1.16
<h1 style="color: #4CAF50;">Hello V1</h1><p>时间:2026-05-11 星期一</p><p>地点:内蒙古自治区 呼和浩特市</p>
cby@DESKTOP-IKRNJQE:~$ curl -k -H "Host: app.example.com" https://192.168.1.16
<h1 style="color: #2196F3;">Hello V2</h1><p>时间:2026-05-11 星期一</p><p>地点:内蒙古自治区 呼和浩特市</p>
cby@DESKTOP-IKRNJQE:~$ curl -k -H "Host: app.example.com" https://192.168.1.16
<h1 style="color: #4CAF50;">Hello V1</h1><p>时间:2026-05-11 星期一</p><p>地点:内蒙古自治区 呼和浩特市</p>
cby@DESKTOP-IKRNJQE:~$
创建将 90% 流量发送到 v1,10% 流量发送到 v2 的路由:
cat > httproute-canary.yaml << EOF
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: web-app-canary-route
namespace: default
spec:
parentRefs:
- name: production-gateway
namespace: web-app
hostnames:
- "app.example.com"
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: web-app-v1
port: 80
weight: 90
- name: web-app-v2
port: 80
weight: 10
EOF
应用配置:
kubectl delete -f httproute-basic.yaml
kubectl apply -f httproute-canary.yaml
cby@DESKTOP-IKRNJQE:~$ kubectl get HTTPRoute
NAMESPACE NAME HOSTNAMES AGE
default backend ["www.example.com"] 45m
default web-app-canary-route ["app.example.com"] 104s
cby@DESKTOP-IKRNJQE:~$
测试流量分割:
for i in {1..20}; do
curl -s -H "Host: app.example.com" http://192.168.1.16
done
cby@DESKTOP-IKRNJQE:~$ for i in {1..20}; do
curl -s -H "Host: app.example.com" http://192.168.1.16
done
<h1 style="color: #4CAF50;">Hello V1</h1><p>时间:2026-05-11 星期一</p><p>地点:内蒙古自治区 呼和浩特市</p>
<h1 style="color: #4CAF50;">Hello V1</h1><p>时间:2026-05-11 星期一</p><p>地点:内蒙古自治区 呼和浩特市</p>
<h1 style="color: #4CAF50;">Hello V1</h1><p>时间:2026-05-11 星期一</p><p>地点:内蒙古自治区 呼和浩特市</p>
<h1 style="color: #2196F3;">Hello V2</h1><p>时间:2026-05-11 星期一</p><p>地点:内蒙古自治区 呼和浩特市</p>
<h1 style="color: #4CAF50;">Hello V1</h1><p>时间:2026-05-11 星期一</p><p>地点:内蒙古自治区 呼和浩特市</p>
<h1 style="color: #4CAF50;">Hello V1</h1><p>时间:2026-05-11 星期一</p><p>地点:内蒙古自治区 呼和浩特市</p>
<h1 style="color: #4CAF50;">Hello V1</h1><p>时间:2026-05-11 星期一</p><p>地点:内蒙古自治区 呼和浩特市</p>
<h1 style="color: #4CAF50;">Hello V1</h1><p>时间:2026-05-11 星期一</p><p>地点:内蒙古自治区 呼和浩特市</p>
<h1 style="color: #4CAF50;">Hello V1</h1><p>时间:2026-05-11 星期一</p><p>地点:内蒙古自治区 呼和浩特市</p>
<h1 style="color: #4CAF50;">Hello V1</h1><p>时间:2026-05-11 星期一</p><p>地点:内蒙古自治区 呼和浩特市</p>
<h1 style="color: #4CAF50;">Hello V1</h1><p>时间:2026-05-11 星期一</p><p>地点:内蒙古自治区 呼和浩特市</p>
<h1 style="color: #4CAF50;">Hello V1</h1><p>时间:2026-05-11 星期一</p><p>地点:内蒙古自治区 呼和浩特市</p>
<h1 style="color: #4CAF50;">Hello V1</h1><p>时间:2026-05-11 星期一</p><p>地点:内蒙古自治区 呼和浩特市</p>
<h1 style="color: #2196F3;">Hello V2</h1><p>时间:2026-05-11 星期一</p><p>地点:内蒙古自治区 呼和浩特市</p>
<h1 style="color: #4CAF50;">Hello V1</h1><p>时间:2026-05-11 星期一</p><p>地点:内蒙古自治区 呼和浩特市</p>
<h1 style="color: #4CAF50;">Hello V1</h1><p>时间:2026-05-11 星期一</p><p>地点:内蒙古自治区 呼和浩特市</p>
<h1 style="color: #4CAF50;">Hello V1</h1><p>时间:2026-05-11 星期一</p><p>地点:内蒙古自治区 呼和浩特市</p>
<h1 style="color: #4CAF50;">Hello V1</h1><p>时间:2026-05-11 星期一</p><p>地点:内蒙古自治区 呼和浩特市</p>
<h1 style="color: #4CAF50;">Hello V1</h1><p>时间:2026-05-11 星期一</p><p>地点:内蒙古自治区 呼和浩特市</p>
<h1 style="color: #4CAF50;">Hello V1</h1><p>时间:2026-05-11 星期一</p><p>地点:内蒙古自治区 呼和浩特市</p>
cby@DESKTOP-IKRNJQE:~$
cat > httproute-header.yaml << EOF
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: header-based-route
namespace: default
spec:
parentRefs:
- name: production-gateway
namespace: web-app
hostnames:
- "app.example.com"
rules:
- matches:
- headers:
- name: x-version
value: v2
backendRefs:
- name: web-app-v2
port: 80
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: web-app-v1
port: 80
EOF
测试:
kubectl delete -f httproute-canary.yaml
kubectl apply -f httproute-header.yaml
# 不带 Header,访问 v1
curl -H "Host: app.example.com" http://192.168.1.16
# 带 Header,访问 v2
curl -H "Host: app.example.com" -H "x-version: v2" http://192.168.1.16
cby@DESKTOP-IKRNJQE:~$ curl -H "Host: app.example.com" http://192.168.1.16
<h1 style="color: #4CAF50;">Hello V1</h1><p>时间:2026-05-11 星期一</p><p>地点:内蒙古自治区 呼和浩特市</p>
cby@DESKTOP-IKRNJQE:~$
cby@DESKTOP-IKRNJQE:~$ curl -H "Host: app.example.com" -H "x-version: v2" http://192.168.1.16
<h1 style="color: #2196F3;">Hello V2</h1><p>时间:2026-05-11 星期一</p><p>地点:内蒙古自治区 呼和浩特市</p>
cby@DESKTOP-IKRNJQE:~$
cat > httproute-rewrite.yaml << EOF
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: rewrite-route
namespace: default
spec:
parentRefs:
- name: production-gateway
namespace: web-app
hostnames:
- "app.example.com"
rules:
- matches:
- path:
type: PathPrefix
value: /api/v1
filters:
- type: URLRewrite
urlRewrite:
path:
type: ReplacePrefixMatch
replacePrefixMatch: /
backendRefs:
- name: web-app-v1
port: 80
- matches:
- path:
type: PathPrefix
value: /api/v2
filters:
- type: URLRewrite
urlRewrite:
path:
type: ReplacePrefixMatch
replacePrefixMatch: /
backendRefs:
- name: web-app-v2
port: 80
EOF
测试使用
kubectl delete -f httproute-header.yaml
kubectl apply -f httproute-rewrite.yaml
curl -H "Host: app.example.com" http://192.168.1.16/api/v1
curl -H "Host: app.example.com" http://192.168.1.16/api/v2
cby@DESKTOP-IKRNJQE:~$ curl -H "Host: app.example.com" http://192.168.1.16/api/v1
<h1 style="color: #4CAF50;">Hello V1</h1><p>时间:2026-05-11 星期一</p><p>地点:内蒙古自治区 呼和浩特市</p>
cby@DESKTOP-IKRNJQE:~$ curl -H "Host: app.example.com" http://192.168.1.16/api/v2
<h1 style="color: #2196F3;">Hello V2</h1><p>时间:2026-05-11 星期一</p><p>地点:内蒙古自治区 呼和浩特市</p>
cby@DESKTOP-IKRNJQE:~$
cat > httproute-modify.yaml << EOF
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: header-modify-route
namespace: default
spec:
parentRefs:
- name: production-gateway
namespace: web-app
hostnames:
- "app.example.com"
rules:
- matches:
- path:
type: PathPrefix
value: /
filters:
- type: RequestHeaderModifier
requestHeaderModifier:
add:
- name: X-Forwarded-Gateway
value: "nginx-gateway"
set:
- name: X-Custom-Header
value: "custom-value"
- type: ResponseHeaderModifier
responseHeaderModifier:
add:
- name: X-Powered-By
value: "Gateway-API"
backendRefs:
- name: web-app-v1
port: 80
EOF
kubectl delete -f httproute-rewrite.yaml
kubectl apply -f httproute-modify.yaml
curl -v -H "Host: app.example.com" http://192.168.1.16/
cby@DESKTOP-IKRNJQE:~$ curl -v -H "Host: app.example.com" http://192.168.1.16/
* Trying 192.168.1.16:80...
* Established connection to 192.168.1.16 (192.168.1.16 port 80) from 172.30.72.41 port 46798
* using HTTP/1.x
> GET / HTTP/1.1
> Host: app.example.com
> User-Agent: curl/8.18.0
> Accept: */*
>
* Request completely sent off
< HTTP/1.1 200 OK
< server: nginx/1.29.8
< date: Mon, 11 May 2026 14:54:24 GMT
< content-type: text/html
< content-length: 128
< last-modified: Mon, 11 May 2026 14:02:13 GMT
< etag: "6a01e165-80"
< accept-ranges: bytes
< x-powered-by: Gateway-API
<
<h1 style="color: #4CAF50;">Hello V1</h1><p>时间:2026-05-11 星期一</p><p>地点:内蒙古自治区 呼和浩特市</p>
* Connection #0 to host 192.168.1.16:80 left intact
cby@DESKTOP-IKRNJQE:~$
为应用团队创建受限角色,只允许管理 Route 资源:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: gateway-route-manager
namespace: default
rules:
- apiGroups: ["gateway.networking.k8s.io"]
resources: ["httproutes", "grpcroutes"]
verbs: ["get", "list", "watch", "create", "update", "patch"]
apiVersion: gateway.networking.k8s.io/v1beta1
kind: ReferenceGrant
metadata:
name: allow-tls-ref
namespace: cert-manager
spec:
from:
- group: gateway.networking.k8s.io
kind: Gateway
namespace: web-app
to:
- group: ""
kind: Secret
name: wildcard-tls-cert
限制允许的路由来源,减少配置复杂度:
spec:
listeners:
- name: http
port: 80
protocol: HTTP
allowedRoutes:
namespaces:
from: Selector
selector:
matchLabels:
allow-gateway-access: "true"
金丝雀发布流程:
# 阶段 1: 5% 流量
backendRefs:
- name: web-app-v1
weight: 95
- name: web-app-v2
weight: 5
# 阶段 2: 25% 流量
backendRefs:
- name: web-app-v1
weight: 75
- name: web-app-v2
weight: 25
# 阶段 3: 100% 流量
backendRefs:
- name: web-app-v2
weight: 100
通过快速切换权重实现蓝绿部署:
# 初始状态: 100% 蓝色环境
backendRefs:
- name: blue-service
weight: 100
- name: green-service
weight: 0
# 切换时: 快速切换到绿色环境
backendRefs:
- name: blue-service
weight: 0
- name: green-service
weight: 100
spec:
listeners:
- name: http
port: 80
protocol: HTTP
allowedRoutes:
namespaces:
from: Selector
selector:
matchLabels:
environment: production
问题 1: Gateway 状态为 "Not Accepted"
检查步骤:
# 1. 检查 GatewayClass 是否存在且有效
kubectl get gatewayclass
# 2. 检查 Controller 是否运行
kubectl get pods -n <controller-namespace>
# 3. 查看 Gateway 事件
kubectl describe gateway <name> -n <namespace>
# 4. 检查控制器日志
kubectl logs -n <controller-namespace> -l app=<controller-name>
问题 2: HTTPRoute 未被接受
检查步骤:
# 1. 验证 parentRefs 是否正确
kubectl get httproute <name> -o yaml
# 2. 检查 Gateway 是否允许该命名空间的路由
kubectl describe gateway <gateway-name> -n <namespace>
# 3. 验证后端服务是否存在
kubectl get svc <backend-service-name>
# 4. 检查 ReferenceGrant (如果跨命名空间)
kubectl get referencegrant -A
问题 3: 流量未正确路由
检查步骤:
# 1. 验证路由规则匹配条件
kubectl describe httproute <name>
# 2. 测试后端服务直接访问
kubectl run test --rm -i --tty --image=curlimages/curl -- \
curl http://<service-name>.<namespace>.svc.cluster.local
# 3. 检查 Gateway 外部 IP
kubectl get gateway <name> -o jsonpath='{.status.addresses}'
# 4. 使用详细输出测试
curl -v -H "Host: <hostname>" http://<gateway-ip><path>
spec:
replicas: 3
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
# 备份所有 Gateway API 资源
kubectl get gatewayclass,gateway,httproute,tcproute,referencegrant -A -o yaml > gateway-backup.yaml
关键监控指标:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: multi-domain-route
spec:
parentRefs:
- name: production-gateway
hostnames:
- "app1.example.com"
- "app2.example.com"
- "app3.example.com"
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: shared-backend
port: 80
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: api-gateway-route
spec:
parentRefs:
- name: production-gateway
hostnames:
- "api.example.com"
rules:
- matches:
- path:
type: PathPrefix
value: /users
backendRefs:
- name: user-service
port: 8080
- matches:
- path:
type: PathPrefix
value: /orders
backendRefs:
- name: order-service
port: 8080
- matches:
- path:
type: PathPrefix
value: /payments
backendRefs:
- name: payment-service
port: 8080
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: ab-test-route
spec:
parentRefs:
- name: production-gateway
hostnames:
- "app.example.com"
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: variant-a
port: 80
weight: 50
- name: variant-b
port: 80
weight: 50
Q1: Gateway API 和 Ingress 可以共存吗?
A: 可以。它们使用不同的资源类型,可以同时在集群中运行。建议逐步迁移,先在新服务中使用 Gateway API。
Q2: 如何选择 Gateway Controller 实现?
A: 考虑因素:
推荐选择:
Q3: Gateway API 的性能如何?
A: Gateway API 本身是控制平面,性能取决于数据平面实现(Envoy/Nginx 等)、配置复杂度和硬件资源。现代实现(如 Envoy)可以达到数十万 QPS,延迟在毫秒级。
Q4: 如何处理 WebSocket 连接?
A: HTTPRoute 天然支持 WebSocket,无需特殊配置。确保后端服务正确处理 Upgrade 头即可。
Q5: 可以实现速率限制吗?
A: Gateway API v1 标准不直接支持速率限制,但可以通过以下方式实现:
Q6: 如何迁移现有的 Ingress 配置?
A: 迁移步骤:
可以使用官方工具 ingress2gateway 辅助转换:
kubectl get ingress -A -o yaml | ingress2gateway -f -
Q7: Gateway API 支持哪些 Kubernetes 版本?
A: Gateway API v1 需要 Kubernetes 1.22+,推荐使用最新的稳定版 Kubernetes 以获得最佳支持。
Q8: 如何实现灰度发布的自动化?
A: 结合以下工具:
Kubernetes Gateway API 代表了 Kubernetes 流量管理的未来方向。通过本教程,您应该已经掌握了:
下一步学习建议:
祝您在 Kubernetes Gateway API 的学习之路上取得成功!