Gateway API + Envoy Gateway + K8s 1.33
推荐版本
| 组件 | 版本 |
|---|---|
| Kubernetes | 1.33 |
| Gateway API CRD | v1.5.1 |
| Envoy Gateway | v1.8.2 |
| Envoy Proxy | distroless-v1.38.0 |
| Rate Limit | 1e50889b |
脚本一览
| 脚本 | 作用 |
|---|---|
sync-images.sh |
把官方镜像同步到自己仓库 |
install-eg.sh |
一键安装 Gateway API + Envoy Gateway |
uninstall-gateway.sh |
**一键卸载Gateway ** |
eg-values.yaml |
Helm values |
eg-proxy.yaml |
数据面镜像 + GatewayClass(强制 NodePort + Cluster) |
ensure-envoy-nodeport.sh |
创建 Gateway 后纠正 Service,保证所有节点可访问 |
1. 同步镜像到私有仓库
在有外网的服务器上同步镜像

docker login registry.cn-chengdu.aliyuncs.com
bash sync-images.sh
2. 一键安装
export GH_PROXY="${GH_PROXY:-https://ghfast.top/}"
export IMAGE_REGISTRY=registry.example.com/myproj
bash install-eg.sh
等待安装完即可


安装后创建入口,并改正数据面 Service:
kubectl apply -f - <<'EOF'
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: eg
namespace: default
spec:
gatewayClassName: eg
listeners:
- name: http
protocol: HTTP
port: 80
allowedRoutes:
namespaces:
from: All
EOF

# 必做:NodePort + externalTrafficPolicy=Cluster(所有节点可访问)
bash ensure-envoy-nodeport.sh
kubectl get gateway eg -o wide
kubectl -n envoy-gateway-system get svc -l gateway.envoyproxy.io/owning-gateway-name=eg


3. 裸机多节点访问(必读,避免再踩坑)
只有某一个节点能打开 Gateway,例如仅:
http://172.16.10.117:32030/ # 通
http://172.16.10.114:32030/ # 不通
原因
数据面 Service 默认常为:
type: LoadBalancer(裸机 EXTERNAL-IP 一直<pending>)- 或
externalTrafficPolicy: Local→ 只有跑着 Envoy Pod 的节点上的 NodePort 能通
正确配置(必须同时满足)
| 字段 | 正确值 | 说明 |
|---|---|---|
spec.type |
NodePort |
裸机不用云 LB |
spec.externalTrafficPolicy |
Cluster |
任意节点 IP:NodePort 都转发到 Envoy |
| NodePort | 如 32030(自动分配) |
所有节点共用同一 NodePort 号 |
eg-proxy.yaml 已写入上述策略;创建 Gateway 后再执行一次:
bash ensure-envoy-nodeport.sh
4. 一键卸载
bash uninstall-gateway.sh



卸载后自检:
kubectl get ns | grep envoy-gateway || echo "无 envoy-gateway 命名空间"
kubectl get crd | grep -E 'gateway\.(networking|envoyproxy)' || echo "无 gateway 相关 CRD"

若提示仍有残留,再执行一次:
bash uninstall-gateway.sh --yes
重装:
bash install-eg.sh
重装后创建 Gateway,务必再执行 bash ensure-envoy-nodeport.sh。
5. 业务路由:HTTPRoute / GRPCRoute
HTTPRoute(HTTP)
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: demo-http
namespace: default
spec:
parentRefs:
- name: eg # 挂到 Gateway/eg
hostnames:
- "demo.example.com" # 可选
rules:
- matches:
- path:
type: PathPrefix # Exact | PathPrefix | RegularExpression
value: /app
backendRefs:
- name: demo-svc # Service 名
port: 8080
kubectl apply -f examples/httproute-demo.yaml
kubectl get httproute -A

GRPCRoute(gRPC)
gRPC 走 HTTP/2,挂在 Gateway 的 HTTP(明文)或 HTTPS(TLS) listener 上:
apiVersion: gateway.networking.k8s.io/v1
kind: GRPCRoute
metadata:
name: demo-grpc
namespace: default
spec:
parentRefs:
- name: eg
hostnames:
- "grpc.example.com"
rules:
- matches:
- method:
service: helloworld.Greeter
method: SayHello
backendRefs:
- name: grpc-svc
port: 9000
kubectl apply -f examples/grpcroute-demo.yaml
kubectl get grpcroute -A
# grpcurl -plaintext -authority grpc.example.com \
# <节点IP>:<NodePort> helloworld.Greeter/SayHello
修改响应头 Server(如 nginx → Gateway)
注意:
HTTPRoute的ResponseHeaderModifier对Server这个特殊头经常无效,不要只依赖它。
方式一(优先):ClientTrafficPolicy 全局改写
kubectl apply -f examples/clienttrafficpolicy-server-header.yaml

