本页面介绍如何在 Google Kubernetes Engine (GKE) 上部署 Kubernetes 网关资源。此外,还介绍了如何部署专用网关和面向互联网的网关来公开应用,并演示了 Gateway API 资源模型的一些概念。
多集群负载均衡的网关部署目前为预览版。如需了解如何部署网关以实现多集群负载均衡,请参阅部署多集群网关。
准备工作
在开始之前,请确保您已执行以下任务:
- 启用 Google Kubernetes Engine API。 启用 Google Kubernetes Engine API
- 如果您要使用 Google Cloud CLI 执行此任务,请安装并初始化 gcloud CLI。
GKE Gateway Controller 要求
- 对于标准版,需要 GKE 1.24 或更高版本。
- Google Cloud CLI 407.0.0 版或更高版本。
- 仅 VPC 原生集群支持 Gateway API。
- 如果您使用的是内部 GatewayClass,则必须启用代理专用子网。
- 如果您使用的是 Istio,则必须将 Istio 升级到以下版本之一:
- 1.15.2 或更高版本
- 1.14.5 或更高版本
- 1.13.9 或更高版本。
- 您不能将 Gateway
v1alpha
API 与 Istio 搭配使用。如需了解详情,请参阅 Kubernetes Gateway 和 Istio Gateway。 - Gateway API 不支持
networking.gke.io/app-protocols
注解。请改用appProtocol
字段。
限制和已知问题
存在以下限制:
- GKE GatewayClass 支持不同的功能,具体取决于它们使用的负载均衡器。如需详细了解每个 GatewayClass 支持的不同功能,请参阅 GatewayClass 功能。
- 您可以在 Google Cloud 控制台中查看 GKE 为网关创建的负载均衡器资源,但这些资源不会引用它们所连接的网关或 GKE 集群。
- 您无法在 Google Cloud 控制台中查看网关、HTTPRoute 和政策资源。您可以使用 Kubernetes API 发现和管理网关资源。
- 您无法使用网关自动生成 Google 管理的 SSL 证书,但可以手动创建和引用 Google 管理的 SSL 证书。如需了解详情,请参阅保护网关安全。
- 您必须在同一宿主项目或服务项目中的 GKE 集群中部署网关。不支持跨项目部署。
- 正式版中的内部 GatewayClass(内部 HTTP[S] 负载均衡器)支持流量管理功能。预览版中的
gke-l7-global-external-managed
和gke-l7-global-external-managed-mc
GatewayClass 支持外部 GatewayClass(外部 HTTP[S] 负载均衡器)。 - HTTPRoute 是唯一受支持的路由类型。不支持 TCPRoute、UDPRoute 和 TLSRoute。如需查看 GKE Gateway Controller 支持的字段列表,请参阅 GatewayClass 功能。
GKE Gateway 不支持以下负载均衡功能:
- Cloud CDN。
- Identity-Aware Proxy。
- Google Cloud Armor。
- SSL 政策。
- 从 HTTP 到 HTTPS 的重定向。
- 自定义请求和响应标头
- 将 GKE Gateway Controller 控制器与 Compute Engine 上的 Kubernetes(自行管理的 Kubernetes)搭配使用。
FrontendConfig
和BackendConfig
资源。请改用 Gateway 政策。
在集群中启用 Gateway API
在 GKE 中使用网关资源之前,您的集群必须启用 Gateway API。此 API 由 --gateway-api
标志控制。您可以在启用时使用值 standard
,在停用时使用 disabled
。
创建启用 Gateway API 的新集群
创建启用 Gateway API 的新 VPC 原生 GKE 集群:
gcloud container clusters create CLUSTER_NAME \
--gateway-api=standard \
--cluster-version=VERSION \
--region=COMPUTE_REGION
请替换以下内容:
CLUSTER_NAME
:集群的名称。VERSION
:GKE 版本,必须为 1.24 或更高版本。您还可以使用--release-channel
标志来选择发布渠道。发布渠道必须具有默认版本 1.24 或更高版本。COMPUTE_REGION
:新集群的 Compute Engine 区域。对于区域级集群,请使用--zone=COMPUTE_ZONE
。
--gateway-api=standard
标志指示 GKE 使用集群安装 v1beta1
CRD。
在现有集群上启用 Gateway API
更新现有 VPC 原生集群:
gcloud container clusters update CLUSTER_NAME \
--gateway-api=standard \
--region=COMPUTE_REGION
请替换以下内容:
CLUSTER_NAME
:现有集群的名称。COMPUTE_REGION
:集群的 Compute Engine 区域。对于区域级集群,请使用--zone=COMPUTE_ZONE
。
验证集群
创建或升级集群后,GKE Gateway Controller 会自动安装 GatewayClass。控制器可能需要几分钟时间才能识别 CRD 并安装 GatewayClass。
确认您的集群中安装了 GatewayClass:
kubectl get gatewayclass
输出类似于以下内容:
NAME CONTROLLER ACCEPTED AGE
gke-l7-global-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 的网络访问的应用。
配置代理专用子网
您必须先配置代理专用子网,然后才能创建使用内部 HTTP(S) 负载均衡器的网关。在使用内部 HTTP(S) 负载均衡器的 VPC 中,每个区域都必须具有一个代理专用子网。此子网为负载均衡器代理提供了内部 IP 地址。
创建代理专用子网:
gcloud compute networks subnets create SUBNET_NAME \ --purpose=REGIONAL_MANAGED_PROXY \ --role=ACTIVE \ --region=REGION \ --network=VPC_NETWORK_NAME \ --range=CIDR_RANGE
请替换以下内容:
SUBNET_NAME
:代理专用子网的名称。REGION
:代理专用子网的区域。VPC_NETWORK_NAME
:包含子网的 VPC 网络的名称。CIDR_RANGE
:子网的主要 IP 地址范围。使用的子网掩码长度不得超过/26
,以确保至少有 64 个 IP 地址可用于该区域中的代理。建议的子网掩码为/23
。
验证代理专用子网:
gcloud compute networks subnets describe SUBNET_NAME \ --region=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
对应于区域内部 HTTP(S) 负载均衡器。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": "us-central1-a" }
转到
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": "us-central1-a" }
最后,使用
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": "us-central1-a" }
部署外部网关
外部网关公开可从互联网或 VPC 外部网络访问的应用。外部网关部署与内部网关部署类似,但您必须保护应用的安全,因为公共互联网可以访问网关。
作为平台管理员,您可能需要使用外部网关公开应用。以下示例展示了如何将多个证书附加到网关并将证书分组到证书映射,并使用 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-gxlb listeners: - name: https protocol: HTTPS port: 443
此清单描述了具有以下字段的网关:
gatewayClassName: gke-l7-gxlb
:指定此网关的 GatewayClass。此网关类使用全球外部 HTTP(S) 负载均衡器(经典版)。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 gateways.gateway.networking.k8s.io external-http
输出类似于以下内容:
Spec: Gateway Class Name: gke-l7-gxlb Listeners: Allowed Routes: Namespaces: From: Same Name: https Port: 443 Protocol: HTTPS 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:37:21Z Message: Reason: Ready Status: True Type: Ready Listeners: Attached Routes: 0 Conditions: Last Transition Time: 2022-11-01T05:37:21Z Message: Reason: Ready Status: True Type: Ready Name: https Supported Kinds: Group: gateway.networking.k8s.io Kind: HTTPRoute Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal ADD 50s sc-gateway-controller default/external-http Normal UPDATE 5s (x3 over 50s) sc-gateway-controller default/external-http Normal SYNC 5s sc-gateway-controller SYNC on default/external-http was a success
此输出显示集群中部署的网关具有负载均衡器和公共 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" }
使用共享 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 的允许条件为
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": "us-central1-a" } ... { "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": "us-central1-a" }
配置 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 地址池 |
---|---|
|
主节点 IP 地址范围内的区域级专用 IP 地址 |
|
Google 的公共 IP 范围中的全球公共 IP 地址 |
addresses.NamedAddress
字段可让您指定独立于网关的 IP 地址。您可以在网关部署之前创建静态 IP 地址资源,并且 NamedAddress
会引用该资源。即使网关已删除,您也可以重复使用静态 IP 地址。
使用已命名的 IP 地址
您可以通过指定 NamedAddress
来配置 IP 地址。您必须先预配静态 IP 地址,然后才能创建 Gateway。
为全球级或区域级 Gateway 创建静态 IP 地址资源:
gcloud compute addresses create IP_ADDRESS_NAME \ --purpose=SHARED_LOADBALANCER_VIP \ --region=REGION \ --subnet=SUBNET \ --project=PROJECT_ID
请替换以下内容:
IP_ADDRESS_NAME
:新的静态 IP 地址的名称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
路由状态
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-gxlb-mc
$ kubectl get gateway.networking.x-k8s.io
NAME CLASS
multi-cluster-gateway gke-l7-gxlb-mc
# Istio Gateway
$ kubectl get gw
NAME AGE
bookinfo-gateway 64m
$ kubectl get gateway.networking.istio.io
NAME AGE
bookinfo-gateway 64m
问题排查
内部网关缺少代理专用子网
创建内部网关时可能会出现以下问题:
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 and active subnetwork is required in the same region and VPC as the forwarding rule.
如需解决此问题,请配置代理专用子网。
后续步骤
- 详细了解 Gateway Controller。
- 了解如何使用政策配置网关资源。