Kubernetes Gateway API ¶
Gateway API 介绍 ¶
Gateway API 架构 ¶
Gateway API(之前叫 Service API)是由 SIG-NETWORK 社区管理的开源项目,项目地址:https://gateway-api.sigs.k8s.io/。主要原因是 Ingress 资源对象不能很好的满足网络需求,很多场景下 Ingress 控制器都需要通过定义 annotations 或者 crd 来进行功能扩展,这对于使用标准和支持是非常不利的,新推出的 Gateway API 旨在通过可扩展的面向角色的接口来增强服务网络。
Gateway API 是 Kubernetes 中的一个 API 资源集合,包括 GatewayClass、Gateway、HTTPRoute、TCPRoute、Service 等,这些资源共同为各种网络用例构建模型。
Gateway API 的改进比当前的 Ingress 资源对象有很多更好的设计:
- 面向角色 - Gateway 由各种 API 资源组成,这些资源根据使用和配置 Kubernetes 服务网络的角色进行建模。
- 通用性 - 和 Ingress 一样是一个具有众多实现的通用规范,Gateway API 是一个被设计成由许多实现支持的规范标准。
- 更具表现力 - Gateway API 资源支持基于 Header 头的匹配、流量权重等核心功能,这些功能在 Ingress 中只能通过自定义注解才能实现。
- 可扩展性 - Gateway API 允许自定义资源链接到 API 的各个层,这就允许在 API 结构的适当位置进行更精细的定制。
还有一些其他值得关注的功能:
- GatewayClasses - GatewayClasses 将负载均衡实现的类型形式化,这些类使用户可以很容易了解到通过 Kubernetes 资源可以获得什么样的能力。
- 共享网关和跨命名空间支持 - 它们允许共享负载均衡器和 VIP,允许独立的路由资源绑定到同一个网关,这使得团队可以安全地共享(包括跨命名空间)基础设施,而不需要直接协调。
- 规范化路由和后端 - Gateway API 支持类型化的路由资源和不同类型的后端,这使得 API 可以灵活地支持各种协议(如 HTTP 和 gRPC)和各种后端服务(如 Kubernetes Service、存储桶或函数)。
面向角色设计 ¶
无论是道路、电力、数据中心还是 Kubernetes 集群,基础设施都是为了共享而建的,然而共享基础设施提供了一个共同的挑战,那就是如何为基础设施用户提供灵活性的同时还能被所有者控制。
Gateway API 通过对 Kubernetes 服务网络进行面向角色的设计来实现这一目标,平衡了灵活性和集中控制。它允许共享的网络基础设施(硬件负载均衡器、云网络、集群托管的代理等)被许多不同的团队使用,所有这些都受到集群运维设置的各种策略和约束。下面的例子显示了是如何在实践中运行的。
一个集群运维人员创建了一个基于 GatewayClass 的 Gateway 资源,这个 Gateway 部署或配置了它所代表的基础网络资源,集群运维和特定的团队必须沟通什么可以附加到这个 Gateway 上来暴露他们的应用。集中的策略,如 TLS,可以由集群运维在 Gateway 上强制执行,同时,Store 和 Site 应用在他们自己的命名空间中运行,但将他们的路由附加到相同的共享网关上,允许他们独立控制他们的路由逻辑。
这种关注点分离的设计可以使不同的团队能够管理他们自己的流量,同时将集中的策略和控制留给集群运维。
Gateway API 概念 ¶
在整个 Gateway API 中涉及到3个角色:基础设施提供商、集群管理员、应用开发人员,在某些场景下可能还会涉及到应用管理员等角色。Gateway API 中定义了3种主要的资源模型:GatewayClass、Gateway、Route。
GatewayClass ¶
GatewayClass 定义了一组共享相同配置和动作的网关。每个GatewayClass 由一个控制器处理,是一个集群范围的资源,必须至少有一个 GatewayClass 被定义。
这与 Ingress 的 IngressClass 类似,在 Ingress v1beta1 版本中,与 GatewayClass 类似的是 ingress-class 注解,而在Ingress V1 版本中,最接近的就是 IngressClass 资源对象。
Gateway ¶
Gateway 网关描述了如何将流量转化为集群内的服务,也就是说,它定义了一个请求,要求将流量从不了解 Kubernetes 的地方转换到集群内的服务。例如,由云端负载均衡器、集群内代理或外部硬件负载均衡器发送到 Kubernetes 服务的流量。
它定义了对特定负载均衡器配置的请求,该配置实现了 GatewayClass 的配置和行为规范,该资源可以由管理员直接创建,也可以由处理 GatewayClass 的控制器创建。
Gateway 可以附加到一个或多个路由引用上,这些路由引用的作用是将流量的一个子集导向特定的服务。
Route 资源 ¶
路由资源定义了特定的规则,用于将请求从网关映射到 Kubernetes 服务。
从 v1alpha2 版本开始,API 中包含四种 Route 路由资源类型,对于其他未定义的协议,鼓励采用特定实现的自定义路由类型,当然未来也可能会添加新的路由类型。
HTTPRoute ¶
HTTPRoute 适用于 HTTP 或 HTTPS 连接,适用于我们想要检查 HTTP 请求并使用 HTTP 请求进行路由或修改的场景,比如使用 HTTP Headers 头进行路由,或在请求过程中对它们进行修改。
TLSRoute ¶
TLSRoute 用于 TLS 连接,通过 SNI 进行区分,它适用于希望使用 SNI 作为主要路由方法的地方,并且对 HTTP 等更高级别协议的属性不感兴趣,连接的字节流不经任何检查就被代理到后端。
TCPRoute 和 UDPRoute ¶
TCPRoute(和UDPRoute)旨在用于将一个或多个端口映射到单个后端。在这种情况下,没有可以用来选择同一端口的不同后端的判别器,所以每个 TCPRoute 在监听器上需要一个不同的端口。你可以使用 TLS,在这种情况下,未加密的字节流会被传递到后端,当然也可以不使用 TLS,这样加密的字节流将传递到后端。
Gateway API 概念之间关系 ¶
使用反向代理实现的网关的典型客户端/网关 API 请求流程如下所示:
- 客户端向 http://foo.example.com 发出请求
- DNS 将域名解析为 Gateway 网关地址
- 反向代理在监听器上接收请求,并使用 Host Header 来匹配HTTPRoute
- (可选)反向代理可以根据 HTTPRoute 的匹配规则进行路由
- (可选)反向代理可以根据 HTTPRoute 的过滤规则修改请求,即添加或删除 headers
- 最后,反向代理根据 HTTPRoute 的 forwardTo 规则,将请求转发给集群中的一个或多个对象,即服务。
2. Gateway API 应用案例 ¶
配置 Kubernetes 网关提供程序并部署/公开服务
---
## 创建 ServiceAccount
apiVersion: v1
kind: ServiceAccount
metadata:
namespace: traefik
name: traefik-ingress-controller
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: gateway-role
rules:
- apiGroups:
- ""
resources:
- namespaces
verbs:
- list
- watch
- apiGroups:
- ""
resources:
- services
- endpoints
- secrets
verbs:
- get
- list
- watch
- apiGroups:
- gateway.networking.k8s.io
resources:
- gatewayclasses
- gateways
- httproutes
- tcproutes
- tlsroutes
verbs:
- get
- list
- watch
- apiGroups:
- gateway.networking.k8s.io
resources:
- gatewayclasses/status
- gateways/status
- httproutes/status
- tcproutes/status
- tlsroutes/status
verbs:
- update
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: gateway-controller
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: gateway-role
subjects:
- kind: ServiceAccount
name: traefik-ingress-controller
namespace: traefik
kubectl apply -f 01-rbac.yaml
---
## 创建 gatewayclass 资源
apiVersion: networking.x-k8s.io/v1alpha1
kind: GatewayClass
metadata:
name: my-gateway-class
spec:
controller: traefik.io/gateway-controller
---
## 创建 gateway 资源
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: Gateway
metadata:
name: my-gateway
namespace: default
spec:
gatewayClassName: my-gateway-class
listeners: # Use GatewayClass defaults for listener definition.
- name: http
protocol: HTTP
port: 80
---
## 创建 HTTPRoute 资源
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: HTTPRoute
metadata:
name: http-app
namespace: default
spec:
parentRefs:
- name: my-gateway
hostnames:
- tencent.k8s.huichengcheng.com
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: whoami
port: 80
weight: 1
kubectl apply -f 02-gatewayapi.yaml
---
## 创建 whoami deployment 资源
apiVersion: apps/v1
kind: Deployment
metadata:
name: whoami
spec:
replicas: 2
selector:
matchLabels:
app: whoami
template:
metadata:
labels:
app: whoami
spec:
containers:
- name: whoami
image: traefik/whoami
---
## 创建 whoami service 资源
apiVersion: v1
kind: Service
metadata:
name: whoami
spec:
selector:
app: whoami
ports:
- protocol: TCP
port: 80
kubectl apply -f 03-whoami.yaml
---
## 1. 编写 traefik 资源清单
apiVersion: apps/v1
kind: DaemonSet
metadata:
namespace: traefik
name: traefik
labels:
app: traefik
spec:
selector:
matchLabels:
app: traefik
template:
metadata:
labels:
app: traefik
spec:
serviceAccountName: traefik-ingress-controller
terminationGracePeriodSeconds: 1
containers:
- name: traefik
image: traefik:v2.11
args:
- --configfile=/config/traefik.yaml
- --experimental.kubernetesgateway
- --providers.kubernetesgateway
volumeMounts:
- mountPath: /config
name: config
ports:
- name: web
containerPort: 80
hostPort: 80 ## 将容器端口绑定所在服务器的 80 端口
- name: websecure
containerPort: 50000
hostPort: 50000 ## 将容器端口绑定所在服务器的 443 端口
- name: admin
containerPort: 8080 ## Traefik Dashboard 端口
- name: tcpep
containerPort: 8083
hostPort: 8083 ## 将容器端口绑定所在服务器的 8083 端口
- name: udpep
containerPort: 8084
hostPort: 8084 ## 将容器端口绑定所在服务器的 8084 端口
protocol: UDP
volumes:
- name: config
configMap:
name: traefik
tolerations: ## 设置容忍所有污点,防止节点被设置污点
- operator: "Exists"
nodeSelector: ## 设置node筛选器,在特定label的节点上启动
IngressProxy: "true"
---
## 2. 创建 service
apiVersion: v1
kind: Service
metadata:
name: traefik
namespace: traefik
labels:
app: traefik
app.kubernetes.io/name: traefik-dashboard
spec:
ports:
- protocol: TCP
name: web
port: 80
- protocol: TCP
name: websecure ## 代替 443
port: 50000
selector:
app: traefik
kubectl apply -f 04-Traefik.yaml
3. 通过 Gateway API方式暴露 WEB 应用 ¶
配置 Kubernetes gateway api 网关提供程序并部署/公开服务
---
## 1. 创建 deployment 资源
kind: Deployment
apiVersion: apps/v1
metadata:
name: nginx-web-gatewayapi
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: gatewayweb
template:
metadata:
labels:
app: gatewayweb
spec:
containers:
- name: nginx-web
image: nginx:latest
lifecycle:
postStart:
exec:
command: ["/bin/sh", "-c", "echo gatewayweb > /usr/share/nginx/html/index.html"]
ports:
- containerPort: 80
---
## 2. 创建 deployment 对应的 service 资源
apiVersion: v1
kind: Service
metadata:
name: nginx-web-gatewayapi-svc
namespace: default
spec:
ports:
- name: http
port: 80
selector:
app: gatewayweb
kubectl apply -f 01-gatewayapi-web.yaml
---
## 1. 创建 gatewayclass 资源
apiVersion: networking.x-k8s.io/v1alpha1
kind: GatewayClass
metadata:
name: my-gateway-class
spec:
controller: traefik.io/gateway-controller
---
## 2. 创建 gateway 资源
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: Gateway
metadata:
name: nginx-web-gateway
spec:
gatewayClassName: my-gateway-class
listeners:
- name: http
protocol: HTTP
port: 50000
---
## 3. 创建 gateway-httproute
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: HTTPRoute
metadata:
name: nginx-web-gateway-api-route
spec:
parentRefs:
- name: nginx-web-gateway
hostnames:
- "nginx.k8s.huichengcheng.com"
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: nginx-web-gatewayapi-svc
port: 80
weight: 1
kubectl apply -f 02-gatewayapi-web-gateway.yaml
kubectl get httproute
4. 金丝雀发布 ¶
Gateway APIs 规范可以支持的另一个功能是金丝雀发布,假设你想在一个端点上运行两个不同的服务(或同一服务的两个版本),并将一部分请求路由到每个端点,则可以通过修改你的 HTTPRoute 来实现。
配置 Kubernetes gateway api 网关提供程序并进行金丝雀发布
---
## 1. 创建 v1 版本
kind: Deployment
apiVersion: apps/v1
metadata:
name: nginx-web1
spec:
replicas: 1
selector:
matchLabels:
app: v1
template:
metadata:
labels:
app: v1
spec:
containers:
- name: nginx-web-c
image: nginx:latest
lifecycle:
postStart:
exec:
command: ["/bin/sh", "-c", "echo svc1 > /usr/share/nginx/html/index.html"]
ports:
- containerPort: 80
---
## 2. 创建 v2 版本
kind: Deployment
apiVersion: apps/v1
metadata:
name: nginx-web2
spec:
replicas: 1
selector:
matchLabels:
app: v2
template:
metadata:
labels:
app: v2
spec:
containers:
- name: nginx-web-c
image: nginx:latest
lifecycle:
postStart:
exec:
command: ["/bin/sh", "-c", "echo svc2 > /usr/share/nginx/html/index.html"]
ports:
- containerPort: 80
---
## 3. 创建 两个版本的 service
apiVersion: v1
kind: Service
metadata:
name: svc1
spec:
ports:
- name: http
port: 80
selector:
app: v1
---
apiVersion: v1
kind: Service
metadata:
name: svc2
spec:
ports:
- name: http
port: 80
selector:
app: v2
kubectl apply -f 01-gateway-cn-deploy.yaml
---
## 1. 创建 gatewayclass 资源
apiVersion: networking.x-k8s.io/v1alpha1
kind: GatewayClass
metadata:
name: my-gateway-class
spec:
controller: traefik.io/gateway-controller
---
## 2. 创建 gateway 资源
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: Gateway
metadata:
name: nginx-web-gateway
spec:
gatewayClassName: my-gateway-class
listeners:
- name: http
protocol: HTTP
port: 50000
---
## 3. 创建 gateway-httproute
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: HTTPRoute
metadata:
name: nginx-web-gateway-api-route
spec:
parentRefs:
- name: nginx-web-gateway
hostnames:
- "nginx1.k8s.huichengcheng.com"
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: svc1
port: 80
weight: 3 # 3/4 的请求到svc1
- name: svc2
port: 80
weight: 3 # 3/4 的请求到svc1