apiVersion: gateway.envoyproxy.io/v1alpha1
kind: ClientTrafficPolicy
metadata:
name: set-server-header
namespace: default
spec:
targetRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: eg
headers:
lateResponseHeaders:
set:
- name: Server
value: Gateway
验证:
curl -sI http://<节点IP>:<NodePort>/ | grep -i server
# 期望: server: Gateway

方式二:不生效时用 EnvoyPatchPolicy(强制 OVERWRITE)
需先开启控制器的 EnvoyPatchPolicy(EnvoyGateway / 配置里):
extensionApis:
enableEnvoyPatchPolicy: true
然后:
kubectl apply -f examples/envoypatch-server-header.yaml
该清单对 listener default/eg/http 设置:
server_name: Gatewayserver_header_transformation: OVERWRITE
若 Gateway/listener 名不同,改 patch 里的 name: <ns>/<gateway>/<listener>。
| 做法 | 说明 |
|---|---|
ResponseHeaderModifier |
对 Server 常无效 |
ClientTrafficPolicy late set |
先试,全 Gateway 生效 |
EnvoyPatchPolicy |
最稳,直接改 Envoy HCM |
6. 常用查看命令
kubectl get gatewayclass
kubectl get gateway -A -o wide
kubectl get httproute,grpcroute -A
# 路由是否 Accepted
kubectl get httproute,grpcroute -A -o wide
kubectl describe httproute -A
kubectl describe grpcroute -A
kubectl -n envoy-gateway-system get pods,svc
# 确认多节点可访问:应为 type=NodePort externalTrafficPolicy=Cluster
kubectl -n envoy-gateway-system get svc -l gateway.envoyproxy.io/owning-gateway-name=eg \
-o custom-columns=NAME:.metadata.name,TYPE:.spec.type,POLICY:.spec.externalTrafficPolicy,NODEPORT:.spec.ports[0].nodePort
7. 查看 Gateway 转发 / 访问日志
转发日志在数据面 Envoy(处理流量的 Pod),不在控制面 envoy-gateway Deployment。
# 列出数据面 Pod
kubectl -n envoy-gateway-system get pods -l gateway.envoyproxy.io/owning-gateway-name=eg
# 实时看访问日志(JSON,含 method / path / response_code / route_name / upstream_host)
kubectl -n envoy-gateway-system logs -f \
-l gateway.envoyproxy.io/owning-gateway-namespace=default,gateway.envoyproxy.io/owning-gateway-name=eg \
-c envoy
# 只看有 start_time 的访问行并格式化(需本机 jq)
kubectl -n envoy-gateway-system logs \
-l gateway.envoyproxy.io/owning-gateway-namespace=default,gateway.envoyproxy.io/owning-gateway-name=eg \
-c envoy --tail=100 | grep start_time | jq
日志里重点字段:
| 字段 | 含义 |
|---|---|
route_name |
命中的 HTTPRoute 规则 |
upstream_host / upstream_cluster |
转到的后端 |
response_code |
返回码 |
:authority / method / x-envoy-origin-path |
请求 Host / 方法 / 路径 |
控制面排障(配置下发,不是每条业务请求):
kubectl -n envoy-gateway-system logs -f deploy/envoy-gateway
让响应头返回 x-request-id(排障用)
访问日志里虽有 x-request-id,但 Envoy 默认不会把它写回响应头(客户端请求里没带时)。
要用「响应头里的 ID → 搜日志」必须打开回写。
临时验证(客户端自己带 ID):
RID=$(cat /proc/sys/kernel/random/uuid) # 或 uuidgen
curl -sI -H "X-Request-ID: ${RID}" http://172.16.10.114:31258/ | grep -i x-request-id
# 响应里应能看到 x-request-id
长期方案:强制始终回写(推荐)
- 开启 EnvoyPatchPolicy(改控制器配置后重启
envoy-gateway):
# EnvoyGateway / ConfigMap 配置片段
extensionApis:
enableEnvoyPatchPolicy: true
常见改法(按实际安装调整):
kubectl -n envoy-gateway-system edit configmap envoy-gateway-config
# 在 envoy-gateway.yaml 的 extensionApis 下加上 enableEnvoyPatchPolicy: true
kubectl -n envoy-gateway-system rollout restart deploy/envoy-gateway

- 应用 patch:
kubectl apply -f examples/envoypatch-echo-request-id.yaml

核心是设置 HCM:always_set_request_id_in_response: true。
- 验证:
curl -sI http://172.16.10.114:31258/ | grep -i x-request-id
# 期望出现: x-request-id: <uuid>
# 用该 ID 搜访问日志
kubectl -n envoy-gateway-system logs \
-l gateway.envoyproxy.io/owning-gateway-name=eg -c envoy --tail=200 \
| grep '<上面的-uuid>'

8. 下载地址
git clone https://github.com/web-starbucket/k8s-script.git
Comments & discussion
The first comment in each thread opens a topic. Signed-in readers can keep the conversation going under that topic.
No comments yet. Sign in to start a topic.
Start a new topic
Sign in to start a topic or join the discussion.