本页面介绍了如何部署 Kubernetes Gateway 资源,以将入站流量负载均衡到单个 Google Kubernetes Engine (GKE) 集群。
如需部署 Gateway 以跨多个集群(或舰队)对入站流量进行负载均衡,请参阅部署多集群 Gateway。准备工作
在开始之前,请确保您已执行以下任务:
- 启用 Google Kubernetes Engine API。 启用 Google Kubernetes Engine API
- 如果您要使用 Google Cloud CLI 执行此任务,请安装并初始化 gcloud CLI。 如果您之前安装了 gcloud CLI,请运行
gcloud components update
以获取最新版本。
GKE Gateway Controller 要求
- 对于标准版,需要 GKE 1.24 或更高版本。
- 对于 Autopilot,需要 GKE 1.26 或更高版本。
- Google Cloud CLI 407.0.0 版或更高版本。
- 仅 VPC 原生集群支持 Gateway API。
- 如果您使用的是内部 GatewayClass,则必须启用代理专用子网。
- 集群必须启用
HttpLoadBalancing
插件。 - 如果您使用的是 Istio,则必须将 Istio 升级到以下版本之一:
- 1.15.2 或更高版本
- 1.14.5 或更高版本
- 1.13.9 或更高版本。
- 如果您使用的是共享 VPC,则需要在宿主项目中将
Compute Network User
角色分配给服务项目的 GKE 服务账号。
限制和局限
GKE GatewayClass 支持不同的功能,具体取决于它们使用的负载均衡器。如需详细了解每个 GatewayClass 支持的不同功能,请参阅 GatewayClass 功能。
您不能使用 FrontendConfig 或 BackendConfig 配置网关,必须使用政策。
GKE 网关的行为与 Ingress 不同,因为网关不会推断健康检查参数。如果您的 Service 没有为
GET /
请求返回 200,或者您有其他调整的 Pod 就绪性检查,则需要为 Service 配置 HealthCheckPolicy。您可以在 Google Cloud 控制台中查看 GKE 为网关创建的负载均衡器资源,但这些资源不会引用它们所连接的网关或 GKE 集群。
您无法使用网关自动生成 Google 管理的 SSL 证书,但可以手动创建和引用 Google 管理的 SSL 证书。如需了解详情,请参阅保护网关安全。
HTTPRoute 是唯一受支持的路由类型。不支持 TCPRoute、UDPRoute 和 TLSRoute。如需查看 GKE Gateway Controller 支持的字段列表,请参阅 GatewayClass 功能。
使用网关或路径重定向的自定义请求和响应标头以及使用网关的网址重写仅适用于 GKE 1.27 版或更高版本。
- 对于使用网关和路径重定向的自定义请求和响应标头以及使用网关的网址重写,不支持 GatewayClass
gke-l7-gxlb
。
不支持以下 Google Cloud 标头变量:
cdn_cache_id
(GKE 网关不支持 Cloud CDN)cdn_cache_status
(GKE 网关不支持 Cloud CDN)origin_request_header
(GKE 网关不支持 CORS)
GKE Gateway 不支持 Cloud CDN 负载均衡功能。
不支持双向 TLS 自定义标头(GKE 网关不支持 mTLS)
Google Cloud 传统应用负载均衡器限制适用于 GKE 网关,还有一项额外的限制:
- 您不能在后端服务中配置自定义主机响应标头。
路径重定向和网址重写是互斥的,您不能在同一规则中同时使用这两个过滤条件。
Cloud Load Balancing 不支持将流量重定向到其他端口。如需查看 GKE Gateway Controller 支持的字段列表,请参阅 GatewayClass 功能。
GKE 网关不支持通配符、正则表达式和动态网址。
如果您指定具有区域级外部网关类的网关,则控制器会预配内部 IP 地址而不是外部地址。 如需了解如何将已命名的地址与区域级外部应用负载均衡器结合使用,请参阅部署区域级外部网关。
网关利用独立 NEG 来预配网络端点组。为了确保网关控制器正确协调负载均衡器配置,您无法修改作为网关一部分的 Service 的
cloud.google.com/neg
注解。GKE Gateway 不支持引用 GKE Ingress 也引用的 Service。
将
Gateway
配置为预配 IP 地址时,不支持更改Gateway.spec.gatewayClass
。为确保网关控制器正确协调负载均衡器,请删除现有网关,并使用更新后的gatewayClass
值重新部署清单。不支持
networking.gke.io/app-protocols
注解。请改用appProtocol
字段来实现相同的结果。
在集群中启用 Gateway API
在 GKE 中使用 Gateway 资源之前,您的集群必须启用 Gateway API。
创建启用 Gateway API 的新集群
从 GKE 1.26 版开始,GKE 在 Autopilot 集群上支持 Gateway API。如果您在 GKE 1.26 及更高版本上创建新的 Autopilot 集群,Gateway API 是默认启用的。对于 GKE 1.25 及更低版本上的现有集群,Gateway API 默认停用。
Autopilot
创建启用 Gateway API 的新 GKE Autopilot 集群:
gcloud container clusters create-auto CLUSTER_NAME \
--location=CLUSTER_LOCATION \
--release-channel=RELEASE_CHANNEL \
--cluster-version=VERSION
替换以下内容:
CLUSTER_NAME
:集群的名称。CLUSTER_LOCATION
:新集群的 Compute Engine 区域或可用区。RELEASE_CHANNEL
:发布渠道的名称。VERSION
:GKE 版本,必须为 1.26 或更高版本。您还可以使用--release-channel
标志来选择发布渠道。发布渠道必须具有默认版本 1.26 或更高版本。
Standard
使用 GKE Standard 时,Gateway API 由 --gateway-api
标志控制。启用时使用值 standard,停用时则使用值 disabled。
创建启用 Gateway API 的新 VPC 原生 GKE 集群:
gcloud container clusters create CLUSTER_NAME \
--gateway-api=standard \
--cluster-version=VERSION \
--location=CLUSTER_LOCATION
替换以下内容:
RELEASE_CHANNEL
:发布渠道的名称。CLUSTER_NAME
:集群的名称。VERSION
:GKE 版本,必须为 1.24 或更高版本。您还可以使用--release-channel
标志来选择发布渠道。发布渠道必须具有默认版本 1.24 或更高版本。CLUSTER_LOCATION
:新集群的 Compute Engine 区域或可用区。
--gateway-api=standard
标志指示 GKE 使用集群安装 v1beta1
CRD。
在现有集群上启用 Gateway API
确保您的 Autopilot 集群版本为 1.26 或更高版本,并且 Standard 集群版本为 1.24 或更高版本。
如需在现有 GKE 集群(Autopilot 或 Standard)上启用 Gateway API,请使用以下命令:
gcloud container clusters update CLUSTER_NAME \
--location=CLUSTER_LOCATION\
--gateway-api=standard
替换以下内容:
CLUSTER_NAME
:现有集群的名称。CLUSTER_LOCATION
:集群的 Compute Engine 区域或可用区。
--gateway-api=standard
标志指示 GKE 使用集群安装 v1beta1
CRD。
验证集群
创建或升级集群后,GKE Gateway Controller 会自动安装 GatewayClass。控制器可能需要几分钟时间才能识别 CRD 并安装 GatewayClass。
确认已在 GKE 控制平面中启用 Gateway API:
gcloud container clusters describe CLUSTER_NAME \ --location=CLUSTER_LOCATION \ --format json
输出类似于以下内容:如果此输出为空,请再次运行集群更新命令。
"networkConfig": { ... "gatewayApiConfig": { "channel": "CHANNEL_STANDARD" }, ... },
确认您的集群中安装了 GatewayClass:
kubectl get gatewayclass
输出类似于以下内容:
NAME CONTROLLER ACCEPTED AGE gke-l7-global-external-managed networking.gke.io/gateway True 16h gke-l7-regional-external-managed networking.gke.io/gateway True 16h gke-l7-gxlb networking.gke.io/gateway True 16h gke-l7-rilb networking.gke.io/gateway True 16h
如需了解每个 GatewayClass 的功能,请参阅 GatewayClass 功能。
部署内部网关
内部网关公开只能从 VPC 或连接到 VPC 的网络访问的应用。
部署区域级内部网关
以下示例展示了如何部署区域性内部网关,以便实现在特定地理区域内服务之间的高效安全通信。
配置代理专用子网
您必须先配置代理专用子网,然后才能创建使用内部应用负载均衡器的网关。在使用内部应用负载均衡器的 VPC 中,每个区域都必须具有一个代理专用子网。此子网为负载均衡器代理提供了内部 IP 地址。
创建代理专用子网:
gcloud compute networks subnets create SUBNET_NAME \ --purpose=REGIONAL_MANAGED_PROXY \ --role=ACTIVE \ --region=COMPUTE_REGION \ --network=VPC_NETWORK_NAME \ --range=CIDR_RANGE
替换以下内容:
SUBNET_NAME
:代理专用子网的名称。COMPUTE_REGION
:代理专用子网的区域。VPC_NETWORK_NAME
:包含子网的 VPC 网络的名称。CIDR_RANGE
:子网的主要 IP 地址范围。使用的子网掩码长度不得超过/26
,以确保至少有 64 个 IP 地址可用于该区域中的代理。建议的子网掩码为/23
。
验证代理专用子网:
gcloud compute networks subnets describe SUBNET_NAME \ --region=COMPUTE_REGION
输出类似于以下内容:
... gatewayAddress: 10.1.1.1 ipCidrRange: 10.1.1.0/24 kind: compute#subnetwork name: proxy-subnet network: https://www.googleapis.com/compute/v1/projects/PROJECT_NAME/global/networks/default privateIpGoogleAccess: false privateIpv6GoogleAccess: DISABLE_GOOGLE_ACCESS purpose: REGIONAL_MANAGED_PROXY region: https://www.googleapis.com/compute/v1/projects/PROJECT_NAME/regions/REGION role: ACTIVE selfLink: https://www.googleapis.com/compute/v1/projects/PROJECT_NAME/regions/REGION/subnetworks/proxy-subnet state: READY
创建网关
网关资源表示在 Kubernetes 中路由流量的数据层面。网关可表示许多不同类型的负载均衡和路由,具体取决于派生网关的 GatewayClass。如需详细了解网关资源,请参阅网关资源说明或 API 规范。
在这种情况下,GKE 集群的管理员需要创建一个网关,可供不同团队用于在内部公开其应用。管理员部署网关,应用团队独立部署其路由并将路由连接到此网关。
将以下网关清单保存到名为
gateway.yaml
的文件中:kind: Gateway apiVersion: gateway.networking.k8s.io/v1beta1 metadata: name: internal-http spec: gatewayClassName: gke-l7-rilb listeners: - name: http protocol: HTTP port: 80
此清单包含以下字段:
gatewayClassName: gke-l7-rilb
:指定派生此网关的 GatewayClass。gke-l7-rilb
对应于内部应用负载均衡器。port: 80
指定网关仅开放端口 80 来监听 HTTP 流量。
在您的集群中部署网关:
kubectl apply -f gateway.yaml
验证网关是否已正确部署。部署其所有资源可能需要几分钟时间。
kubectl describe gateways.gateway.networking.k8s.io internal-http
输出类似于以下内容:
Name: internal-http Namespace: default Spec: Gateway Class Name: gke-l7-rilb Listeners: Allowed Routes: Kinds: Group: gateway.networking.k8s.io Kind: HTTPRoute Namespaces: From: Same Name: http Port: 80 Protocol: HTTP Status: Addresses: Type: IPAddress Value: 192.168.1.14 Conditions: Last Transition Time: 1970-01-01T00:00:00Z Message: Waiting for controller Reason: NotReconciled Status: False Type: Scheduled Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal ADD 92s networking.gke.io/gateway test/internal-http Normal UPDATE 45s (x3 over 91s) networking.gke.io/gateway test/internal-http Normal SYNC 45s networking.gke.io/gateway SYNC on test/internal-http was a success
此时,您的集群中部署了一个网关,该网关已预配负载均衡器和 IP 地址。但是,该网关没有路由,因此不知道应该如何将流量发送到后端。如果没有路由,所有流量都会流向默认后端,这会返回 HTTP 404。接下来,您将部署应用和路由,告知网关如何到达应用后端。
部署演示应用
应用团队可以独立于网关的部署部署他们的应用和路由。在某些情况下,应用团队可能还希望拥有网关,并自行将其部署为专用于应用的资源。如需了解网关和路由的不同所有权模型,请参阅路由绑定。不过在此示例中,商店团队会部署其应用以及通过在上一部分中创建的 internal-http
网关公开其应用的附带 HTTPRoute。
HTTPRoute 资源有许多可配置的字段可用于流量匹配。如需了解 HTTPRoute 字段的说明,请参阅 API 规范。
将商店应用(store-v1、store-v2 和 store-german 部署)部署到您的集群:
kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/gke-networking-recipes/main/gateway/gke-gateway-controller/app/store.yaml
这将创建三个 Deployment 和三个 Service,分别名为 store-v1、store-v2 和 store-german。
验证应用已成功部署:
kubectl get pod
应用运行后,输出类似于以下内容:
NAME READY STATUS RESTARTS AGE store-german-66dcb75977-5gr2n 1/1 Running 0 38s store-v1-65b47557df-jkjbm 1/1 Running 0 14m store-v2-6856f59f7f-sq889 1/1 Running 0 14m
验证 Service 已部署:
kubectl get service
输出会显示每个商店 Deployment 的 Service:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE store-german ClusterIP 10.48.3.183 <none> 8080/TCP 4s store-v1 ClusterIP 10.48.2.224 <none> 8080/TCP 5s store-v2 ClusterIP 10.48.4.48 <none> 8080/TCP 5s
部署 HTTPRoute
路由资源定义了用于将流量从网关映射到 Kubernetes 后端的特定于协议的规则。HTTPRoute 资源会执行 HTTP 和 HTTPS 流量匹配和过滤,并且受所有 gke-l7
GatewayClass 支持。
在本部分中,您将部署一个 HTTPRoute,它会使用访问您的商店应用所需的路由规则对网关进行编程。
将以下 HTTPRoute 清单保存到名为
store-route.yaml
的文件中:kind: HTTPRoute apiVersion: gateway.networking.k8s.io/v1beta1 metadata: name: store spec: parentRefs: - kind: Gateway name: internal-http hostnames: - "store.example.com" rules: - backendRefs: - name: store-v1 port: 8080 - matches: - headers: - name: env value: canary backendRefs: - name: store-v2 port: 8080 - matches: - path: value: /de backendRefs: - name: store-german port: 8080
在集群中部署 HTTPRoute:
kubectl apply -f store-route.yaml
store
HTTPRoute 使用parentRefs
属性绑定到internal-http
网关:这些路由规则在底层的负载均衡器上配置,如下图所示:这些路由规则通过以下方式处理 HTTP 流量:
- 发送到
store.example.com/de
的流量路由到 Servicestore-german
。 - 发送到
store.example.com
且具有 HTTP 标头"env: canary"
的流量路由到 Servicestore-v2
。 - 发送到
store.example.com
的其余流量路由到 Servicestore-v1
。
- 发送到
验证 HTTPRoute 已部署:
kubectl describe httproute store
输出类似于以下内容:
Name: store Namespace: default Labels: <none> Annotations: <none> API Version: gateway.networking.k8s.io/v1beta1 Kind: HTTPRoute <...> Spec: Hostnames: store.example.com Parent Refs: Group: gateway.networking.k8s.io Kind: Gateway Name: internal-http Rules: Backend Refs: Group: Kind: Service Name: store-v1 Port: 8080 Weight: 1 Matches: Path: Type: PathPrefix Value: / Backend Refs: Group: Kind: Service Name: store-v2 Port: 8080 Weight: 1 Matches: Headers: Name: env Type: Exact Value: canary Path: Type: PathPrefix Value: / Backend Refs: Group: Kind: Service Name: store-german Port: 8080 Weight: 1 Matches: Path: Type: PathPrefix Value: /de Status: Parents: Conditions: Last Transition Time: 2022-11-01T04:18:52Z Message: Reason: Accepted Status: True Type: Accepted Last Transition Time: 2022-11-01T04:18:52Z Message: Reason: ReconciliationSucceeded Status: True Type: Reconciled Controller Name: networking.gke.io/gateway Parent Ref: Group: gateway.networking.k8s.io Kind: Gateway Name: internal-http Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal ADD 24m sc-gateway-controller default/store Normal SYNC 16m (x4 over 23m) sc-gateway-controller Bind of HTTPRoute "default/store" to ParentRef {Group: gateway.networking.k8s.io", <...>
验证 HTTPRoute 已绑定到网关:
kubectl describe gateway
输出类似于以下内容:
Name: internal-http Namespace: default Labels: <none> <...> Status: Addresses: Type: IPAddress Value: 10.128.15.203 Conditions: Last Transition Time: 2022-11-01T03:47:01Z Message: Reason: Scheduled Status: True Type: Scheduled Last Transition Time: 2022-11-01T03:47:01Z Message: Reason: Ready Status: True Type: Ready Listeners: Attached Routes: 1 Conditions: Last Transition Time: 2022-11-01T03:47:01Z Message: Reason: Ready Status: True Type: Ready Name: http Supported Kinds: Group: gateway.networking.k8s.io Kind: HTTPRoute <...>
将流量发送到应用
现在,网关、路由和应用已在集群中部署,您可以将流量传递到您的应用。
从网关检索 IP 地址,以便将流量发送到您的应用:
kubectl get gateways.gateway.networking.k8s.io internal-http -o=jsonpath="{.status.addresses[0].value}"
输出为一个 IP 地址。
在与集群连接的虚拟机 (VM) 实例上,通过 shell 将流量发送到此 IP 地址。为此,您可以创建一个虚拟机。这是必要的操作,因为网关具有内部 IP 地址,并且只能从 VPC 网络内部访问。由于
internal-http
是区域级负载均衡器,因此客户端 shell 必须与 GKE 集群位于同一区域。由于您没有 example.com 主机名,因此请手动设置主机标头,以便观察流量路由。首先尝试请求 store.example.com:
curl -H "host: store.example.com" VIP
将
VIP
替换为上一步中的 IP 地址。演示应用的输出显示了应用运行位置的相关信息:
{ "cluster_name": "gke1", "host_header": "store.example.com", "metadata": "store-v1", "node_name": "gke-gke1-pool-2-bd121936-5pfc.c.gateway-demo-243723.internal", "pod_name": "store-v1-84b47c7f58-pmgmk", "pod_name_emoji": "💇🏼♀️", "project_id": "gateway-demo-243723", "timestamp": "2022-10-25T13:31:17", "zone": "ZONE_NAME" }
转到
store.example.com/de
中的德语版商店服务,测试路径匹配:curl -H "host: store.example.com" VIP/de
输出会确认请求已由
store-german
Pod 处理:{ "cluster_name": "gke1", "host_header": "store.example.com", "metadata": "Gutentag!", "node_name": "gke-gke1-pool-2-bd121936-n3xn.c.gateway-demo-243723.internal", "pod_name": "store-german-5cb6474c55-lq5pl", "pod_name_emoji": "🧞♀", "project_id": "gateway-demo-243723", "timestamp": "2022-10-25T13:35:37", "zone": "ZONE_NAME" }
最后,使用
env: canary
HTTP 标头将流量发送到 Canary 版商店服务:curl -H "host: store.example.com" -H "env: canary " VIP
输出会确认请求已由
store-v2
Pod 处理:{ "cluster_name": "gke1", "host_header": "store.example.com", "metadata": "store-v2", "node_name": "gke-gke1-pool-2-bd121936-5pfc.c.gateway-demo-243723.internal", "pod_name": "store-v2-5788476cbd-s9thb", "pod_name_emoji": "🦰", "project_id": "gateway-demo-243723", "timestamp": "2022-10-25T13:38:26", "zone": "ZONE_NAME" }
部署外部网关
外部网关公开可从互联网或 VPC 外部网络访问的应用。外部网关部署与内部网关部署类似,但您必须保护应用的安全,因为公共互联网可以访问网关。
您可以通过两种方式创建外部网关:全球级外部网关或区域级外部网关。
全球外部网关使用全球 IP 地址(或任播 IP 地址)作为在所有 Google Cloud Compute 区域中通告的网关的前端。将流量发送到此任播 IP 地址的客户端会路由到通告该 IP 地址的最近 Google 位置。全球外部网关仅在高级网络服务层级提供。
区域级外部网关使用区域级 IP 地址作为网关的前端,该网关仅在部署区域级外部网关的本地 Google Cloud Compute 区域中通告。将流量发送到此区域级 IP 地址的客户端会由其本地 ISP 和互联网进行路由,然后再到达通告该 IP 地址的 Google 区域。区域级外部网关仅在标准网络服务层级提供。
部署全球外部网关
以下示例展示了如何将多个证书附加到全球外部网关并将证书分组到证书映射,并使用 Certificate Manager 和 HTTPRoute 公开商店应用。
创建证书映射
如果每个网关需要 15 个或更多证书或者您需要使用通配符证书,Google 建议使用 Certificate Manager 来管理证书。
您还可以使用 Kubernetes Secret 或 Google 管理的 SSL 证书来保护外部网关。如需了解详情,请参阅网关安全性。
在本部分中,您将使用 Certificate Manager 创建证书,以保护集群上运行的应用。
启用 Certificate Manager API:
gcloud services enable certificatemanager.googleapis.com
创建证书映射:
gcloud beta certificate-manager maps create store-example-com-map
将 Google 管理的证书和密钥加载到证书中:
gcloud beta certificate-manager certificates create store-example-com-cert \ --certificate-file="CERTIFICATE_FILE" \ --private-key-file="PRIVATE_KEY_FILE"
替换以下内容:
CERTIFICATE_FILE
:您选择的新文件的名称。文件必须具有扩展名.pem
。例如cert.pem
。PRIVATE_KEY_FILE
:您的私钥文件的名称。
如需了解详情,请参阅创建私钥和证书。
创建将证书分配给证书映射的
CertificateMapEntry
:gcloud beta certificate-manager maps entries create store-example-com-map-entry \ --map=store-example-com-map \ --hostname=store.example.com \ --certificates=store-example-com-cert
如需了解如何使用其他证书来源(例如 Kubernetes Secret 或 SSL 证书)保护网关,请参阅保护网关安全。
创建网关
网关资源表示在 Kubernetes 中路由流量的数据层面。网关可以表示许多不同类型的负载均衡和路由,具体取决于其使用的 GatewayClass。
在本部分中,您将创建一个网关。应用团队可以独立部署路由并将其安全地附加到网关,从而使用网关将应用公开给互联网。
将以下清单保存到名为
gateway.yaml
的文件中:kind: Gateway apiVersion: gateway.networking.k8s.io/v1beta1 metadata: name: external-http annotations: networking.gke.io/certmap: store-example-com-map spec: gatewayClassName: gke-l7-global-external-managed listeners: - name: https protocol: HTTPS port: 443
此清单描述了具有以下字段的网关:
gatewayClassName: gke-l7-global-external-managed
:指定此网关的 GatewayClass。此网关类使用全球外部应用负载均衡器。protocol: HTTPS
和port: 443
:指定网关为 HTTPS 流量开放端口 443。这些字段会启用 TLS。networking.gke.io/certmap: store-example-com-map
:指定 Certificate Manager 中证书映射的名称。
没有 TLS 部分,因为 TLS 是使用注解
networking.gke.io/certmap
以及使用 Certificate Manager 配置的。将清单应用到您的集群:
kubectl apply -f gateway.yaml
GKE 可能需要几分钟时间来部署资源。
验证网关已成功部署:
kubectl describe gateway
输出类似于以下内容:
Name: external-http Namespace: default Labels: <none> ... Spec: Gateway Class Name: gke-l7-global-external-managed Listeners: Allowed Routes: Namespaces: From: Same Name: https Port: 443 Protocol: HTTPS Tls: Certificate Refs: Group: Kind: Secret Name: store-example-com Mode: Terminate ...
此输出显示集群中部署的网关具有负载均衡器和公共 IP 地址。该网关没有路由,这意味着它无法将流量发送到后端。如果没有路由,所有流量都会流向默认后端,这会返回 HTTP 404 响应。在下一部分中,您将部署路由,以指示网关将流量发送到后端。
部署演示应用
应用团队可以独立于网关的部署部署他们的应用和路由。在某些情况下,应用团队可能还希望拥有网关,并自行将其部署为专用于其应用的资源。如需了解网关和路由的不同所有权模型,请参阅路由绑定。在此示例中,商店团队会部署应用和附带的 HTTPRoute,以通过在上一部分中创建的 external-http
网关公开应用。
如需详细了解 HTTPRoute 字段,请参阅 API 规范。
将示例应用部署到您的集群:
kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/gke-networking-recipes/main/gateway/gke-gateway-controller/app/store.yaml
此示例应用创建了三个 Deployment 和三个 Service,分别名为
store-v1
、store-v2
和store-german
。验证应用已成功部署:
kubectl get pod
输出类似于以下内容:
NAME READY STATUS RESTARTS AGE store-german-66dcb75977-5gr2n 1/1 Running 0 38s store-v1-65b47557df-jkjbm 1/1 Running 0 14m store-v2-6856f59f7f-sq889 1/1 Running 0 14m
验证 Service 已成功部署:
kubectl get service
输出类似于以下内容:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE store-german ClusterIP 10.48.3.183 <none> 8080/TCP 4s store-v1 ClusterIP 10.48.2.224 <none> 8080/TCP 5s store-v2 ClusterIP 10.48.4.48 <none> 8080/TCP 5s
创建 HTTPRoute
路由资源定义了用于将流量从网关映射到 Kubernetes 后端的特定于协议的规则。HTTPRoute 资源会执行 HTTP 和 HTTPS 流量匹配和过滤,并且受所有 gke-l7-*
GatewayClass 支持。
在本部分中,您将部署 HTTPRoute,它会使用访问示例应用所需的路由规则来配置网关。
将以下清单保存到名为
store-route-external.yaml
的文件中:kind: HTTPRoute apiVersion: gateway.networking.k8s.io/v1beta1 metadata: name: store-external spec: parentRefs: - kind: Gateway name: external-http hostnames: - "store.example.com" rules: - backendRefs: - name: store-v1 port: 8080 - matches: - headers: - name: env value: canary backendRefs: - name: store-v2 port: 8080 - matches: - path: value: /de backendRefs: - name: store-german port: 8080
此清单描述了引用
external-http
网关的 HTTPRoute。将清单应用到您的集群:
kubectl apply -f store-route-external.yaml
store
HTTPRoute 使用parentRefs
属性绑定到external-http
网关:下图展示了在底层负载均衡器上配置的路由规则:路由规则对 HTTP 流量的处理方式如下:
- 发送到
store.example.com/de
的流量路由到 Servicestore-german
。 - 发送到
store.example.com
且具有 HTTP 标头"env: canary"
的流量路由到 Servicestore-v2
。 - 发送到
store.example.com
的其余流量路由到 Servicestore-v1
。
- 发送到
验证 HTTPRoute 已部署:
kubectl describe httproute store-external
输出类似于以下内容:
Name: store-external Namespace: default Labels: <none> Annotations: <none> API Version: gateway.networking.k8s.io/v1beta1 Kind: HTTPRoute <...> Spec: Hostnames: store.example.com Parent Refs: Group: gateway.networking.k8s.io Kind: Gateway Name: external-http Rules: Backend Refs: Group: Kind: Service Name: store-v1 Port: 8080 Weight: 1 Matches: Path: Type: PathPrefix Value: / Backend Refs: Group: Kind: Service Name: store-v2 Port: 8080 Weight: 1 Matches: Headers: Name: env Type: Exact Value: canary Path: Type: PathPrefix Value: / Backend Refs: Group: Kind: Service Name: store-german Port: 8080 Weight: 1 Matches: Path: Type: PathPrefix Value: /de Status: Parents: Conditions: Last Transition Time: 2022-11-01T05:42:31Z Message: Reason: Accepted Status: True Type: Accepted Last Transition Time: 2022-11-01T05:43:18Z Message: Reason: ReconciliationSucceeded Status: True Type: Reconciled Controller Name: networking.gke.io/gateway Parent Ref: Group: gateway.networking.k8s.io Kind: Gateway Name: external-http Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal ADD 2m48s sc-gateway-controller default/store-external Normal SYNC 61s (x3 over 2m27s) sc-gateway-controller Bind of HTTPRoute "default/store-external" to ParentRef Group: "gateway.networking.k8s.io", ...
验证 HTTPRoute 已绑定到网关:
kubectl describe gateway external-http
输出类似于以下内容:
Name: external-http Namespace: default Labels: <none> <...> Status: Addresses: Type: IPAddress Value: 34.149.207.45 Conditions: Last Transition Time: 2022-11-01T05:37:21Z Message: Reason: Scheduled Status: True Type: Scheduled Last Transition Time: 2022-11-01T05:43:18Z Message: Reason: Ready Status: True Type: Ready Listeners: Attached Routes: 1 Conditions: Last Transition Time: 2022-11-01T05:43:18Z Message: Reason: Ready Status: True Type: Ready Name: https Supported Kinds: Group: gateway.networking.k8s.io Kind: HTTPRoute <...>
将流量发送到应用
现在,网关、路由和应用已在集群中部署,您可以将流量传递到您的应用。
获取网关的 IP 地址:
kubectl get gateways.gateway.networking.k8s.io external-http -o=jsonpath="{.status.addresses[0].value}"
输出为一个 IP 地址。
创建一个虚拟机:
gcloud cloud-shell ssh
将流量从虚拟机发送到网关 IP 地址。您必须手动设置主机标头,因为您不拥有
example.com
主机名。curl -H "host: store.example.com" https://GATEWAY_IP_ADDRESS --resolve store.example.com:443:GATEWAY_IP_ADDRESS --cacert cacert.pem -v
将
GATEWAY_IP_ADDRESS
替换为上一步中网关的 IP 地址。输出显示来自演示版应用有关应用运行位置的信息:
{ "cluster_name": "gke1", "host_header": "store.example.com", "metadata": "store-v1", "node_name": "gke-gke1-pool-2-bd121936-5pfc.c.gateway-demo-243723.internal", "pod_name": "store-v1-84b47c7f58-pmgmk", "pod_name_emoji": "💇🏼♀️", "project_id": "gateway-demo-243723", "timestamp": "2022-09-25T13:31:17", "zone": "us-central1-a" }
转到
store.example.com/de
中的德语版store
服务,以测试路径匹配:curl -H "host: store.example.com" https://GATEWAY_IP_ADDRESS/de --resolve store.example.com:443:GATEWAY_IP_ADDRESS --cacert cacert.pem -v
输出会确认请求已由
store-german
Pod 处理:{ "cluster_name": "gke1", "host_header": "store.example.com", "metadata": "Gutentag!", "node_name": "gke-gke1-pool-2-bd121936-n3xn.c.gateway-demo-243723.internal", "pod_name": "store-german-5cb6474c55-lq5pl", "pod_name_emoji": "🧞♀", "project_id": "gateway-demo-243723", "timestamp": "2022-09-25T13:35:37", "zone": "us-central1-a" }
使用
env: canary
HTTP 标头将流量发送到store
服务的 Canary 版本:curl -H "host: store.example.com" -H "env: canary " https://GATEWAY_IP_ADDRESS/de --resolve store.example.com:443:GATEWAY_IP_ADDRESS --cacert cacert.pem -v
输出会确认请求已由
store-v2
Pod 处理:{ "cluster_name": "gke1", "host_header": "store.example.com", "metadata": "store-v2", "node_name": "gke-gke1-pool-2-bd121936-5pfc.c.gateway-demo-243723.internal", "pod_name": "store-v2-5788476cbd-s9thb", "pod_name_emoji": "👩🏿", "project_id": "gateway-demo-243723", "timestamp": "2022-09-25T13:38:26", "zone": "us-central1-a" }
部署区域级外部网关
以下示例展示了如何使用自行管理的证书和 HTTPRoute 公开具有附加到区域外部网关的多份证书的商店应用。
为区域级网关创建代理子网
您必须先配置代理专用子网,然后才能创建使用区域级外部应用负载均衡器的网关。在使用区域级外部应用负载均衡器的 VPC 中,每个区域都必须具有一个 external_managed_proxy
子网。此子网为负载均衡器代理提供了内部 IP 地址。
创建证书以保护您的客户端流量
您可以使用证书授权机构 (CA) 颁发并验证的证书,也可以创建自签名证书。如需详细了解如何创建证书,请参阅将证书存储在 Kubernetes Secret 中。
创建区域级外部 HTTP(S) 网关
为外部负载均衡器创建区域级静态 IP 地址。
gcloud compute addresses create IP_ADDRESS_NAME \ --region=COMPUTE_REGION \ --network-tier=STANDARD
替换以下内容:
IP_ADDRESS_NAME
:新的静态 IP 地址的名称。COMPUTE_REGION
:集群在其中运行的 Compute Engine 区域。
使用自行管理的证书创建区域级外部应用负载均衡器网关,如下所示,并将清单保存为
regional-gateway.yaml
:kind: Gateway apiVersion: gateway.networking.k8s.io/v1beta1 metadata: name: external-regional-http spec: gatewayClassName: gke-l7-regional-external-managed listeners: - name: https protocol: HTTPS port: 443 tls: mode: Terminate certificateRefs: - name: store-example-com addresses: - type: NamedAddress value: IP_ADDRESS_NAME
应用
regional-gateway
清单:kubectl apply -f regional-gateway.yaml
验证配置。
kubectl get gateway
输出类似于以下内容:
NAME CLASS ADDRESS READY AGE external-http gke-l7-regional-external-managed 35.118.32.224 True 49s
如需了解更多详情,请使用 describe 命令:
kubectl describe gateway
输出类似于以下内容:
Name: external-regional-http Namespace: default Labels: <none> ... Spec: Gateway Class Name: gke-l7-regional-external-managed Listeners: Allowed Routes: Namespaces: From: Same Name: https Port: 443 Protocol: HTTPS Tls: Certificate Refs: Group: Kind: Secret Name: store-example-com Mode: Terminate ...
部署演示应用
您可以独立于 Gateway 的部署来部署应用和路由。
如需详细了解如何部署演示应用,请参阅部署演示应用。创建 HTTPRoute
您必须创建 HTTPRoute 才能执行 HTTP 和 HTTPS 流量匹配和过滤。
将流量发送到应用
部署应用并创建 HTTPRoute 后,您可以将流量传递给应用。
如需详细了解如何将流量发送到应用,请参阅将流量发送到应用。使用共享 Gateway
Gateway API 使用单独的资源(网关和路由资源)来部署负载均衡器和路由规则。这与 Ingress 不同,Ingress 会将所有内容组合到一个资源中。通过在资源之间拆分责任,网关可让负载均衡器及其路由规则单独部署,并由不同用户或团队进行部署。这样一来,网关即可成为共享网关,这些网关与多个不同路由连接,可以完全由独立团队拥有和管理,甚至可以跨不同命名空间。
针对共享网关部署路由
此示例基于部署内部 Gateway中部署的 internal-http
Gateway。
在此示例中,网站团队将部署其应用、Service 和HTTPRoute,以将来自 Gateway 的流量与这些 Service 匹配。
部署示例应用:
kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/gke-networking-recipes/main/gateway/gke-gateway-controller/app/site.yaml
将以下清单保存到名为
site-route-internal.yaml
的文件中:kind: HTTPRoute apiVersion: gateway.networking.k8s.io/v1beta1 metadata: name: site-internal spec: parentRefs: - kind: Gateway name: internal-http hostnames: - "site.example.com" rules: - backendRefs: - name: site-v1 port: 8080
此清单描述了一个与
site.example.com
的所有流量匹配并将其路由到site-v1
Service 的 HTTPRoute。将清单应用到您的集群:
kubectl apply -f site-route-internal.yaml
验证 HTTPRoute 是否已连接到 Gateway:
kubectl describe httproute.gateway.networking.k8s.io site-internal
输出类似于以下内容:
Status: Parents: Conditions: Last Transition Time: 2023-01-09T15:05:43Z Message: Reason: Accepted Status: True Type: Accepted Last Transition Time: 2023-01-09T15:05:43Z Message: Reason: ReconciliationSucceeded Status: True Type: Reconciled Controller Name: networking.gke.io/gateway Parent Ref: Group: gateway.networking.k8s.io Kind: Gateway Name: internal-http ...
如果 Gateway 的
Accepted
条件为True
,则表示 HTTPRoute 已成功绑定到 Gateway。如需详细了解状态字段,请参阅路由状态。验证流向 Gateway 的流量是否已正确路由:
curl -H "host: site.example.com" GATEWAY_IP_ADDRESS curl -H "host: store.example.com" GATEWAY_IP_ADDRESS
将
GATEWAY_IP_ADDRESS
替换为 Gateway 的 IP 地址。您必须在 Gateway 所在的 VPC 中使用虚拟机 (VM)。
输出类似于以下内容:
{ "cluster_name": "CLUSTER_NAME", "host_header": "site.example.com", "metadata": "site-v1", "pod_name": "site-v1-5d64fc4d7d-fz6f6", "pod_name_emoji": "👩🏼🍳", "project_id": "PROJECT_ID", "timestamp": "2022-11-02T19:07:01", "zone": "ZONE_NAME" } ... { "cluster_name": "CLUSTER_NAME", "host_header": "store.example.com", "metadata": "store-v1", "pod_name": "store-v1-6d8d58d78-vz8pn", "pod_name_emoji": "🧝🏻♂️", "project_id": "PROJECT_ID", "timestamp": "2022-11-02T19:07:01", "zone": "ZONE_NAME" }
配置 Gateway 默认后端
所有 gke-l7-*
GatewayClass 都会向不匹配的流量返回 HTTP 404。您可以使用显式默认 Route 配置默认后端,该路由会将不匹配的流量发送到用户提供的 Service。
以下 HTTPRoute 示例演示了如何自定义默认后端。如果您应用与以下内容类似的 HTTPRoute,则其优先于隐式默认后端:
kind: HTTPRoute
apiVersion: gateway.networking.k8s.io/v1beta1
metadata:
name: custom-default-backend
spec:
parentRefs:
- kind: Gateway
name: my-internal-gateway
rules:
- backendRefs:
- name: my-custom-default-backend-service
port: 8080
此 HTTPRoute 匹配来自特定网关的所有流量。每个 Gateway 只能有一个规则,否则规则会发生冲突并且优先顺序适用。
您可以使用默认后端来阻止他人创建路由所有 Gateway 流量的默认路由后端。显式 HTTPRoute 始终优先于具有冲突路由规则的新 HTTPRoute。
为 Gateway 配置静态 IP 地址
每个 Gateway 都有一个 IP 地址,用于监听流量。如果您未在 Gateway 上指定 IP 地址,则 Gateway 控制器会自动提供 IP 地址。您还可以创建静态 IP 地址,以使 IP 地址的存在与 Gateway 生命周期无关。
部署网关后,其 IP 地址会显示在状态字段中:
kind: Gateway
...
status:
addresses:
- value: 10.15.32.3
根据 GatewayClass,IP 地址是从以下子网分配的:
GatewayClass | 默认 IP 地址池 |
---|---|
|
主节点 IPv4/IPv6 地址范围中的区域专用 IP 地址 |
|
Google 的区域外部 IPv4/IPv6 范围中的区域公共 IP 地址 |
|
Google 的全球外部 IPv4/IPv6 范围中的全球公共 IP 地址 |
addresses.NamedAddress
字段可让您指定独立于网关的 IP 地址。您可以在网关部署之前创建静态 IP 地址资源,并且 NamedAddress
会引用该资源。即使网关已删除,您也可以重复使用静态 IP 地址。
使用已命名的 IP 地址
您可以通过指定 NamedAddress
来配置 IP 地址。您必须先预配静态 IP 地址,然后才能创建 Gateway。
创建静态 IP 地址资源:
gcloud compute addresses create IP_ADDRESS_NAME \ --purpose=SHARED_LOADBALANCER_VIP \ --region=COMPUTE_REGION \ --subnet=SUBNET \ --project=PROJECT_ID
替换以下内容:
IP_ADDRESS_NAME
:新的静态 IP 地址的名称COMPUTE_REGION
:对于区域级 Gateway,是集群在其中运行的 Compute Engine 区域。 对于全球外部 Gateway,不需要此标志。SUBNET
:IP 地址的子网。 对于全球外部 Gateway,不需要此标志。PROJECT_ID
:GKE 集群在其中运行的项目。
将以下清单保存到名为
named-ip-gateway.yaml
的文件中:kind: Gateway apiVersion: gateway.networking.k8s.io/v1beta1 metadata: name: internal-http spec: gatewayClassName: gke-l7-rilb listeners: - name: http protocol: HTTP port: 80 addresses: - type: NamedAddress value: IP_ADDRESS_NAME
此清单描述了一个引用已命名的 IP 地址的 Gateway。
将清单应用到您的集群:
kubectl apply -f named-ip-gateway.yaml
验证 Gateway IP 地址:
kubectl describe gateway internal-http
输出类似于以下内容:
Name: internal-http Namespace: default Labels: <none> ... Spec: Addresses: Type: NamedAddress Value: IP_ADDRESS_NAME Gateway Class Name: gke-l7-rilb Listeners: Allowed Routes: Namespaces: From: Same Name: http Port: 80 Protocol: HTTP Status: Addresses: Type: IPAddress Value: 10.15.32.103
配置从 HTTP 到 HTTPS 的重定向
Cloud Load Balancing 提供从 HTTP 到 HTTPS 的重定向功能。外部应用负载均衡器将未加密的 HTTP 请求重定向到使用相同 IP 地址的 HTTPS 负载均衡器。当您创建启用 HTTP 到 HTTPS 重定向的网关时,系统会自动创建这两个负载均衡器。对端口 80 上网关的外部 IP 地址的请求会自动重定向到端口 443 上的同一外部 IP 地址。
默认情况下,网关上未定义 HTTP 到 HTTPS 重定向。
如需将 HTTP 流量重定向到 HTTPS,请配置网关以同时处理 HTTP 和 HTTPS 流量。如果您停用 HTTP 或 HTTPS,则网关不会重定向流量。
以下示例展示了如何使用 HTTP 到 HTTPS 重定向确保从客户端发送到 Web 应用的流量始终重定向到安全页面。
重定向来自网关命名空间的 HTTP 流量
在以下示例中,网关配置为允许 HTTP 监听器上的 Same
(来自同一命名空间的连接),而 HTTPS 监听器向所有命名空间开放。若使用此配置,应该只有重定向 HTTPRoute
与网关位于同一命名空间。
此配置可确保没有其他 HTTPRoute 可以绑定到网关的 HTTP 监听器。这要求 gateway-infra
命名空间中不允许应用团队的 HTTPRoute。
创建网关的命名空间
gateway-infra
。将清单保存为gateway-namespace.yaml
:apiVersion: v1 kind: Namespace metadata: name: gateway-infra
应用清单:
kubectl apply -f gateway-namespace.yaml
使用以下清单创建网关并将清单保存为
external-gateway.yaml
:kind: Gateway apiVersion: gateway.networking.k8s.io/v1beta1 metadata: name: external-http namespace: gateway-infra spec: gatewayClassName: gke-l7-global-external-managed listeners: - name: http protocol: HTTP port: 80 allowedRoutes: kinds: - kind: HTTPRoute namespaces: from: Same - name: https protocol: HTTPS port: 443 allowedRoutes: kinds: - kind: HTTPRoute namespaces: from: All tls: mode: Terminate options: networking.gke.io/pre-shared-certs: store-example-com
allowedRoutes
部分中的namespaces
字段将 HTTP 监听器限制为网关的命名空间gateway-infra
。HTTPS 监听器不包含对允许的命名空间的限制,因此所有命名空间都使用具有 HTTPRoute 的 HTTPS 监听器。
应用清单:
kubectl apply -f external-gateway.yaml
如需强制进行 HTTPS 重定向,请使用以下清单创建默认 HTTPRoute 并将清单保存为
redirect-httproute.yaml
:kind: HTTPRoute apiVersion: gateway.networking.k8s.io/v1beta1 metadata: name: redirect namespace: gateway-infra spec: parentRefs: - namespace: gateway-infra name: external-http sectionName: http rules: - filters: - type: RequestRedirect requestRedirect: scheme: https
sectionName
字段指示网关仅在 HTTP 监听器上匹配。RequestRedirect
过滤条件会强制重定向到 HTTPS 监听器。
此配置会将在网关端口 80 上收到的所有流量重定向到端口 443 上的监听器,从而在客户端和负载均衡器之间强制执行安全通信。
应用清单:
kubectl apply -f redirect-httproute.yaml
使用以下清单为应用创建 Service。将清单保存为
service-deployment.yaml
:apiVersion: v1 kind: Service metadata: name: store-v1 spec: selector: app: store version: v1 ports: - port: 8080 targetPort: 8080 --- apiVersion: apps/v1 kind: Deployment metadata: name: store-v1 spec: replicas: 2 selector: matchLabels: app: store version: v1 template: metadata: labels: app: store version: v1 spec: containers: - name: whereami image: us-docker.pkg.dev/google-samples/containers/gke/whereami:v1.2.20 ports: - containerPort: 8080 env: - name: METADATA value: "store-v1"
应用清单:
kubectl apply -f service-deployment.yaml
为仅允许 HTTPS 的应用创建 HTTPRoute。将清单保存为
httproute.yaml
:kind: HTTPRoute apiVersion: gateway.networking.k8s.io/v1beta1 metadata: name: store-external labels: gateway: external-http spec: parentRefs: - name: external-http namespace: gateway-infra sectionName: https hostnames: - "store.example.com" rules: - backendRefs: - name: store-v1 port: 8080
应用清单:
kubectl apply -f httproute.yaml
重定向来自基础架构命名空间的 HTTP 流量
在某些情况下,基础架构或平台管理团队与应用团队之间没有明显的区别,因此防止网关滥用可能成为一个难题。
以下示例进一步限制了 HTTP 监听器的使用,以防止应用团队意外使用非安全协议。此示例将网关配置为仅当路由在给定命名空间 (http-redirect) 中时才允许 HTTPRoute 使用 HTTP 监听器,同时它将 HTTPS 监听器向所有命名空间开放。您可以使用 Kubernetes RBAC 限制 http-redirect 命名空间,这样应用团队就不会错误地在此命名空间中创建 HTTPRoute。
创建网关的命名空间。将清单保存为
gateway-namespace.yaml
:apiVersion: v1 kind: Namespace metadata: name: gateway-infra
应用清单:
kubectl apply -f gateway-namespace.yaml
创建网关的命名空间,并将清单保存为
redirect-namespace.yaml
:apiVersion: v1 kind: Namespace metadata: name: http-redirect labels: otherInfra: httpToHttps
- 此命名空间设置了特定标签。
应用清单:
kubectl apply -f redirect-namespace.yaml
如需限制 HTTP 监听器的使用,请使用以下清单创建网关。将清单保存为
external-gateway.yaml
:kind: Gateway apiVersion: gateway.networking.k8s.io/v1beta1 metadata: name: external-http namespace: gateway-infra spec: gatewayClassName: gke-l7-global-external-managed listeners: - name: http protocol: HTTP port: 80 allowedRoutes: kinds: - kind: HTTPRoute namespaces: from: selector selector: matchLabels: otherInfra: httpToHttps - name: https protocol: HTTPS port: 443 allowedRoutes: kinds: - kind: HTTPRoute namespaces: from: All tls: mode: Terminate options: networking.gke.io/pre-shared-certs: store-example-com ```
namespace
字段指定在gateway-infra
命名空间中创建网关。allowedRoutes
部分中的namespaces
字段将 HTTP 监听器限制为与标签otherInfra: httpToHttps
匹配的命名空间。
应用清单:
kubectl apply -f external-gateway.yaml
如需强制进行 HTTPS 重定向,请使用以下清单创建默认 HTTPRoute。将清单保存为
http-redirect.yaml
:kind: HTTPRoute apiVersion: gateway.networking.k8s.io/v1beta1 metadata: name: redirect namespace: http-redirect spec: parentRefs: - namespace: gateway-infra name: external-http sectionName: http rules: - filters: - type: RequestRedirect requestRedirect: scheme: https
sectionName
字段指示网关仅在 HTTP 监听器上匹配。RequestRedirect
过滤条件会强制重定向到 HTTPS 监听器。
应用清单:
kubectl apply -f http-redirect.yaml
使用以下清单为应用创建 Service。将清单保存为
service-deployment.yaml
:apiVersion: v1 kind: Service metadata: name: store-v1 spec: selector: app: store version: v1 ports: - port: 8080 targetPort: 8080 --- apiVersion: apps/v1 kind: Deployment metadata: name: store-v1 spec: replicas: 2 selector: matchLabels: app: store version: v1 template: metadata: labels: app: store version: v1 spec: containers: - name: whereami image: us-docker.pkg.dev/google-samples/containers/gke/whereami:v1.2.20 ports: - containerPort: 8080 env: - name: METADATA value: "store-v1"
应用清单:
kubectl apply -f service-deployment.yaml
使用以下清单为仅允许 HTTPS 的应用创建 HTTPRoute。将清单保存为
http-route.yaml
:kind: HTTPRoute apiVersion: gateway.networking.k8s.io/v1beta1 metadata: name: store-external labels: gateway: external-http spec: parentRefs: - name: external-http namespace: gateway-infra sectionName: https hostnames: - "store.example.com" rules: - backendRefs: - name: store-v1 port: 8080
应用清单:
kubectl apply -f http-route.yaml
配置路径重定向和网址重写
路径重定向涉及将传入请求从一个网址路径重定向到另一个网址路径。借助路径重定向,您可以在需要处理过期或已弃用的网址时更改网址结构。
网址重写有助于在服务器上处理传入网址之前修改该网址。它允许您更改网址的结构或格式,而无需实际更改底层内容或文件结构。网址重写对创建方便记忆且易于理解的人性化和搜索引擎优化 (SEO) 型网址非常有用。默认情况下,系统不会配置路径重定向和网址重写,您需要使用 HTTPRoute 中的过滤条件明确配置这些重定向或重写。
GKE Gateway 支持路径重定向和网址重写。如需了解详情,请参阅 HTTP 路径重定向和重写。
配置路径重定向
您可以将路径重定向配置为替换整个路径,也可以仅替换网址中的前缀。
替换整个路径
如需替换整个路径,请在 HTTPRoute 中配置过滤条件,以将网址路径中包含前缀
/any-path
的任何网址替换为严格值/new-path
。如下所示创建
HTTPRoute
清单,并将其命名为store.yaml
:apiVersion: gateway.networking.k8s.io/v1beta1 kind: HTTPRoute metadata: name: store spec: parentRefs: - kind: Gateway name: external-http hostnames: - store.example.com rules: - matches: - path: type: PathPrefix value: /any-path filters: - type: RequestRedirect requestRedirect: path: type: ReplaceFullPath replaceFullPath: /new-path statusCode: 302
例如,此清单为 HTTPRoute 设置路由规则,如下所示:到网址 https://store.example.com/any-path/... 的任意路由应重定向到新位置 https://store.example.com/new-path/(严格)。
应用清单:
kubectl apply -f store.yaml
此路由规则遵循严格的重定向规则,这意味着浏览器不会尝试缓存重定向,而是重定向到最新版本。
仅替换前缀
如需仅替换前缀,请在 HTTPRoute 中配置过滤条件,以将网址路径中包含前缀
/any-prefix
的任何网址替换为严格值/new-prefix
。如下所示创建
HTTPRoute
清单,并将其命名为store.yaml
:apiVersion: gateway.networking.k8s.io/v1beta1 kind: HTTPRoute metadata: name: store spec: parentRefs: - kind: Gateway name: external-http hostnames: - store.example.com rules: - matches: - path: type: PathPrefix value: /any-prefix filters: - type: RequestRedirect requestRedirect: path: type: ReplacePrefixMatch replacePrefixMatch: /new-prefix statusCode: 302
例如,此清单为 HTTPRoute 设置路由规则,如下所示:到网址 https://store.example.com/any-path/v1/... 的任意路由应重定向到新位置 https://store.example.com/new-path/v1/...(仅替换前缀)。
应用清单:
kubectl apply -f store.yaml
此路由规则遵循唯一的重定向规则,可确保浏览器始终将您重定向到相同的预期页面。
配置网址重写
设置网址重写可更改网址对用户的显示方式。您可以使用网址重写功能,让网址更加方便用户使用,改进搜索引擎优化 (SEO),或将用户重定向到新网页。
重写整个主机名
要重写整个主机名,请执行以下操作:
在 HTTPRoute 中配置过滤条件,指示网关将请求标头中的
Host
信息从 www.example.com 替换为 store.example.com。,然后再将请求转发到后端服务。如下所示创建
HTTPRoute
清单,并将其命名为www.yaml
:apiVersion: gateway.networking.k8s.io/v1beta1 kind: HTTPRoute metadata: name: www spec: parentRefs: - kind: Gateway name: external-http hostnames: - www.example.com rules: - filters: - type: URLRewrite urlRewrite: hostname: store.example.com backendRefs: - name: store-v1 port: 8080
例如,通过上述配置,任何对 https://www.example.com 的请求都将转发到带有
Host: store.example.com
标头(而不是Host: www.example.com
)的后端服务。应用清单:
kubectl apply -f www.yaml
使用路径修饰符进行重写
您可以将重写与路径修饰符结合使用,以在将请求中继到后端服务之前提供高级网址和路径修改。
如需使用路径修饰符进行重写,请执行以下操作:
在 HTTPRoute 中配置过滤条件,指示网关将请求标头中的“主机”信息从 www.example.com 更改为 store.example.com,并将值
/store
替换为/
,然后再将请求转发到后端服务。如下所示创建
HTTPRoute
清单,并将其命名为www.yaml
:apiVersion: gateway.networking.k8s.io/v1beta1 kind: HTTPRoute metadata: name: www spec: parentRefs: - kind: Gateway name: external-http hostnames: - www.example.com rules: - matches: - path: type: PathPrefix value: /store filters: - type: URLRewrite urlRewrite: hostname: store.example.com path: type: ReplacePrefixMatch replacePrefixMatch: /de backendRefs: - name: store-german port: 8080
例如,通过上述配置,任何对 https://www.example.com/store/... 的请求都将转发到请求标头中带有
Host: store.example.com
(而不是Host: www.example.com
)的后端服务,并且/store
将被重写为/de
。应用清单:
kubectl apply -f www.yaml
验证配置
如需在使用网址重写或路径重定向过滤条件创建 HTTPRoute 后验证过滤条件是否已应用,请执行以下操作:
kubectl get httproute www -o yaml
输出类似于以下内容:
apiVersion: gateway.networking.k8s.io/v1beta1
kind: HTTPRoute
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"gateway.networking.k8s.io/v1beta1","kind":"HTTPRoute","metadata":{"annotations":{},"name":"www","namespace":"default"},"spec":{"hostnames":["www.example.com"],"parentRefs":[{"kind":"Gateway","name":"external-http"}],"rules":[{"backendRefs":[{"name":"store-german","port":8080}],"filters":[{"type":"URLRewrite","urlRewrite":{"hostname":"store.example.com","path":{"replacePrefixMatch":"/de","type":"ReplacePrefixMatch"}}}],"matches":[{"path":{"type":"PathPrefix","value":"/store"}}]}]}}
creationTimestamp: "2023-06-22T01:00:42Z"
generation: 3
name: www
namespace: default
resourceVersion: "51268631"
uid: e516493e-806d-44d6-ae0d-1c9ff25682cf
spec:
hostnames:
- www.example.com
parentRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: external-http
rules:
- backendRefs:
- group: ""
kind: Service
name: store-german
port: 8080
weight: 1
filters:
- type: URLRewrite
urlRewrite:
hostname: store.example.com
path:
replacePrefixMatch: /de
type: ReplacePrefixMatch
matches:
- path:
type: PathPrefix
value: /store
status:
parents:
- conditions:
- lastTransitionTime: "2023-06-22T01:11:26Z"
message: ""
observedGeneration: 2
reason: Accepted
status: "True"
type: Accepted
- lastTransitionTime: "2023-06-22T01:11:26Z"
message: ""
observedGeneration: 2
reason: ReconciliationSucceeded
status: "True"
type: Reconciled
controllerName: networking.gke.io/gateway
parentRef:
group: gateway.networking.k8s.io
kind: Gateway
name: external-http
如需了解更多详情,请使用 describe 命令:
kubectl describe httproute
配置自定义请求和响应标头
使用自定义请求和响应标头,您可以为 HTTP(S) 请求和响应指定其他标头。根据负载均衡器检测到的信息,这些标头可以包含以下信息:
- 客户端的延迟时间
- 客户端 IP 地址的地理位置
- TLS 连接的参数
默认情况下,向后端服务发送/从后端服务接收的请求不会添加自定义标头,您需要使用 HTTPRoute 中的过滤条件明确配置自定义标头。
您可以通过在 HTTPRoute 的规则中添加过滤条件部分来配置自定义标头,如下所示:
配置自定义请求标头
使用 RequestHeaderModifier 过滤条件创建 HTTPRoute 清单,然后将其保存为 http-route-request.yaml:
apiVersion: gateway.networking.k8s.io/v1beta1
kind: HTTPRoute
metadata:
name: store
spec:
<...>
rules:
filters:
- type: RequestHeaderModifier
requestHeaderModifier:
<...>
应用清单:
kubectl apply -f http-route-request.yaml
配置自定义响应标头
使用 ResponseHeaderModifier 过滤条件创建 HTTPRoute 清单,并将其保存为 http-route-response.yaml:
apiVersion: gateway.networking.k8s.io/v1beta1
kind: HTTPRoute
metadata:
name: store
spec:
<...>
rules:
filters:
- type: ResponseHeaderModifier
responseHeaderModifier:
<...>
应用清单:
kubectl apply -f http-route-response.yaml
您可以按照 Gateway API 实现中的说明添加、设置和移除标头。您可以使用 Google Cloud 支持的变量通过自定义标头配置 HTTPRoute。
示例 1:
如需配置在将客户端位置信息发送到后端服务之前将该信息添加到 HTTP 请求的 HTTPRoute,请创建 HTTPRoute 清单并将其命名为 external-http-request.yaml
:
apiVersion: gateway.networking.k8s.io/v1beta1
kind: HTTPRoute
metadata:
name: store
spec:
parentRefs:
- kind: Gateway
name: external-http
hostnames:
- store.example.com
rules:
- matches:
- path:
type: PathPrefix
value: /fr
filters:
- type: RequestHeaderModifier
requestHeaderModifier:
add:
- name: X-Client-Geo-Location
value: "{client_region},{client_city}"
backendRefs:
- name: store-french
port: 8080
例如,对于位于法国特拉斯堡的客户端,网关会将标头添加为 X-Client-Geo-Location:FR,Strasbourg
。
示例 2:
如需配置添加自定义响应标头以支持 HTTP 严格传输安全协议的 HTTPRoute,请创建 HTTPRoute 清单并将其命名为 external-http-response.yaml
:
apiVersion: gateway.networking.k8s.io/v1beta1
kind: HTTPRoute
metadata:
name: store
spec:
parentRefs:
- kind: Gateway
name: external-http
hostnames:
- store.example.com
rules:
- matches:
- path:
type: PathPrefix
value: /de
filters:
- type: ResponseHeaderModifier
responseHeaderModifier:
add:
- name: Strict-Transport-Security
value: max-age=63072000
backendRefs:
- name: store-german
port: 8080
验证配置
如需在配置自定义请求和响应标头后验证配置,请执行以下操作:
kubectl get httproute
输出类似于以下内容:
NAME HOSTNAMES AGE store ["store.example.com"] 4d23h
如需了解更多详情,请使用 describe 命令:
kubectl describe httproute
输出类似于以下内容:
Name: store Namespace: default Labels: <none> Annotations: <none> API Version: gateway.networking.k8s.io/v1beta1 Kind: HTTPRoute Metadata: Creation Timestamp: 2023-05-27T00:51:01Z Generation: 5 Resource Version: 25418887 UID: 2e07a1b8-420b-41b4-acd1-cecbfcd39f42 Spec: Hostnames: store.example.com Parent Refs: Group: gateway.networking.k8s.io Kind: Gateway Name: external-http Rules: Backend Refs: Group: Kind: Service Name: store-v1 Port: 8080 Weight: 1 Matches: Path: Type: PathPrefix Value: / Backend Refs: Group: Kind: Service Name: store-v2 Port: 8080 Weight: 1 Matches: Headers: Name: env Type: Exact Value: canary Path: Type: PathPrefix Value: / Backend Refs: Group: Kind: Service Name: store-german Port: 8080 Weight: 1 Filters: Request Header Modifier: Add: Name: X-Client-Geo-Location Value: {client_region},{client_city} Type: RequestHeaderModifier Matches: Path: Type: PathPrefix Value: /de Status: <...>
路由状态
HTTPRoute 资源会发出条件和事件,以帮助用户了解 HTTPRoute 是否已成功与一个或多个 Gateway 绑定,或者 HTTPRoute 是否被拒绝。
HTTPRoute 条件
HTTPRoute 条件指示 Route 的状态及其绑定到的 Gateway。由于一个 Route 可以绑定到多个 Gateway,因此这是一个 Gateway 以及 Route 与每个 Gateway 之间的各个条件的列表。
Accepted=True
表示 HTTPRoute 已成功绑定到 Gateway。Accepted=False
表示 HTTPRoute 已被拒绝与此 Gateway 绑定。
如果 Gateway bindings
标题下未列出任何 Gateway,则 HTTPRoute 标签和 Gateway 标签选择器可能不匹配。如果 Route 未被任何 Gateway 选择,则可能会发生这种情况。
HTTPRoute 事件
HTTPRoute 事件提供有关 HTTPRoute 状态的详细信息。事件分组的原因如下:
ADD
事件由添加的资源触发。UPDATE
事件由更新的资源触发。SYNC
事件由定期协调触发。
路由合并、优先权和验证
路由优先权
Gateway API 针对具有重叠路由规则的 Route 如何匹配流量定义了严格的优先权规则。两个重叠 HTTPRoute 之间的优先权如下所示:
- 主机名合并:最长/最具体的主机名匹配。
- 路径合并:最长/最具体的路径匹配。
- 标头合并:匹配的 HTTP 标头的最大数。
- 冲突:如果前三个规则未确立优先权,则优先权转给时间戳最早的 HTTPRoute 资源。
路由合并
对于 gke-l7
GatewayClass,给定网关的所有 HTTPRoutes 都会合并到同一个网址映射资源中。HTTPRoute 的合并在一起的方式取决于 HTTPRoute 之间的重叠类型。来自前面的示例的 HTTPRoute 可以拆分为三个单独的 HTTPRoute,用于说明路由合并和优先权:
- 路由合并:所有三个 HTTPRoute 都与同一
internal-http
网关连接,因此它们会合并在一起。 - 主机名合并:对于
store.example.com
,所有三个路由都匹配,因此它们的主机名规则会合并。 - 路径合并:store-german-route 具有更具体的路径
/de
,因此不会进一步合并。store-v1-route 和 store-v2-route 同样与同一/*
路径匹配,因此它们会在该路径上合并。 - 标头合并:store-v2-route 具有一组比 store-v1-route 更具体的 HTTP 标头匹配项,因此不会进一步合并。
- 冲突:由于路由可以按主机名、路径和标头进行合并,因此不会发生冲突,并且所有路由规则都应用于流量。
前面的示例中使用的单个 HTTPRoute 相当于这三个单独的路由:
kind: HTTPRoute
apiVersion: gateway.networking.k8s.io/v1beta1
metadata:
name: store-v1-route
spec:
parentRefs:
- kind: Gateway
name: internal-http
hostnames:
- "store.example.com"
rules:
- backendRefs:
- kind: Service
name: store-v1
port: 8080
---
kind: HTTPRoute
apiVersion: gateway.networking.k8s.io/v1beta1
metadata:
name: store-v2-route
spec:
parentRefs:
- kind: Gateway
name: internal-http
hostnames:
- "store.example.com"
rules:
- matches:
- headers:
- type: Exact
name: env
value: canary
backendRefs:
- kind: Service
name: store-v2
port: 8080
---
kind: HTTPRoute
apiVersion: gateway.networking.k8s.io/v1beta1
metadata:
name: store-german-route
spec:
parentRefs:
- kind: Gateway
name: internal-http
hostnames:
- "store.example.com"
rules:
- matches:
- path:
type: PathPrefix
value: /de
backendRefs:
- kind: Service
name: store-german
port: 8080
Kubernetes 网关和 Istio 网关
请注意,Kubernetes Gateway API 和 Istio API 都有一个名为 Gateway
的资源。虽然它们执行类似的功能,但并不是相同的资源。如果您在同一 Kubernetes 集群中同时使用 Istio 和 Gateway API,则当您在命令行中使用 kubectl 时,这些名称将重叠。kubectl get gateway
可能会返回 Kubernetes 网关资源,但不会返回 Istio 网关资源,反之亦然。
$ kubectl api-resources
NAME SHORTNAMES APIGROUP NAMESPACED KIND
gateways gw networking.istio.io/v1beta1 true Gateway
gateways gtw networking.k8s.io/v1beta1 true Gateway
如果您使用的是 Istio 并升级到 GKE 1.20 及更高版本,则建议开始使用网关资源简称或指定 API 组。Kubernetes 网关的简称为 gtw
,Istio 网关的简称为 gw
。以下命令会分别返回 Kubernetes 网关资源和 Istio 网关资源。
# Kubernetes Gateway
$ kubectl get gtw
NAME CLASS
multi-cluster-gateway gke-l7-global-external-managed-mc
$ kubectl get gateway.networking.x-k8s.io
NAME CLASS
multi-cluster-gateway gke-l7-global-external-managed-mc
# Istio Gateway
$ kubectl get gw
NAME AGE
bookinfo-gateway 64m
$ kubectl get gateway.networking.istio.io
NAME AGE
bookinfo-gateway 64m
问题排查
区域中缺少代理专用子网
具体情况:
创建区域级 Gateway(内部或外部)时,可能会出现以下问题:
generic::invalid_argument: error ensuring load balancer: Insert: Invalid value for field 'resource.target': 'regions/[REGION_NAME]/targetHttpProxies/gkegw-x5vt-default-internal-http-[ID]'. A reserved managed proxy subnetwork with purpose REGIONAL_MANAGED_PROXY is required.
原因:
此错误消息表示 Gateway 的区域中不存在代理专用子网。
临时解决方法:
如需解决此问题,请配置代理专用子网。
区域中已存在用途错误的代理专用子网
具体情况:
为区域级 Gateway(内部或外部)创建代理专用子网时,可能会出现以下问题:
ERROR: (gcloud.compute.networks.subnets.create) Could not fetch resource:
- The resource 'projects/[PROJECT_NAME]/regions/[REGION_NAME]/subnetworks/[PROXY_ONLY_SUBNET_NAME]' already exists
原因:
此错误消息表示您尝试在已具有代理专用子网的区域中创建区域级代理专用子网。
临时解决方法:
如需解决此问题,请按照以下步骤操作:
检查该区域中是否已存在代理专用子网,并验证其用途是否正确:
列出您的子网,以确定哪个是该区域中的代理专用子网:
gcloud compute networks subnets list --regions=COMPUTE_REGION
将
COMPUTE_REGION
替换为您要在其中创建区域级 Gateway 的 Compute Engine 区域。描述该区域中的代理专用子网,以确定其用途:
gcloud compute networks subnets describe PROXY_ONLY_SUBNET \ --region COMPUTE_REGION | grep -E 'name|purpose'
将
PROXY_ONLY_SUBNET
替换为代理专用子网。
GKE Gateway 仅支持区域级 Gateway(内部或区域级)的
REGIONAL_MANAGED_PROXY
代理专用子网。如果该区域中的现有代理专用子网是使用
INTERNAL_HTTPS_LOAD_BALANCER
用途创建的,请将其用途迁移到REGIONAL_MANAGED_PROXY
。
后续步骤
- 详细了解 Gateway Controller。
- 了解如何使用政策配置网关资源。