Gateway API-2


Gateway API

目录

[toc]

原文链接

https://onedayxyy.cn/docs/GatewayAPI/

本节实战

实战名称
🚩 实战:配置请求路由-2023.12.27
🚩 实战:路由到指定版本-2023.12.27
🚩 实战:基于用户身份路由-2023.12.27
🚩 实战:基于权重的路由-2023.12.27
🚩 实战:使用 TLS 暴露服务-2023.12.27

配置请求路由

接下来我们来了解下如果通过 Gateway API 将请求动态路由到微服务的多个版本。

同样我们这里以 Bookinfo 示例为例(首先要部署 Bookinfo 应用),我们首先将所有流量路由到微服务的 v1 (版本 1),然后将应用规则根据 HTTP 请求 header 的值路由流量。

🚩 实战:配置请求路由-2023.12.27

🔱 说明:

此部分实战因自己Gatway API部署失败导致无法进一步测试,这里仅维护文档。

  • 测试环境
k8s v1.27.6(containerd://1.6.20)(cni:flannel:v0.22.2)
istio v1.19.3(--set profile=demo)

实验软件:

链接:https://pan.baidu.com/s/1pMnJxgL63oTlGFlhrfnXsA?pwd=7yqb
提取码:7yqb
2023.11.5-实战:BookInfo 示例应用-2023.11.5(测试成功)

image-20231105111842627

  • 首先要部署 Bookinfo 应用(部署方式见之前文章)

  • 首先专门为 Bookinfo 应用创建一个 Gateway 资源对象,如下所示:

# bookinfo-gateway.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: bookinfo-gateway
spec:
  gatewayClassName: istio
  listeners:
    - name: http
      port: 80
      protocol: HTTP
      allowedRoutes:
        namespaces:
          from: Same

上面的 Gateway 资源对象与之前的示例类似,只是这里我们将 allowedRoutes 设置为 Same表示允许同一命名空间中的所有路由资源对象都可以连接到这个网关。

  • 然后为 Productpage 应用创建一个 HTTPRoute 资源对象,如下所示:
# productpage-route.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: bookinfo
spec:
  parentRefs:
    - name: bookinfo-gateway # 引用上面定义的 Gateway 对象
  rules:
    - matches:
        - path:
            type: Exact
            value: /productpage
        - path:
            type: PathPrefix
            value: /static
        - path:
            type: Exact
            value: /login
        - path:
            type: Exact
            value: /logout
        - path:
            type: PathPrefix
            value: /api/v1/products
      backendRefs:
        - name: productpage # 引用的后端服务
          port: 9080

和以前 VirtualService 的类似,我们为 Productpage 应用配置了几个路由规则,这样我们就可以在页面上正常访问应用了。

  • 直接应用上面的两个资源清单文件即可:
kubectl apply -f bookinfo-gateway.yaml
kubectl apply -f productpage-route.yaml
  • 同样当我们创建了 Gateway 对象后,会自动在 default 命名空间中部署一个 gateway-istio 的 Deployment 和 对应的 Service:
$ kubectl get pods -l istio.io/gateway-name=bookinfo-gateway
NAME                                      READY   STATUS    RESTARTS   AGE
bookinfo-gateway-istio-548556df95-kggs2   1/1     Running   0          112s
$ kubectl get svc bookinfo-gateway-istio
NAME                     TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)                        AGE
bookinfo-gateway-istio   LoadBalancer   10.111.86.147   <pending>     15021:30357/TCP,80:30749/TCP   2m19s
  • 正常我们就可以通过上面的 30749 这个 NodePort 端口来访问 Productpage 应用了:

img

测试结束。😘

路由到指定版本

同样的页面上的评论区域会出现 3 种不同的状态,因为我们背后有 3 个不同的版本的评论服务。

🚩 实战:路由到指定版本-2023.12.27

🔱 说明:

此部分实战因自己Gatway API部署失败导致无法进一步测试,这里仅维护文档。

  • 测试环境
