API 网关、Kubernetes 网关和服务网格综合指南

港控/mmm° 2024-03-16 18:00 180阅读 0赞

关于 API 网关、Kubernetes 网关和服务网格,仍然存在很多混淆。很多是因为:

  1. 人们经常用相同的关键词提及这些技术,例如金丝雀部署、速率限制和服务发现。
  2. 所有这些技术都使用反向代理。
  3. 一些 API 网关有自己的 Kubernetes 网关和服务网格,反之亦然。
  4. 有很多文章/视频对这三种技术进行了比较,并得出了为什么一种技术优于另一种技术的结论。

在本文中,我将尝试解释这些技术并分享它们的根本区别以及如何迎合不同的用例。

API网关

API 网关位于您的客户端应用程序和 API 之间。它接受所有客户端请求,将它们转发到所需的 API,并在组合包中将响应返回给客户端。

它基本上是一个具有很多功能的反向代理。

d4b20828b84ebacb37d0c8e8d9ade139.png

除此之外,API 网关还可以具有身份验证、安全性、细粒度流量控制和监控等功能,让 API 开发人员只关注业务需求。

有许多可用的 API 网关解决方案。一些流行的免费和开源解决方案是:

  • Apache APISIX:构建在 Nginx 之上的高性能、可扩展的云原生 API 网关。
  • Gloo Edge:一个建立在 Envoy 代理之上的 API 网关。
  • Kong:一个可插入的 API 网关,也是基于 Nginx 构建的。
  • Tyk:一个用 Go 编写的 API 网关,支持 REST、GraphQL、TCP 和 gRPC 协议。

GCP、AWS和Azure等云平台也有自己专有的 API 网关。

API 网关、Kubernetes 网关和服务网格支持金丝雀部署——在新软件版本普遍可用之前逐渐向一小部分用户推出新软件版本。

下面的示例展示了如何在 Apache APISIX 中配置金丝雀部署。

631e99a61a90506acb702d798f1daa82.png

您可以使用以下配置向APISIX Admin API发送请求:

  1. <span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>curl http://127.0.0.1:9180/apisix/admin/routes/1 <span style="color:var(--syntax-literal-color)">\</span>
  2. <span style="color:var(--syntax-error-color)">-H</span> <span style="color:var(--syntax-string-color)">'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1'</span> <span style="color:var(--syntax-error-color)">-X</span> PUT <span style="color:var(--syntax-error-color)">-d</span> <span style="color:var(--syntax-string-color)">'
  3. {
  4. "uri":"/*",
  5. "plugins":{
  6. "traffic-split":{
  7. "rules":[
  8. {
  9. "weighted_upstreams":[
  10. {
  11. "upstream":{
  12. "name":"api-v1",
  13. "type":"roundrobin",
  14. "nodes":{
  15. "api-v1:8080":1
  16. }
  17. },
  18. "weight":95
  19. },
  20. {
  21. "weight":5
  22. }
  23. ]
  24. }
  25. ]
  26. }
  27. },
  28. "upstream":{
  29. "type":"roundrobin",
  30. "nodes":{
  31. "api-v2:8080":1
  32. }
  33. }
  34. }'</span>
  35. </code></span></span>

APISIX 现在会将 95% 的流量路由到 api-v1 服务,将 5% 的流量路由到 api-v2 服务。

Kubernetes 网关

Kubernetes 网关只是 Kubernetes 原生 API 网关。也就是说,您可以使用 Kubernetes API 管理这些 API 网关,类似于 Kubernetes pod、服务或部署。

在 Kubernetes 中,您的 API 是部署在集群中的 pod 和服务。然后,您使用 Kubernetes 网关将外部流量定向到您的集群。

Kubernetes 提供了两个 API 来实现这一点,Ingress API和Gateway API。

240cbd3722d67b3499f60556f900c2c9.png

Kubernetes 入口 API

Ingress API 的创建是为了通过引入路由和 SSL 终止等功能来克服默认服务类型NodePort和LoadBalancer的限制。它还标准化了将 Kubernetes 服务暴露给外部流量的方式。

