Blog

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. 同步镜像到私有仓库

在有外网的服务器上同步镜像 《放弃Nginx Ingress,一键部署Gateway-api网关》文章正文配图 — STARBUCKET BLOG

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

等待安装完即可 《放弃Nginx Ingress,一键部署Gateway-api网关》文章正文配图(配图 2)— STARBUCKET BLOG

《放弃Nginx Ingress,一键部署Gateway-api网关》文章正文配图(配图 3)— STARBUCKET BLOG

安装后创建入口,并改正数据面 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
![](https://resource.starbucket.cn/website/image/posts/abandon-nginx-ingress-and-deploy-gateway-api-gateway-with-just-one-click/19aaceebeeff4a55994a50e2e25de5de.png)

# 必做: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

《放弃Nginx Ingress,一键部署Gateway-api网关》文章正文配图(配图 4)— STARBUCKET BLOG

《放弃Nginx Ingress,一键部署Gateway-api网关》文章正文配图(配图 5)— STARBUCKET BLOG


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

《放弃Nginx Ingress,一键部署Gateway-api网关》文章正文配图(配图 6)— STARBUCKET BLOG

《放弃Nginx Ingress,一键部署Gateway-api网关》文章正文配图(配图 7)— STARBUCKET BLOG

《放弃Nginx Ingress,一键部署Gateway-api网关》文章正文配图(配图 8)— STARBUCKET BLOG

卸载后自检:

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

《放弃Nginx Ingress,一键部署Gateway-api网关》文章正文配图(配图 9)— STARBUCKET BLOG

若提示仍有残留,再执行一次:

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

《放弃Nginx Ingress,一键部署Gateway-api网关》文章正文配图(配图 10)— STARBUCKET BLOG

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)

注意:HTTPRouteResponseHeaderModifierServer 这个特殊头经常无效,不要只依赖它。

方式一(优先):ClientTrafficPolicy 全局改写

kubectl apply -f examples/clienttrafficpolicy-server-header.yaml

《放弃Nginx Ingress,一键部署Gateway-api网关》文章正文配图(配图 11)— STARBUCKET BLOG

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

《放弃Nginx Ingress,一键部署Gateway-api网关》文章正文配图(配图 12)— STARBUCKET BLOG

方式二:不生效时用 EnvoyPatchPolicy(强制 OVERWRITE)

需先开启控制器的 EnvoyPatchPolicy(EnvoyGateway / 配置里):

extensionApis:
  enableEnvoyPatchPolicy: true

然后:

kubectl apply -f examples/envoypatch-server-header.yaml

该清单对 listener default/eg/http 设置:

  • server_name: Gateway
  • server_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

长期方案:强制始终回写(推荐)

  1. 开启 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

《放弃Nginx Ingress,一键部署Gateway-api网关》文章正文配图(配图 13)— STARBUCKET BLOG

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

《放弃Nginx Ingress,一键部署Gateway-api网关》文章正文配图(配图 14)— STARBUCKET BLOG

核心是设置 HCM:always_set_request_id_in_response: true

  1. 验证:
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>'

《放弃Nginx Ingress,一键部署Gateway-api网关》文章正文配图(配图 15)— STARBUCKET BLOG

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.