k8s v1.27.6(containerd://1.6.20)(cni:flannel:v0.22.2)
istio v1.19.3(--set profile=demo)

实验软件:

链接:https://pan.baidu.com/s/1pMnJxgL63oTlGFlhrfnXsA?pwd=7yqb
提取码:7yqb
2023.11.5-实战:BookInfo 示例应用-2023.11.5(测试成功)

image-20231105111842627

  • 我们可以创建一个如下所示的 HTTPRoute 资源对象,首先将流量路由到 v1 版本:
# route-reviews-v1.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: reviews
spec:
  parentRefs: # 这里我们引用的是 reviews 这个 Service 对象
    - group: ""
      kind: Service
      name: reviews
      port: 9080
  rules:
    - backendRefs:
        - name: reviews-v1
          port: 9080

注意上面的资源对象中我们是通过 parentRefs 字段引用的是 reviews 这个 Service 对象,而不是 Gateway 对象了,因为我们流量并不是从 Gateway 直接过来的,而是通过 Productpage 访问 reviews 服务,也就是 Service 对象。然后背后的我们会将流量全部路由到 v1 版本的 reviews 服务 reviews-v1

  • 现在我们再应用上面的这个资源对象:
kubectl apply -f route-reviews-v1.yaml

不过这里需要注意不同于 Istio API 使用 DestinationRule 子集来定义服务的版本, Kubernetes Gateway API 将为此使用后端 Service 服务来进行定义。

  • 所以我们还需要运行以下命令为三个版本的 reviews 服务创建后端服务定义:
kubectl apply -f samples/bookinfo/platform/kube/bookinfo-versions.yaml
  • 然后我们可以通过再次刷新 Bookinfo 应用程序,现在我们无论刷新多少次,页面的评论部分都不会显示评级星标,这是因为我们将 Istio 配置为将评论服务的所有流量路由到版本 reviews:v1,而此版本的服务不访问星级评分服务。

img

测试结束。😘

基于用户身份路由

接下来我们来更改路由配置,将来自特定用户的所有流量路由到特定服务版本,比如将来自名为 Jason 的用户的所有流量被路由到服务 reviews:v2(包含星级评分功能的版本)。

🚩 实战:基于用户身份路由-2023.12.27

🔱 说明:

此部分实战因自己Gatway API部署失败导致无法进一步测试,这里仅维护文档。

  • 测试环境
k8s v1.27.6(containerd://1.6.20)(cni:flannel:v0.22.2)
istio v1.19.3(--set profile=demo)

实验软件:

链接:https://pan.baidu.com/s/1pMnJxgL63oTlGFlhrfnXsA?pwd=7yqb
提取码:7yqb
2023.11.5-实战:BookInfo 示例应用-2023.11.5(测试成功)

image-20231105111842627

  • 创建一个如下所示的 HTTPRoute 资源对象:
# route-reviews-jason-v2.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: reviews
spec:
  parentRefs:
    - group: ""
      kind: Service
      name: reviews
      port: 9080
  rules:
    - matches:
        - headers: # 匹配请求头 end-user: jason
            - name: end-user
              value: jason
      backendRefs:
        - name: reviews-v2
          port: 9080
    - backendRefs:
        - name: reviews-v1
          port: 9080

在上面的 HTTPRoute 资源对象中,我们将访问 reviews 的流量分为两个规则,第一个规则匹配请求头 end-user: jason,然后将流量路由到 reviews-v2 服务,第二个则是如果不匹配将流量路由到 reviews-v1 服务。

  • 然后我们再次应用这个资源对象:
kubectl apply -f route-reviews-jason-v2.yaml
  • 然后我们在 Bookinfo 页面上面,可以以用户 jason 身份进行登录,登录后无论如何刷新浏览器,我们将始终在页面上看到黑色的星级评分,也就是 reviews 的 v2 版本。

img

我们也可以切换成其他用户,或者不登录,刷新浏览器,那么就不会显示星级评分了。

测试成功。😘

基于权重的路由

接下来我们再来测试下基于权重的路由,常常我们有将流量从微服务的一个版本逐步迁移到另一个版本的需求,同样使用 Gateway API 来实现也非常简单。

下面我们将会把 50% 的流量发送到 reviews:v1,另外,50% 的流量发送到 reviews:v3。接着,再把 100% 的流量发送到 reviews:v3 来完成迁移。

🚩 实战:基于权重的路由-2023.12.27

🔱 说明:

此部分实战因自己Gatway API部署失败导致无法进一步测试,这里仅维护文档。

  • 测试环境
k8s v1.27.6(containerd://1.6.20)(cni:flannel:v0.22.2)
istio v1.19.3(--set profile=demo)

实验软件:

链接:https://pan.baidu.com/s/1pMnJxgL63oTlGFlhrfnXsA?pwd=7yqb
提取码:7yqb
2023.11.5-实战:BookInfo 示例应用-2023.11.5(测试成功)

image-20231105111842627

  • 首先重新运行下面的命令将所有流量路由到 review 服务的 v1 版本。
kubectl apply -f route-reviews-v1.yaml
  • 接下来创建如下所示的资源对象,把 50% 的流量从 reviews:v1 转移到 reviews:v3
# route-reviews-50-v3.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: reviews
spec:
  parentRefs:
    - group: ""
      kind: Service
      name: reviews
      port: 9080
  rules:
    - backendRefs:
        - name: reviews-v1
          port: 9080
          weight: 50
        - name: reviews-v3
          port: 9080
          weight: 50

上面的对象中在 backendRefs 中我们使用了一个 weight 字段,用于设置权重,这里我们将 reviews-v1reviews-v3 的权重都设置为 50,也就是说将流量平均分配到这两个版本的服务上。

  • 然后我们应用这个资源对象即可:
kubectl apply -f route-reviews-50-v3.yaml
  • 等待几秒钟,等待新的规则传播到代理中生效,然后我们再次刷新浏览器中的 productpage 页面,大约有 50% 的几率会看到页面中带红色星级的评价内容。 这是因为 reviews 的 v3 版本可以访问带星级评价,但 v1 版本不能。

  • 如果你认为 reviews:v3 微服务已经稳定,那么接下来我们就可以将 100% 的流量路由 reviews:v3

# route-reviews-v3.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: reviews
spec:
  parentRefs:
    - group: ""
      kind: Service
      name: reviews
      port: 9080
  rules:
    - backendRefs:
        - name: reviews-v3
          port: 9080
  • 然后我们再次应用这个资源对象:
kubectl apply -f route-reviews-v3.yaml
  • 现在,当我们访问 Bookinfo 应用时,将始终看到带有红色星级评分的书评。

测试成功😘。

使用 TLS 暴露服务

接下来我们来看下如何通过 TLS 来暴露服务,这里我们以 httpbin 示例进行说明。

🚩 实战:使用 TLS 暴露服务-2023.12.27

🔱 说明:

此部分实战因自己Gatway API部署失败导致无法进一步测试,这里仅维护文档。

  • 测试环境
k8s v1.27.6(containerd://1.6.20)(cni:flannel:v0.22.2)
istio v1.19.3(--set profile=demo)

实验软件:

链接:https://pan.baidu.com/s/1pMnJxgL63oTlGFlhrfnXsA?pwd=7yqb
提取码:7yqb
2023.11.5-实战:BookInfo 示例应用-2023.11.5(测试成功)

image-20231105111842627

  • 首先要部署 httpbin 示例:
kubectl apply -f samples/httpbin/httpbin.yaml

然后接下来生成客户端和服务器证书和密钥,这里我们使用 openssl 工具来生成。

  • 首先创建用于服务签名的根证书和私钥:
$ mkdir example_certs1
$ openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -subj '/O=example Inc./CN=example.com' -keyout example_certs1/example.com.key -out example_certs1/example.com.crt
  • httpbin.example.com 创建证书和私钥:
$ openssl req -out example_certs1/httpbin.example.com.csr -newkey rsa:2048 -nodes -keyout example_certs1/httpbin.example.com.key -subj "/CN=httpbin.example.com/O=httpbin organization"
$ openssl x509 -req -sha256 -days 365 -CA example_certs1/example.com.crt -CAkey example_certs1/example.com.key -set_serial 0 -in example_certs1/httpbin.example.com.csr -out example_certs1/httpbin.example.com.crt
  • 然后接下来需要为入口网关创建 Secret:
kubectl create -n istio-system secret tls httpbin-credential \
  --key=example_certs1/httpbin.example.com.key \
  --cert=example_certs1/httpbin.example.com.crt
  • 这里我们创建一个独立的 Kubernetes Gateway:
# httpbin-gateway.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: mygateway
  namespace: istio-system
spec:
  gatewayClassName: istio
  listeners:
    - name: https
      hostname: "httpbin.example.com"
      port: 443
      protocol: HTTPS
      tls:
        mode: Terminate
        certificateRefs:
          - name: httpbin-credential
      allowedRoutes:
        namespaces:
          from: Selector
          selector:
            matchLabels:
              kubernetes.io/metadata.name: default

在上面的对象中我们配置了 HTTPS 协议,并在 tls 中配置使用 Terminate 模式,也就是说我们将在网关上终止 TLS 连接,然后在 certificateRefs 中引用了之前创建的 Secret 对象,用于配置网关的凭据。最后通过 allowedRoutes 字段配置了允许的路由,这里我们配置的是将流量路由到 default 命名空间中的所有路由资源对象。

  • 接下来,通过定义相应的 HTTPRoute 配置网关的入口流量路由:
# httpbin-route.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: httpbin
spec:
  parentRefs:
    - name: mygateway
      namespace: istio-system
  hostnames: ["httpbin.example.com"]
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /status
        - path:
            type: PathPrefix
            value: /delay
      backendRefs:
        - name: httpbin
          port: 8000

这里最重要的就是在 parentRefs 字段中引用了之前创建的 Gateway 对象。

  • 然后我们直接应用上面的两个资源对象即可:
kubectl apply -f httpbin-gateway.yaml
kubectl apply -f httpbin-route.yaml
  • 同样应用后会自动在 istio-system 命名空间中部署一个 gateway-istio 的 Deployment 和对应的 Service:
$ kubectl get pods -n istio-system
NAME                                       READY   STATUS    RESTARTS         AGE
mygateway-istio-64676bfc88-q8nft           1/1     Running   0                32s
$ kubectl get svc -n istio-system
NAME                      TYPE           CLUSTER-IP       EXTERNAL-IP   PORT(S)                                                                      AGE
mygateway-istio           LoadBalancer   10.111.175.36    <pending>     15021:31206/TCP,443:32597/TCP                                                74s
  • 然后我们可以通过 32597 这个 NodePort 端口向 httpbin 服务发送 HTTPS 请求:
$ curl -v -HHost:httpbin.example.com --resolve "httpbin.example.com:32597:192.168.0.100" --cacert example_certs1/example.com.crt "https://httpbin.example.com:32597/status/418"

* Initializing NSS with certpath: sql:/etc/pki/nssdb
*   CAfile: example_certs1/example.com.crt
  CApath: none
* SSL connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
* Server certificate:
*       subject: O=httpbin organization,CN=httpbin.example.com
*       start date: Dec 22 07:13:47 2023 GMT
*       expire date: Dec 21 07:13:47 2024 GMT
*       common name: httpbin.example.com
*       issuer: CN=example.com,O=example Inc.
# ......

    -=[ teapot ]=-

       _...._
     .'  _ _ `.
    | ."` ^ `". _,
    \_;`"---"`|//
      |       ;/
      \_     _/
        `"""`
* Connection #0 to host httpbin.example.com left intact

正常我们就可以看到输出一个茶壶,这样我们完成了通过 TLS 来暴露服务。

测试成功。😘

TCP 路由

除了 HTTP 路由外,Gateway API 还支持 TCP 和 UDP 路由,配置 TCP 的路由规则,需要使用单独的资源对象 TCPRoute,如下所示:

apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: tcp-echo-gateway
spec:
  gatewayClassName: istio
  listeners:
    - name: tcp-31400
      protocol: TCP
      port: 31400
      allowedRoutes: # 只允许 TCPRoute 资源对象连接到这个网关
        kinds:
          - kind: TCPRoute
---
apiVersion: v1
kind: Service
metadata:
  name: tcp-echo-v1
spec:
  ports:
    - port: 9000
      name: tcp
  selector:
    app: tcp-echo
    version: v1
---
apiVersion: v1
kind: Service
metadata:
  name: tcp-echo-v2
spec:
  ports:
    - port: 9000
      name: tcp
  selector:
    app: tcp-echo
    version: v2
---
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: TCPRoute # TCPRoute 资源对象
metadata:
  name: tcp-echo
spec:
  parentRefs: # 引用定义的 Gateway 对象
    - name: tcp-echo-gateway
      sectionName: tcp-31400
  rules:
    - backendRefs:
        - name: tcp-echo-v1
          port: 9000
          weight: 80
        - name: tcp-echo-v2
          port: 9000
          weight: 20

其他使用

其他的流量管理比如故障注入、熔断这些,Gateway API 尚不支持。

但是支持请求超时,比如对 reviews 服务的调用增加一个半秒的请求超时,可以使用下面的资源对象:

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: reviews
spec:
  parentRefs:
    - group: ""
      kind: Service
      name: reviews
      port: 9080
  rules:
    - backendRefs:
        - name: reviews-v2
          port: 9080
      timeouts:
        request: 500ms

上面的对象中我们添加了一个 timeouts 字段,用于设置请求超时时间。

同样还支持流量镜像,如下的资源对象:

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: httpbin
spec:
  parentRefs:
    - group: ""
      kind: Service
      name: httpbin
      port: 8000
  rules:
    - filters:
        - type: RequestMirror
          requestMirror:
            backendRef:
              name: httpbin-v2
              port: 80
      backendRefs:
        - name: httpbin-v1
          port: 80

在上面的资源对象中我们添加了一个 RequestMirror 过滤器,该过滤器用于将流量镜像到另外的服务上去。

关于我

我的博客主旨:

  • 排版美观,语言精炼;
  • 文档即手册,步骤明细,拒绝埋坑,提供源码;
  • 本人实战文档都是亲测成功的,各位小伙伴在实际操作过程中如有什么疑问,可随时联系本人帮您解决问题,让我们一起进步!

🍀 微信二维码

x2675263825 (舍得), qq:2675263825。

image-20230107215114763

🍀 微信公众号

《云原生架构师实战》

image-20230107215126971

🍀 个人博客站点

http://onedayxyy.cn/

🍀 语雀

https://www.yuque.com/xyy-onlyone

🍀 csdn

https://blog.csdn.net/weixin_39246554?spm=1010.2135.3001.5421

image-20230107215149885

🍀 知乎

https://www.zhihu.com/people/foryouone

image-20230107215203185

最后

好了,关于本次就到这里了,感谢大家阅读,最后祝大家生活快乐,每天都过的有意义哦,我们下期见!


文章作者: hg
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 hg !
  目录