它有两个组件,Ingress和Ingress controller。

Ingress Kubernetes 本机对象定义了一组关于外部流量如何访问您的服务的规则。

此示例配置显示了基于 URI 路径和 Kubernetes Ingress 对象的路由流量:

  1. <span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-name-color)">apiVersion</span>: <span style="color:var(--syntax-string-color)">networking.k8s.io/v1</span>
  2. <span style="color:var(--syntax-name-color)">kind</span>: <span style="color:var(--syntax-string-color)">Ingress</span>
  3. <span style="color:var(--syntax-name-color)">metadata</span>:
  4. <span style="color:var(--syntax-name-color)">name</span>: <span style="color:var(--syntax-string-color)">api-routes</span>
  5. <span style="color:var(--syntax-name-color)">spec</span>:
  6. <span style="color:var(--syntax-name-color)">ingressClassName</span>: <span style="color:var(--syntax-string-color)">apisix</span>
  7. <span style="color:var(--syntax-name-color)">rules</span>:
  8. - <span style="color:var(--syntax-name-color)">http</span>:
  9. <span style="color:var(--syntax-name-color)">paths</span>:
  10. - <span style="color:var(--syntax-name-color)">backend</span>:
  11. <span style="color:var(--syntax-name-color)">service</span>:
  12. <span style="color:var(--syntax-name-color)">name</span>: <span style="color:var(--syntax-string-color)">api-v1</span>
  13. <span style="color:var(--syntax-name-color)">port</span>:
  14. <span style="color:var(--syntax-name-color)">number</span>: <span style="color:var(--syntax-literal-color)">8080</span>
  15. <span style="color:var(--syntax-name-color)">path</span>: <span style="color:var(--syntax-string-color)">/v1</span>
  16. <span style="color:var(--syntax-name-color)">pathType</span>: <span style="color:var(--syntax-string-color)">Exact</span>
  17. - <span style="color:var(--syntax-name-color)">backend</span>:
  18. <span style="color:var(--syntax-name-color)">service</span>:
  19. <span style="color:var(--syntax-name-color)">name</span>: <span style="color:var(--syntax-string-color)">api-v2</span>
  20. <span style="color:var(--syntax-name-color)">port</span>:
  21. <span style="color:var(--syntax-name-color)">number</span>: <span style="color:var(--syntax-literal-color)">8080</span>
  22. <span style="color:var(--syntax-name-color)">path</span>: <span style="color:var(--syntax-string-color)">/v2</span>
  23. <span style="color:var(--syntax-name-color)">pathType</span>: <span style="color:var(--syntax-string-color)">Exact</span>
  24. </code></span></span>

Ingress 控制器实施这些规则并使用反向代理将流量路由到您的集群。

有超过20 个 Ingress 控制器实现。APISIX 有一个Ingress 控制器,它环绕 APISIX API 网关以作为 Kubernetes Ingress 工作。

c29a5ec77ddbab26bfdb30cb6d806ed4.png

APISIX Ingress 控制器将 Kubernetes Ingress 对象转换为 APISIX 配置。

f2a8a5b5db78d2445b5a3b8a49ab2f32.png

APISIX 然后实现此配置。

2dacb503e1b2b5ff30fe9082d230127f.png

您可以将 APISIX 与任何其他 Ingress 控制器交换,因为 Ingress API 不依赖于任何特定的实现。

这种供应商中立性适用于简单的配置。但是如果你想像金丝雀部署那样做复杂的路由,你必须依赖供应商特定的注解。

