Envoy Gateway 控制面、策略与生产落地
平台刚把一条 HTTPRoute 合并进集群,Gateway 与 Route 的 conditions 都已经转绿,业务请求却仍然间歇性返回 503。应用团队看到的是 Gateway API 对象,平台团队看到的是 Envoy Gateway controller,流量真正经过的却是受管 Envoy Proxy;如果三层证据没有关联起来,大家很容易把“控制器已经接受配置”误解成“每个代理都已加载且后端健康”。
Envoy Gateway 解决的不是手写一份 Envoy YAML,而是把 Gateway API 和自身扩展 CRD 表达的期望状态,持续翻译为 Kubernetes 基础设施与 Envoy xDS 配置。它负责控制面,受管 Envoy Proxy 负责数据面。理解这条翻译与发布链,比记住某个 xDS 资源名更重要,因为内部生成名、默认值和扩展字段都会随发行线变化。
不再手写 Envoy,而是管理一条翻译链
Envoy Gateway 与原生 Envoy 的分工要先摆正。原生 Envoy 教程关注 Listener、FilterChain、HTTP Connection Manager、Route、Cluster、Endpoint 与 bootstrap/xDS 语义;Envoy Gateway 关注 Kubernetes 对象由谁拥有、如何 reconciliation、怎样生成受管基础设施与 xDS、策略如何附着、失败如何进入 status,以及团队如何升级和退出。
Resource Translator 先把外部 API 隔离为内部中间表示:Gateway listener 对应 Envoy listener 意图,HTTPRoute 对应 route 意图,backendRef 对应 cluster 意图。Infrastructure Manager 创建或更新 Deployment、Service 等运行载体,xDS Translator 再生成 Envoy 能理解的配置并通过 Delta xDS 下发。Gateway API 对象不会直接写进 Envoy bootstrap,Kubernetes Service Available 也不代表某个 Route 已进入代理配置。
默认供应模型会让 Gateway 生命周期与受管 proxy 基础设施关联,但共享、合并和拓扑会受目标版本、EnvoyProxy 参数及平台设置影响。不能把“一 Gateway 永远对应一 Deployment”当成架构不变量,也不能假设创建 Gateway 必然得到公网 LoadBalancer。
安装前先锁定四方兼容关系
一次可审计安装至少要固定 Kubernetes、Gateway API channel、Envoy Gateway 和 Envoy Proxy 四个维度。下面以仍在支持期内的 Envoy Gateway v1.8.2 为可执行基线:它随附 Gateway API v1.5.1,支持的 Kubernetes 版本以 Envoy Gateway 兼容矩阵 为准。团队升级这个基线时要连同 chart、CRD、Envoy 镜像和兼容矩阵一起改,不把 /latest/ 开发文档、浮动镜像或 Experimental channel 混入生产。
export ENVOY_GATEWAY_VERSION='v1.8.2'
export GATEWAY_API_CHANNEL='standard'
kubectl version
helm version
kubectl get crd gateways.gateway.networking.k8s.io -o yaml 2>/dev/null || true
kubectl get crd envoyproxies.gateway.envoyproxy.io -o yaml 2>/dev/null || true先回答 CRD 所有权:
平台未管理 Gateway API CRD时,可由独立 CRD chart 安装 Gateway API 与 Envoy Gateway CRD。云平台已经管理兼容 Gateway API CRD 时,继续让平台持有它,只安装 Envoy Gateway CRD,并在主 chart 关闭 CRD 安装。不让平台组件、独立 CRD chart 与主 chart 轮流覆盖同一 cluster-scoped CRD。
把 CRD 渲染、审查、dry-run、diff 与应用分开:
helm template eg-crds oci://docker.io/envoyproxy/gateway-crds-helm \
--version "${ENVOY_GATEWAY_VERSION}" \
--set crds.gatewayAPI.enabled=true \
--set "crds.gatewayAPI.channel=${GATEWAY_API_CHANNEL}" \
--set crds.envoyGateway.enabled=true > /tmp/eg-crds.yaml
kubectl apply --server-side --dry-run=server -f /tmp/eg-crds.yaml
kubectl diff --server-side -f /tmp/eg-crds.yaml || true
kubectl apply --server-side -f /tmp/eg-crds.yaml若 Gateway API CRD 由平台持有,把 crds.gatewayAPI.enabled 设为 false,并先用目标兼容矩阵核对平台提供的 bundle、channel、served/storage versions。然后安装 controller,明确关闭主 chart 的 CRD 管理:
helm install eg oci://docker.io/envoyproxy/gateway-helm \
--version "${ENVOY_GATEWAY_VERSION}" \
--namespace envoy-gateway-system \
--create-namespace \
--set crds.enabled=false
kubectl wait --timeout=5m -n envoy-gateway-system \
deployment/envoy-gateway --for=condition=Available
kubectl get pods -n envoy-gateway-system -o wide
kubectl logs -n envoy-gateway-system deploy/envoy-gateway --tail=100这些命令是隔离集群的执行模板。远程 OCI chart、镜像和 CRD 都要在企业代理、私有镜像与制品签名策略下重新验证;云集群随后创建 Gateway 可能供应计费的 LoadBalancer。安装完成后检查 controller Pod 是否满足团队要求的非 root、只读根文件系统、seccomp、资源限额和 NetworkPolicy,而不是把 chart 默认值视为永久安全承诺。
从 GatewayClass 到受管 Envoy
Envoy Gateway v1.8 的控制器名是 gateway.envoyproxy.io/gatewayclass-controller。这个值是 GatewayClass 与控制器之间的身份契约,不是 Deployment 名称;升级其他发行线时先检查版本化文档和安装结果:
kubectl get gatewayclass -o yaml
kubectl get crd envoyproxies.gateway.envoyproxy.io -o yaml
kubectl api-resources --api-group=gateway.envoyproxy.ioHelm 安装只让 controller 运行,并不等于已经有可用入口类。把控制器名写入受版本控制的 GatewayClass 清单:
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
name: eg-managed
spec:
controllerName: gateway.envoyproxy.io/gatewayclass-controllerkubectl apply --server-side --dry-run=server -f gatewayclass.yaml
kubectl apply --server-side -f gatewayclass.yaml
kubectl get gatewayclass eg-managed -o yaml当前 generation 必须出现 Accepted=True。controllerName 不匹配时,API Server 仍会保存对象,但 Envoy Gateway 不会为它供应数据面;同一 Envoy Gateway 实例可接纳多少个匹配类、冲突时如何报告,也要以目标发行线的 Gateway API Support 文档和隔离集群实验为准,不能从历史设计文档推断。
如果团队需要改变数据面副本、Service 类型、Pod 模板或共享模型,通过 EnvoyProxy CR 配置。Gateway.spec.infrastructure.parametersRef 适合每个 Gateway 拥有不同数据面配置;GatewayClass.spec.parametersRef 会让同一类的 Gateway 共享基础配置,官方在需要差异化基础设施时并不推荐后者。类级引用还要显式写 namespace,而 Gateway 级引用只能指向同命名空间对象。这里的 group、kind、name 和 namespace 任一错误都可能让对象拒绝接纳,而不是悄悄退回默认配置。
先创建参数对象,再创建引用它的 Gateway,避免 reconcile 期间短暂采用默认基础设施:
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: EnvoyProxy
metadata:
name: eg-public-proxy
namespace: gateway-system
spec:
provider:
type: Kubernetes
kubernetes:
envoyDeployment:
replicas: 3
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: eg-public
namespace: gateway-system
spec:
gatewayClassName: eg-managed
infrastructure:
parametersRef:
group: gateway.envoyproxy.io
kind: EnvoyProxy
name: eg-public-proxy
listeners:
- name: http
protocol: HTTP
port: 80EnvoyProxy 属于 Envoy Gateway 扩展 API,字段和默认值会随发行线演进,所以让目标集群解释实际 Schema:
kubectl explain envoyproxy --api-version=gateway.envoyproxy.io/v1alpha1
kubectl explain envoyproxy.spec --api-version=gateway.envoyproxy.io/v1alpha1
kubectl explain gatewayclass.spec.parametersRef将 EnvoyProxy 清单与 Helm values 一起版本化,使用 server-side dry-run 和 diff 审查。不要直接改受管 Envoy Deployment:下一次 reconcile 会覆盖漂移,且手工修改无法成为可重建的架构合同。
GatewayClass 的成功证据是目标 controller 对当前 generation 报告 Accepted=True。随后创建 Gateway 时,Envoy Gateway 才开始生成受管基础设施与 xDS;此时要同时观察三组对象:
kubectl get gatewayclass -o yaml
kubectl get gateway -A -o yaml
kubectl get deployment,service,pod -A \
-l gateway.envoyproxy.io/owning-gateway-name标签与资源命名以目标版本实际产物为准;若选择器没有结果,先从 Gateway status、controller 日志与受管资源 ownerReferences 反查,不要依赖网上某个旧版本的生成名称。
双上游实验:从期望状态走到真实流量
实验继续使用 gateway-system、app-team、backend-team 三个命名空间。准备两个可区分上游,镜像固定为团队批准的摘要:
apiVersion: v1
kind: Namespace
metadata:
name: gateway-system
---
apiVersion: v1
kind: Namespace
metadata:
name: app-team
labels:
gateway-access: eg-public
---
apiVersion: v1
kind: Namespace
metadata:
name: backend-team
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: catalog-blue
namespace: app-team
spec:
replicas: 2
selector:
matchLabels: {app: catalog-blue}
template:
metadata:
labels: {app: catalog-blue}
spec:
containers:
- name: echo
image: <approved-echo-image>@sha256:<digest>
args: ["--text=upstream=blue"]
ports: [{name: http, containerPort: 8080}]
readinessProbe:
httpGet: {path: /, port: http}
resources:
requests: {cpu: 25m, memory: 32Mi}
limits: {memory: 128Mi}
---
apiVersion: v1
kind: Service
metadata:
name: catalog-blue
namespace: app-team
spec:
selector: {app: catalog-blue}
ports: [{name: http, port: 8080, targetPort: http}]
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: catalog-green
namespace: app-team
spec:
replicas: 2
selector:
matchLabels: {app: catalog-green}
template:
metadata:
labels: {app: catalog-green}
spec:
containers:
- name: echo
image: <approved-echo-image>@sha256:<digest>
args: ["--text=upstream=green"]
ports: [{name: http, containerPort: 8080}]
readinessProbe:
httpGet: {path: /, port: http}
resources:
requests: {cpu: 25m, memory: 32Mi}
limits: {memory: 128Mi}
---
apiVersion: v1
kind: Service
metadata:
name: catalog-green
namespace: app-team
spec:
selector: {app: catalog-green}
ports: [{name: http, port: 8080, targetPort: http}]kubectl apply -f upstreams.yaml
kubectl rollout status -n app-team deploy/catalog-blue
kubectl rollout status -n app-team deploy/catalog-green
kubectl run -n app-team direct-check --rm -i --restart=Never \
--image='<approved-curl-image>@sha256:<digest>' -- \
sh -c 'curl -fsS http://catalog-blue:8080/; curl -fsS http://catalog-green:8080/'直连应分别返回 upstream=blue 和 upstream=green。接着使用安装后被 Envoy Gateway 接纳的 GatewayClass 名称:
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: eg-public
namespace: gateway-system
spec:
gatewayClassName: eg-managed
listeners:
- name: http
protocol: HTTP
port: 80
hostname: api.example.test
allowedRoutes:
namespaces:
from: Selector
selector:
matchLabels:
gateway-access: eg-public
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: catalog
namespace: app-team
spec:
parentRefs:
- name: eg-public
namespace: gateway-system
sectionName: http
hostnames: [api.example.test]
rules:
- matches:
- path: {type: PathPrefix, value: /catalog}
backendRefs:
- name: catalog-blue
port: 8080
weight: 9
- name: catalog-green
port: 8080
weight: 1kubectl apply -f gateway-route.yaml
kubectl get gateway -n gateway-system eg-public -o yaml
kubectl get httproute -n app-team catalog -o yaml
kubectl get deployment,service,pod -A | grep -i envoy先等当前 generation 的 Gateway Accepted=True、Programmed=True,再在 Route 的目标 parent 下确认 Accepted=True、ResolvedRefs=True。之后取得 status.addresses 报告的实际入口并发送请求:
export GATEWAY_ADDRESS='<reachable-status-address>'
for i in $(seq 1 50); do
curl -fsS -H 'Host: api.example.test' \
"http://${GATEWAY_ADDRESS}/catalog"
done | sort | uniq -c样本应以 blue 为主并能看到 green,但短样本不是精确 90/10 的统计证明。生产灰度要以足够时间窗口、请求量、置信区间和业务指标判定。更重要的是把 Route generation、Envoy Gateway 日志、受管 Envoy readiness、访问日志中的 Route/cluster 身份与响应体关联起来,这才能证明配置确实到达数据面并处理了请求。
正确路由之外,还要验证错误如何停止
错误引用不应偷偷回退
把 catalog-green 改成 catalog-missing。HTTPRoute 仍可能被 parent 接受,但应在目标 parent 下出现 ResolvedRefs=False;对于本应转发到这个无效 backendRef 的请求,Gateway API 规范要求返回 HTTP 500,而不是自动回退到另一个后端。检查顺序是:
kubectl describe httproute -n app-team catalog
kubectl get service,endpointslice -n app-team
kubectl logs -n envoy-gateway-system deploy/envoy-gateway --since=10m修复名称后,先等待 condition 的 observedGeneration 追上 metadata.generation,再请求数据面。旧 generation 的绿色状态没有证明力。
Route 跨命名空间附着由 listener 决定
移除 app-team 的 gateway-access: eg-public 标签后,listener 的 namespace selector 不再接受该 Route。此时 Accepted=False 的原因属于 parent attachment,不需要也不能靠 ReferenceGrant 修复。恢复标签或调整 allowedRoutes 后,再验证 listener 的 attachedRoutes 与 Route condition。
后端跨命名空间默认拒绝
把 green 上游迁到 backend-team,在 HTTPRoute 的 backendRef 中写 namespace: backend-team。没有授权时应出现 ResolvedRefs=False。授权由后端所有者在目标命名空间创建:
apiVersion: gateway.networking.k8s.io/v1
kind: ReferenceGrant
metadata:
name: allow-app-catalog
namespace: backend-team
spec:
from:
- group: gateway.networking.k8s.io
kind: HTTPRoute
namespace: app-team
to:
- group: ""
kind: Service
name: catalog-greenkubectl get referencegrant -n backend-team -o yaml
kubectl apply -f allow-app-catalog.yaml
kubectl get httproute -n app-team catalog -w等待 ResolvedRefs=True 后重放请求,再删除 grant 验证引用被撤销。Envoy Gateway 必须监视 grant 的变化并重新计算配置;若删除后仍然成功,先确认目标命名空间是否存在其他加法 grant,再检查 controller reconcile 与代理配置版本。
项目接入要保存声明、状态与请求三类证据
建议把平台基线和服务发布物拆开:
platform/envoy-gateway/
helm-values.yaml
crd-ownership.md
gatewayclasses/
envoyproxies/
shared-gateways/
upgrade/
services/catalog/deploy/
service.yaml
httproute.yaml
policies/
smoke.sh
rollback.mdCI 先对 CRD 与 Route 做 server-side dry-run、策略准入和 diff;CD 应按目标 parent 精确等待新鲜 conditions,而不是取 status.parents[0];发布验证再请求正确 Host/Path、错误 Host、错误 backend 与未授权 backend。证据归档保留对象 generation、controller 版本、Gateway address、受管 Envoy image 摘要、请求 ID 和上游身份,并对 xDS、日志与 header 做脱敏。
Envoy Gateway controller 的 ServiceAccount、GatewayClass/EnvoyProxy 与共享 Gateway 由平台团队管理;应用团队只写本命名空间 HTTPRoute 和经批准的 policy;跨命名空间 Service/Secret 由目标 owner 用 ReferenceGrant 授权。手工修改受管 Deployment、Service 或 Envoy admin 配置都应由漂移检查阻断。
三类策略先按流量方向理解
Envoy Gateway 提供的策略是实现扩展,不是 Kubernetes 原生稳定 Gateway API 资源。目标版本中常见三类职责如下:
ClientTrafficPolicy 处理客户端到 Envoy listener 的 TLS、连接、客户端地址、路径规范化与 HTTP 协议行为。BackendTrafficPolicy 处理 Envoy 到后端的负载均衡、超时、重试、熔断、健康检查、限流、缓冲与压缩。SecurityPolicy 处理认证、授权、CORS 与外部鉴权等安全行为。
这些 CRD 处于快速演进的扩展 API。不要在模板中凭记忆写 targetSelectors、sectionName、mergeType 或数组合并规则;先用目标集群核对:
kubectl api-resources --api-group=gateway.envoyproxy.io
kubectl explain backendtrafficpolicy.spec --api-version=gateway.envoyproxy.io/v1alpha1
kubectl explain clienttrafficpolicy.spec --api-version=gateway.envoyproxy.io/v1alpha1
kubectl explain securitypolicy.spec --api-version=gateway.envoyproxy.io/v1alpha1
kubectl get backendtrafficpolicy,clienttrafficpolicy,securitypolicy -A -o yaml策略实验每次只改变一个变量。以 JWT 或外部鉴权为例,至少请求有效凭证、缺失凭证、错误 issuer/audience、JWKS 或鉴权服务不可达、Secret 轮换五条路径;只得到一个 200 不能证明 fail-closed。以重试为例,要同时测后端超时、非幂等请求和部分故障,记录总后端请求数,防止重试把一次入口流量放大成多次后端压力。
策略生效需要三层证据:policy status 中目标引用对应的 Accepted condition 与当前 generation、Envoy Gateway 生成配置或受控翻译输出、Envoy 数据面的正反请求。Accepted=False 时先按 reason 区分目标不存在、类型不支持、冲突或字段无效;policy 没有目标条目时检查 namespace、targetRef/targetRefs、控制器 watch scope 和 RBAC。更具体的 Route/listener policy 是否覆盖、继承或合并父级,只能依据目标发行线文档、CRD Schema 与生成 xDS 判断,不能冒充 Gateway API 的跨实现通用规则。
扩展能力越接近 xDS,权限越接近集群根钥匙
当原生 policy 不够时,Envoy Gateway 还可能提供 Wasm、Extension Server、External Processing、Lua、Dynamic Modules 与 EnvoyPatchPolicy 等扩展。它们增加能力,也同时增加代码执行、供应链、延迟、可用性和升级风险。
EnvoyPatchPolicy 直接对生成 xDS 做补丁,默认禁用且不适合作为常规配置层。拥有该权限的主体可能注入任意代理配置,形成 SSRF、凭证读取、拓扑暴露甚至代码执行风险。若不得不用,只能在隔离集群以无害响应头补丁做正反实验,先导出原始配置,删除 policy 后验证配置恢复;RBAC、admission、审计与 extension allowlist 必须同时收紧。
Wasm 来源使用 HTTP 时固定 SHA-256,使用 OCI 时固定 digest 并限制 registry。故意提供错误摘要,分别验证 failOpen=false 阻断和 failOpen=true 放行:前者保护安全策略连续性但可能降低可用性,后者保护可用性却可能绕过鉴权或合规逻辑。这个选择必须按扩展用途作出,不能全局统一。
Extension Server 会在 xDS 下发前通过 gRPC hook 修改配置。要模拟超时、崩溃与无效输出,观察 controller status、last-known-good 配置、重试和数据面行为。控制该服务等价于拥有高权限数据面配置能力;它的身份、网络、版本、延迟 SLO、回退与供应链都必须独立治理。
Envoy admin、xDS dump 和翻译输出可能包含内部拓扑、header、identity 与 Secret 元数据。只允许从受控管理网络短时访问,导出后放入受限临时目录并脱敏销毁。不要为排障创建公网 Service,也不要把长期 port-forward 当作访问控制。
503 到底停在哪一层
排障时按状态流分层,而不是在所有 Pod 里随机搜索:
| 现象 | 第一层证据 | 常见原因 | 下一步 |
|---|---|---|---|
| GatewayClass 未接纳 | GatewayClass conditions | controllerName 不匹配、参数无效、类冲突 | controller scope、日志与 EnvoyProxy 引用 |
| Gateway 未 Programmed | Gateway/listener conditions | 基础设施供应、地址、listener 或证书失败 | 受管资源、事件、controller 日志 |
Route Accepted=False | 目标 parent condition | allowedRoutes、sectionName、hostname/kind 不匹配 | 修复双向附着 |
Route ResolvedRefs=False | backendRef/Secret 与 grant | 名称端口错误或跨 namespace 未授权 | Service/EndpointSlice/ReferenceGrant |
| condition 正常但持续 503 | Envoy 访问日志、cluster health | Endpoint 不健康、网络拒绝、xDS 尚未进入该代理 | readiness、配置版本、Endpoint 与 NetworkPolicy |
| 只有部分代理失败 | Pod 级配置与指标 | xDS 收敛差异、滚动升级、单 Pod 资源或网络问题 | 按 Pod 对比 ACK/NACK、版本与请求 |
| 策略行为不一致 | policy status + xDS + 正反请求 | target/优先级/合并、依赖故障或旧 generation | 核对实际 target 和依赖 fail 模式 |
数据面证据至少包括入口状态码、上游状态码、request ID、命中 Route/cluster、Envoy Pod 身份和配置 generation。Deployment Available、Gateway Programmed=True、Service External-IP 出现或一次 200 都不能单独证明上线完成。
容量设计要同时预算控制面和数据面
控制面容量主要受被观察对象数、Route/backend/Endpoint 规模、配置变更频率、reconcile 队列、翻译开销和 xDS 推送影响;数据面容量受连接数、TLS、HTTP/2/3、请求体缓冲、过滤器、Wasm、日志、重试、镜像与上游健康影响。二者峰值往往在发布或故障时叠加:Endpoint 大量变化触发翻译与推送,同时代理因重试和健康切换承受额外负载。
压测至少包含稳定流量、配置风暴、代理滚动、单后端故障、外部鉴权/限流依赖故障和大请求体。判断指标使用趋势与预算:配置 generation 在发布窗口内收敛,xDS NACK 不持续增长,代理饱和前仍有冗余,重试后的后端请求放大不突破预算,拒绝与排队符合 SLO。示例资源值只能用于实验,生产 requests/limits、HPA 和副本数来自基线测量与故障冗余。
共享 Envoy 数据面节省负载均衡器与 Pod,却扩大租户故障域和权限面;独立 Gateway/数据面隔离更清楚,但会增加 LB、IP、Pod、日志和证书成本。需要按租户信任、流量规模、变更频率、合规与事故半径选择,而不是只比较 Pod 数。
升级顺序是 CRD 先行,回退不是一条 Helm 命令
升级前保存 CRD、所有 Gateway API/Envoy Gateway CR、Helm values、受管镜像摘要和关键 xDS 结构。Helm 不会自动升级 chart /crds 中的 CRD;新 controller 可能依赖新 Schema,所以要先升级兼容的 Gateway API 与 Envoy Gateway CRD,再升级 controller。
helm get values eg -n envoy-gateway-system -a > /tmp/eg-values-before.yaml
kubectl get crd -o yaml > /tmp/crds-before.yaml
kubectl get gatewayclass,gateway,httproute,referencegrant -A -o yaml \
> /tmp/gateway-api-before.yaml
kubectl get envoyproxy,backendtrafficpolicy,clienttrafficpolicy,securitypolicy \
-A -o yaml > /tmp/eg-api-before.yaml
export TARGET_ENVOY_GATEWAY_VERSION='<approved-target-release>'
helm template eg-crds oci://docker.io/envoyproxy/gateway-crds-helm \
--version "${TARGET_ENVOY_GATEWAY_VERSION}" \
--set crds.gatewayAPI.enabled=true \
--set crds.envoyGateway.enabled=true > /tmp/eg-crds-next.yaml
kubectl apply --server-side --dry-run=server -f /tmp/eg-crds-next.yaml
kubectl diff --server-side -f /tmp/eg-crds-next.yaml || true--force-conflicts 会接管字段所有权,不因官方示例使用就自动适合你的平台。先核对 field manager、provider-managed CRD、removed/deprecated fields、conversion 与 storedVersions,再在副本集群验证。升级后重跑双上游、错误引用、Route namespace 拒绝、ReferenceGrant 创建和撤销、TLS、策略依赖故障、代理滚动与 xDS ACK/NACK。
回退必须分层准备:应用 Route/Policy 回退到上一份已验证清单;高风险扩展可先删除以恢复原生翻译链;controller 回退要确认旧版本能读取现有 CR;CRD 回退还要处理 storage version 与已移除字段。只有这些条件成立,helm rollback 才可能成为步骤之一,而不是完整方案。
实际演练先记录 release revision,再恢复应用对象并观察数据面;只有确认旧 controller 与当前 CRD、stored object 兼容后,才回退 chart:
helm history eg -n envoy-gateway-system
kubectl apply --server-side -f artifacts/previous/routes-and-policies/
# 先确认新鲜 condition 与真实请求,再决定是否回退 controller。
helm rollback eg <previous-compatible-revision> -n envoy-gateway-system
kubectl rollout status -n envoy-gateway-system deploy/envoy-gateway
kubectl get gatewayclass,gateway,httproute -A -o yamlhelm rollback 不会把已经单独应用的 CRD 还原,也不会自动删除新版本写入对象的字段。若旧 controller 不能读取当前对象,应停止回退并以前向修复或经过数据迁移验证的恢复方案处理;强行覆盖 CRD 可能让整个集群的 Gateway API 对象无法解码。回退后还要重跑双上游、错误引用、namespace 拒绝、ReferenceGrant 撤销、策略依赖故障与逐 Pod 配置收敛,不能以 Deployment Available 结束。
安全和成本治理决定能否长期运行
Envoy Gateway controller 通常需要观察多命名空间对象、读取 Secret 并管理受管基础设施。多租户集群要评估 namespace mode、每租户 controller、独立 Gateway 与 RoleBinding 收敛;平台、入口、应用和后端 owner 的权限分开,普通用户不能写 status,也不能获得 EnvoyPatchPolicy、Extension Server 或任意 Secret 读取能力。
Proxy egress 只允许 DNS、业务 backend、JWKS/IdP、外部鉴权、限流、OTel/日志和受控扩展仓库等明确目标。TLS 私钥进入 Kubernetes Secret 时,还要有 etcd 静态加密、RBAC、轮换和审计。自定义 EnvoyProxy Pod template、镜像或 bootstrap 后,重新检查非 root、只读文件系统、seccomp/AppArmor/SELinux、capability、NetworkPolicy 与 admin 绑定没有被放宽。
软件许可不等于运行零成本。账单要覆盖 Kubernetes 节点、LoadBalancer、公网 IP、跨区与出口流量、DNS/证书、日志与指标、外部鉴权/限流、Wasm registry、备份、扫描和冗余环境。成本标签应关联 GatewayClass、Gateway owner、环境和数据面拓扑;删除实验时先删 Gateway 与生成的 LoadBalancer,再卸载 chart,最后复查云资源、PVC、日志索引、临时 xDS 导出与费用残留。
上线前最后复核
兼容矩阵、Gateway API channel、Kubernetes 与 Envoy Proxy 组合按目标发行线确认。Gateway API CRD 与 Envoy Gateway CRD 只有一个明确 owner,dry-run、diff 和 field manager 已审查。GatewayClass、Gateway、listener、Route 与 policy conditions 都对应当前 generation。
两个上游直连正常,真实入口能关联请求 ID、Route、Envoy Pod、cluster 与上游身份。错误 backend、Route namespace 不被允许、跨 namespace backend 未授权都稳定拒绝。Policy 同时通过 status、生成配置和数据面正反请求,外部依赖故障语义已验证。
Patch、Wasm、Extension Server 等扩展按代码执行和供应链高风险治理,具备删除回退路径。代理 admin、xDS、日志、Trace 与 Secret 元数据没有暴露到非受控网络或普通工单。控制面收敛与数据面容量都经过发布、故障和滚动场景测量,重试放大在预算内。
升级按 CRD、controller、业务回归顺序演练,旧 controller 与 stored object 的兼容性已证明。清理后没有 LoadBalancer、临时授权、调试端口、xDS 导出、浮动扩展制品与费用残留。