下面的示例显示了如何使用Nginx Ingress配置金丝雀部署。这里使用的自定义注释是特定于 Nginx 的:

  1. <span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-name-color)">apiVersion</span>: <span style="color:var(--syntax-string-color)">networking.k8s.io/v1</span>
  2. <span style="color:var(--syntax-name-color)">kind</span>: <span style="color:var(--syntax-string-color)">Ingress</span>
  3. <span style="color:var(--syntax-name-color)">metadata</span>:
  4. <span style="color:var(--syntax-name-color)">annotations</span>:
  5. <span style="color:var(--syntax-name-color)">nginx.ingress.kubernetes.io/canary</span>: <span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-string-color)">true"</span>
  6. <span style="color:var(--syntax-name-color)">nginx.ingress.kubernetes.io/canary-weight</span>: <span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-string-color)">5"</span>
  7. <span style="color:var(--syntax-name-color)">name</span>: <span style="color:var(--syntax-string-color)">api-canary</span>
  8. <span style="color:var(--syntax-name-color)">spec</span>:
  9. <span style="color:var(--syntax-name-color)">rules</span>:
  10. - <span style="color:var(--syntax-name-color)">http</span>:
  11. <span style="color:var(--syntax-name-color)">paths</span>:
  12. - <span style="color:var(--syntax-name-color)">backend</span>:
  13. <span style="color:var(--syntax-name-color)">serviceName</span>: <span style="color:var(--syntax-string-color)">api-v2</span>
  14. <span style="color:var(--syntax-name-color)">servicePort</span>: <span style="color:var(--syntax-literal-color)">8080</span>
  15. <span style="color:var(--syntax-name-color)">path</span>: <span style="color:var(--syntax-string-color)">/</span>
  16. </code></span></span>

上面的配置会将 5% 的流量路由到 api-v2 服务。

除了注释之外,像 APISIX 这样的 Ingress 控制器还有自定义的 Kubernetes CRD 来克服 Ingress API 的限制。

下面的示例使用 APISIX CRD、ApisixRoute来配置金丝雀部署:

  1. <span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-name-color)">apiVersion</span>: <span style="color:var(--syntax-string-color)">apisix.apache.org/v2</span>
  2. <span style="color:var(--syntax-name-color)">kind</span>: <span style="color:var(--syntax-string-color)">ApisixRoute</span>
  3. <span style="color:var(--syntax-name-color)">metadata</span>:
  4. <span style="color:var(--syntax-name-color)">name</span>: <span style="color:var(--syntax-string-color)">api-canary</span>
  5. <span style="color:var(--syntax-name-color)">spec</span>:
  6. <span style="color:var(--syntax-name-color)">http</span>:
  7. - <span style="color:var(--syntax-name-color)">name</span>: <span style="color:var(--syntax-string-color)">route</span>
  8. <span style="color:var(--syntax-name-color)">match</span>:
  9. <span style="color:var(--syntax-name-color)">paths</span>:
  10. - <span style="color:var(--syntax-string-color)">/*</span>
  11. <span style="color:var(--syntax-name-color)">backends</span>:
  12. - <span style="color:var(--syntax-name-color)">serviceName</span>: <span style="color:var(--syntax-string-color)">api-v1</span>
  13. <span style="color:var(--syntax-name-color)">servicePort</span>: <span style="color:var(--syntax-literal-color)">8080</span>
  14. <span style="color:var(--syntax-name-color)">weight</span>: <span style="color:var(--syntax-literal-color)">95</span>
  15. - <span style="color:var(--syntax-name-color)">serviceName</span>: <span style="color:var(--syntax-string-color)">api-v2</span>
  16. <span style="color:var(--syntax-name-color)">servicePort</span>: <span style="color:var(--syntax-literal-color)">8080</span>
  17. <span style="color:var(--syntax-name-color)">weight</span>: <span style="color:var(--syntax-literal-color)">5</span>
  18. </code></span></span>

这些自定义 CRD 使配置 Ingress 和利用底层 API 网关的全部功能变得更加容易,但以可移植性为代价。

Kubernetes 网关 API

Gateway API 是一个新的 Kubernetes 对象,旨在“修复”Ingress API。

它从 Ingress 控制器开发的自定义 CRD 中汲取灵感,添加基于 HTTP 标头的匹配、加权流量拆分以及其他需要使用 Ingress API 进行自定义专有注释的功能。

下面的示例显示了使用 Kubernetes Gateway API 配置金丝雀部署:

  1. <span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-name-color)">apiVersion</span>: <span style="color:var(--syntax-string-color)">gateway.networking.k8s.io/v1alpha2</span>
  2. <span style="color:var(--syntax-name-color)">kind</span>: <span style="color:var(--syntax-string-color)">HTTPRoute</span>
  3. <span style="color:var(--syntax-name-color)">metadata</span>:
  4. <span style="color:var(--syntax-name-color)">name</span>: <span style="color:var(--syntax-string-color)">api-canary</span>
  5. <span style="color:var(--syntax-name-color)">spec</span>:
  6. <span style="color:var(--syntax-name-color)">rules</span>:
  7. - <span style="color:var(--syntax-name-color)">backendRefs</span>:
  8. - <span style="color:var(--syntax-name-color)">name</span>: <span style="color:var(--syntax-string-color)">api-v1</span>
  9. <span style="color:var(--syntax-name-color)">port</span>: <span style="color:var(--syntax-literal-color)">8080</span>
  10. <span style="color:var(--syntax-name-color)">weight</span>: <span style="color:var(--syntax-literal-color)">95</span>
  11. - <span style="color:var(--syntax-name-color)">name</span>: <span style="color:var(--syntax-string-color)">api-v2</span>
  12. <span style="color:var(--syntax-name-color)">port</span>: <span style="color:var(--syntax-literal-color)">8080</span>
  13. <span style="color:var(--syntax-name-color)">weight</span>: <span style="color:var(--syntax-literal-color)">5</span>
  14. </code></span></span>

任何 Ingress 控制器(实现网关 API)现在都可以实现此配置。

Gateway API 也对 Ingress API进行了很多改进,但它仍处于 alpha 阶段,Gateway API 的实现不断被打破。

服务网格

API 网关和 Kubernetes 网关跨应用程序边界工作,在抽象 API 的同时解决边缘问题。

服务网格解决了一个不同的挑战。

服务网格更关心服务间通信(东西向流量),而不是服务-客户端通信(南北向流量)。

通常,这是通过使用 API/服务部署 Sidecar 代理来实现的。

4f79307ddfd00119a2e6ac7e42a320d3.png

在这里,sidecar 代理处理服务到服务的通信,而不是开发人员必须将网络逻辑编码到服务。

有很多可用的服务网格。一些流行的是:

  • Istio:迄今为止最受欢迎的服务网格。它建立在许多服务网格使用的Envoy 代理之上
  • Linkerd:使用 linkerd2-proxy 的轻量级服务网格,用 Rust 专门为 Linkerd 编写。
  • Consul Connect:一个强调安全性和可观察性的服务网格。它可以与内置代理或 Envoy 一起使用。

像Cilium这样的新服务网格产品通过eBPF直接从内核使用网络功能,提供了基于 sidecar 的服务网格的替代方案。

1ebc47747198626fea8445e74d7f65a6.png

典型的服务网格需要 8 个代理来提供 8 个服务,而基于 eBPF 的服务网格(如 Cilium)则不需要。改编自Cilium Service Mesh – Everything You Need to Know。

服务网格也有基本的入口/出口网关来处理进出服务的南北流量。入口网关是外部流量到服务网格的入口点,出口网关允许网格内部的服务访问外部服务。

1b2984892f41dcddaa3f3a6b8c583c1e.png

Apache APISIX 也有一个名为Amesh 的服务网格实现。它使用 xDS 协议与 Istio 的控制平面一起工作,替换了 sidecar 中的默认 Envoy 代理。

服务网格可让您配置金丝雀部署。例如,您可以将来自一项服务的请求拆分到另一项服务的两个版本中。

35b1384fa373ac5ad9eeac9e8ce6e7a7.png

下面的示例显示了使用 Istio 服务网格配置金丝雀部署:

  1. <span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-name-color)">apiVersion</span>: <span style="color:var(--syntax-string-color)">networking.istio.io/v1alpha3</span>
  2. <span style="color:var(--syntax-name-color)">kind</span>: <span style="color:var(--syntax-string-color)">VirtualService</span>
  3. <span style="color:var(--syntax-name-color)">metadata</span>:
  4. <span style="color:var(--syntax-name-color)">name</span>: <span style="color:var(--syntax-string-color)">api-virtual-service</span>
  5. <span style="color:var(--syntax-name-color)">spec</span>:
  6. <span style="color:var(--syntax-name-color)">hosts</span>:
  7. - <span style="color:var(--syntax-string-color)">api</span>
  8. <span style="color:var(--syntax-name-color)">http</span>:
  9. - <span style="color:var(--syntax-name-color)">route</span>:
  10. - <span style="color:var(--syntax-name-color)">destination</span>:
  11. <span style="color:var(--syntax-name-color)">host</span>: <span style="color:var(--syntax-string-color)">api</span>
  12. <span style="color:var(--syntax-name-color)">subset</span>: <span style="color:var(--syntax-string-color)">v1</span>
  13. <span style="color:var(--syntax-name-color)">weight</span>: <span style="color:var(--syntax-literal-color)">80</span>
  14. - <span style="color:var(--syntax-name-color)">destination</span>:
  15. <span style="color:var(--syntax-name-color)">host</span>: <span style="color:var(--syntax-string-color)">api</span>
  16. <span style="color:var(--syntax-name-color)">subset</span>: <span style="color:var(--syntax-string-color)">v2</span>
  17. <span style="color:var(--syntax-name-color)">weight</span>: <span style="color:var(--syntax-literal-color)">20</span>
  18. </code></span></span>
  19. <span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-name-color)">apiVersion</span>: <span style="color:var(--syntax-string-color)">networking.istio.io/v1alpha3</span>
  20. <span style="color:var(--syntax-name-color)">kind</span>: <span style="color:var(--syntax-string-color)">DestinationRule</span>
  21. <span style="color:var(--syntax-name-color)">metadata</span>:
  22. <span style="color:var(--syntax-name-color)">name</span>: <span style="color:var(--syntax-string-color)">api-destination-rule</span>
  23. <span style="color:var(--syntax-name-color)">spec</span>:
  24. <span style="color:var(--syntax-name-color)">host</span>: <span style="color:var(--syntax-string-color)">api</span>
  25. <span style="color:var(--syntax-name-color)">subsets</span>:
  26. - <span style="color:var(--syntax-name-color)">name</span>: <span style="color:var(--syntax-string-color)">v1</span>
  27. <span style="color:var(--syntax-name-color)">labels</span>:
  28. <span style="color:var(--syntax-name-color)">version</span>: <span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-string-color)">1.0"</span>
  29. - <span style="color:var(--syntax-name-color)">name</span>: <span style="color:var(--syntax-string-color)">v2</span>
  30. <span style="color:var(--syntax-name-color)">labels</span>:
  31. <span style="color:var(--syntax-name-color)">version</span>: <span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-string-color)">2.0"</span>
  32. </code></span></span>

这些配置特定于 Istio。要切换到不同的服务网格,您必须创建不同但类似的供应商相关配置。

服务网格接口(SMI) 规范的创建就是为了解决这个可移植性问题。

SMI规范是一组 Kubernetes CRD,服务网格用户可以使用它来定义应用程序,而无需绑定到服务网格实现。

标准化尝试只有在所有项目都在船上时才会奏效。但这并没有发生在 SMI 规范中,只有少数项目积极参与。

最近,Kubernetes SIG 网络一直在改进 Gateway API 以支持服务网格。

GAMMA (用于网格管理和管理的网关 API)计划是一个专门的 Gateway API 项目小组,其目标是“调查、设计和跟踪 Gateway API 资源、语义以及与服务网格技术和用例相关的其他工件。 “

Gateway API 是 Ingress API 的自然下一步,但我们必须拭目以待,看看它将如何用于服务网格。Istio已宣布打算使用 Gateway API 作为所有流量管理的默认 API,并继续推动该项目向前发展。

下面的示例显示了使用 Gateway API 在 Istio 中配置金丝雀部署。基本思想是使用parentRefs附加到其他服务而不是网关:

  1. <span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-name-color)">apiVersion</span>: <span style="color:var(--syntax-string-color)">gateway.networking.k8s.io/v1beta1</span>
  2. <span style="color:var(--syntax-name-color)">kind</span>: <span style="color:var(--syntax-string-color)">HTTPRoute</span>
  3. <span style="color:var(--syntax-name-color)">metadata</span>:
  4. <span style="color:var(--syntax-name-color)">name</span>: <span style="color:var(--syntax-string-color)">api-canary</span>
  5. <span style="color:var(--syntax-name-color)">spec</span>:
  6. <span style="color:var(--syntax-name-color)">parentRefs</span>:
  7. - <span style="color:var(--syntax-name-color)">kind</span>: <span style="color:var(--syntax-string-color)">Service</span>
  8. <span style="color:var(--syntax-name-color)">name</span>: <span style="color:var(--syntax-string-color)">api-a</span>
  9. <span style="color:var(--syntax-name-color)">port</span>: <span style="color:var(--syntax-literal-color)">8080</span>
  10. <span style="color:var(--syntax-name-color)">rules</span>:
  11. - <span style="color:var(--syntax-name-color)">backendRefs</span>:
  12. - <span style="color:var(--syntax-name-color)">name</span>: <span style="color:var(--syntax-string-color)">api-b-v1</span>
  13. <span style="color:var(--syntax-name-color)">port</span>: <span style="color:var(--syntax-literal-color)">8080</span>
  14. <span style="color:var(--syntax-name-color)">weight</span>: <span style="color:var(--syntax-literal-color)">95</span>
  15. - <span style="color:var(--syntax-name-color)">name</span>: <span style="color:var(--syntax-string-color)">api-b-v2</span>
  16. <span style="color:var(--syntax-name-color)">port</span>: <span style="color:var(--syntax-literal-color)">8080</span>
  17. <span style="color:var(--syntax-name-color)">weight</span>: <span style="color:var(--syntax-literal-color)">5</span>
  18. </code></span></span>

有人担心GAMMA 项目可能会偏向于满足某个特定项目而不是更大社区的需求,这最终将导致其他项目使用他们自己的 API,类似于Kubernetes Ingress API 之后的自定义 CRD 场景。

但是 Gateway API 项目是标准化服务网格中流量管理的最佳尝试。SMI项目还以共同的愿景加入了 GAMMA 倡议,并将帮助倡导服务网格项目对 Gateway API 的一致实施。

Flagger和Argo Rollouts等其他项目也已与 Gateway API 集成。

你应该使用什么?

这个问题只有一个正确答案;“这取决于。”

如果您正在开发 API 并需要身份验证、安全性、路由或指标,那么最好使用 API 网关,而不是在您的 API 中自行构建。

如果你想在 Kubernetes 环境中做类似的事情,你应该使用 Kubernetes 网关,而不是试图让你的 API 网关在 Kubernetes 上工作。值得庆幸的是,许多 API 网关也适用于 Kubernetes 原生配置。

但有时,API 网关 + Ingress 控制器提供的功能对于 Kubernetes 环境来说可能有点矫枉过正,您可能希望切换回简单的流量管理。

另一方面,服务网格解决了一组完全不同的问题。他们还自带网关来处理南北流量(通常足够),但也让您使用自己的网关来提供更多功能。

通过 Kubernetes Gateway API 将 API 网关和服务网格融合在一起,应用程序开发人员应该更容易专注于解决问题,而不是担心底层实现。

Apache APISIX 等项目使用相同的技术来构建 API 网关和服务网格产品,并与这些规范很好地集成,从而激励供应商中立的选择。

您也可能不需要这些。您甚至可能不需要微服务或分布式架构,但当您需要它们时,网关和网格可以让您的生活变得更加轻松。

发表评论

表情:
评论列表 (有 0 条评论,180人围观)

还没有评论,来说两句吧...

相关阅读

    相关 API

    API网关       api gateway 即 api 网关。所有的请求首先会经过这个网关。这有点类似于前端控制器模式,也有点类似于 Facade模式。

    相关 API

    一 网关基本概念 1 API网关介绍 API 网关出现的原因是微服务架构的出现,不同的微服务一般会有不同的网络地址,而外部客户端可能需要调用多个服务的接口才能完成一