本文发布已超过一年。较早的文章可能包含过时内容。请确认页面中的信息自发布以来未发生不正确之处。

Kong Ingress Controller 和 Service Mesh:在 Kubernetes 上设置 Ingress 到 Istio

Kubernetes 已成为容器编排及其内部服务编排的实际标准方式。但是,我们如何让集群外部的服务访问集群内部的服务呢?Kubernetes 提供了 Ingress API 对象,用于管理从外部访问集群内部的服务。

Ingress 是一组规则,它将把入站连接代理到由后端定义的端点。然而,如果没有 Ingress controller,Kubernetes 不知道如何处理 Ingress 资源,这时开源控制器就派上用场了。在本文中,我们将使用其中一种选项:Kong Ingress Controller。Kong Ingress Controller 于一年前开源,最近下载量达到一百万次。在最近发布的 0.7 版本中,还添加了服务网格支持。此版本的其他功能包括

  • 内置 Kubernetes Admission Controller,它在创建或更新 Custom Resource Definitions (CRD) 时进行验证,并拒绝任何无效配置。
  • 内存模式 (In-memory Mode) - 每个 Pod 的控制器主动配置其 Pod 中的 Kong 容器,这将单个 Kong 容器或控制器容器的故障影响范围限制在该 Pod 内。
  • 原生 gRPC 路由 - gRPC 流量现在可以通过 Kong Ingress Controller 原生路由,并支持基于方法的路由。

K4K-gRPC

如果你想更深入地了解 Kong Ingress Controller 0.7,请查阅其 GitHub 仓库

但是让我们回到服务网格支持,因为这将是本文的主要焦点。服务网格允许组织通过将服务间通信抽象到网格层来解决与安全性、可靠性和可观测性相关的微服务挑战。但是如果我们的网格层位于 Kubernetes 内部,而我们仍然需要将某些服务暴露到集群之外呢?这时你就需要一个 Ingress controller,例如 Kong Ingress Controller。在本文中,我们将介绍如何将 Kong Ingress Controller 作为 Ingress 层部署到 Istio 网格。让我们直接开始

Kong Kubernetes Ingress Controller

第一部分:在 Kubernetes 上设置 Istio

本文假设你已在 Kubernetes 上设置好 Istio。如果你需要追赶到这一点,请查阅 Istio 文档。它将引导你在 Kubernetes 上设置 Istio。

1. 安装 Bookinfo 应用

首先,我们需要为托管我们应用和 Kong 代理的命名空间打标签。要为 Bookinfo 应用所在的默认命名空间打标签,运行以下命令

$ kubectl label namespace default istio-injection=enabled
namespace/default labeled

然后创建一个新的命名空间,用于托管我们的 Kong 网关和 Ingress controller

$ kubectl create namespace kong
namespace/kong created

由于 Kong 将位于默认命名空间之外,请确保你也为 Kong 命名空间启用了 istio-injection 并打上标签

$ kubectl label namespace kong istio-injection=enabled
namespace/kong labeled

两个命名空间都必须标记为 istio-injection=enabled。否则,默认配置不会将 sidecar 容器注入到你命名空间的 Pod 中。

现在使用以下命令部署你的 BookInfo 应用

$ kubectl apply -f http://bit.ly/bookinfoapp
service/details created
serviceaccount/bookinfo-details created
deployment.apps/details-v1 created
service/ratings created
serviceaccount/bookinfo-ratings created
deployment.apps/ratings-v1 created
service/reviews created
serviceaccount/bookinfo-reviews created
deployment.apps/reviews-v1 created
deployment.apps/reviews-v2 created
deployment.apps/reviews-v3 created
service/productpage created
serviceaccount/bookinfo-productpage created
deployment.apps/productpage-v1 created

让我们仔细检查我们的 Services 和 Pods,确保我们已正确设置所有内容

$ kubectl get services
NAME          TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
details       ClusterIP   10.97.125.254    <none>        9080/TCP   29s
kubernetes    ClusterIP   10.96.0.1        <none>        443/TCP    29h
productpage   ClusterIP   10.97.62.68      <none>        9080/TCP   28s
ratings       ClusterIP   10.96.15.180     <none>        9080/TCP   28s
reviews       ClusterIP   10.104.207.136   <none>        9080/TCP   28s

你应该看到四个新的服务:details, productpage, ratings 和 reviews。它们都没有外部 IP,所以我们将使用 Kong 网关 来暴露必要的服务。要检查 Pods,运行以下命令

$ kubectl get pods
NAME                              READY   STATUS    RESTARTS   AGE
details-v1-c5b5f496d-9wm29        2/2     Running   0          101s
productpage-v1-7d6cfb7dfd-5mc96   2/2     Running   0          100s
ratings-v1-f745cf57b-hmkwf        2/2     Running   0          101s
reviews-v1-85c474d9b8-kqcpt       2/2     Running   0          101s
reviews-v2-ccffdd984-9jnsj        2/2     Running   0          101s
reviews-v3-98dc67b68-nzw97        2/2     Running   0          101s

此命令输出有用的数据,让我们花点时间来理解它。如果你查看 READY 列,每个 Pod 都有两个容器在运行:服务容器和一个注入在其旁边的 Envoy sidecar。另一个需要强调的是,有三个 review Pods 但只有一个 review 服务。Envoy sidecar 会将流量负载均衡到包含不同版本的三个不同的 review Pods,这让我们能够对我们的更改进行 A/B 测试。在访问已部署的应用之前,我们还有一个步骤。我们需要为 productpage 服务添加一个额外的注解。要做到这一点,运行

$ kubectl annotate service productpage ingress.kubernetes.io/service-upstream=true
service/productpage annotated

API 网关 (Kong) 和服务网格 (Istio) 都可以处理负载均衡。如果没有额外的 ingress.kubernetes.io/service-upstream: "true" 注解,Kong 将尝试通过从 productpage 服务中选择自己的端点/目标来进行负载均衡。这将导致 Envoy 接收该 Pod 的 IP 作为上游本地地址,而不是服务的 Cluster IP。但我们想要服务的 Cluster IP,以便 Envoy 可以正确地负载均衡。

添加此注解后,你应该就可以访问你的 productpage 了!

$ kubectl exec -it $(kubectl get pod -l app=ratings -o jsonpath='{.items[0].metadata.name}') -c ratings -- curl productpage:9080/productpage | grep -o "<title>.*</title>"
<title>Simple Bookstore App</title>

2. 不带数据库的 Kong Kubernetes Ingress Controller

为了向世界暴露你的服务,我们将部署 Kong 作为南北流量网关。Kong 1.1 发布时带有声明性配置和无数据库模式。声明性配置允许你通过 YAML 或 JSON 文件指定所需的系统状态,而不是通过一系列 API 调用。使用声明性配置提供了几个关键优势,可以降低复杂性、提高自动化程度并增强系统性能。通过 Kong Ingress Controller,你应用于集群的任何 Ingress 规则都将自动在 Kong 代理上配置。让我们先这样设置 Kong Ingress Controller 和实际的 Kong 代理

$ kubectl apply -f https://bit.ly/k4k8s
namespace/kong configured
customresourcedefinition.apiextensions.k8s.io/kongconsumers.configuration.konghq.com created
customresourcedefinition.apiextensions.k8s.io/kongcredentials.configuration.konghq.com created
customresourcedefinition.apiextensions.k8s.io/kongingresses.configuration.konghq.com created
customresourcedefinition.apiextensions.k8s.io/kongplugins.configuration.konghq.com created
serviceaccount/kong-serviceaccount created
clusterrole.rbac.authorization.k8s.io/kong-ingress-clusterrole created
clusterrolebinding.rbac.authorization.k8s.io/kong-ingress-clusterrole-nisa-binding created
configmap/kong-server-blocks created
service/kong-proxy created
service/kong-validation-webhook created
deployment.apps/ingress-kong created

要检查 Kong Pod 是否已启动并正在运行,运行

$ kubectl get pods -n kong
NAME                               READY   STATUS    RESTARTS   AGE
pod/ingress-kong-8b44c9856-9s42v   3/3     Running   0          2m26s

此 Pod 中将有三个容器。第一个容器是 Kong 网关,它将是通往你集群的 Ingress 点。第二个容器是 Ingress controller。它使用 Ingress 资源并更新代理以遵循资源中定义的规则。最后,第三个容器是由 Istio 注入的 Envoy 代理。Kong 将通过 Envoy sidecar 代理将流量路由到适当的服务。为了通过我们新部署的 Kong 网关向集群发送请求,使用 Kong 可访问的 IP 地址设置一个包含 URL 的环境变量。

$ export PROXY_URL="$(minikube service -n kong kong-proxy --url | head -1)"
$ echo $PROXY_URL
http://192.168.99.100:32728

接下来,我们需要更改一些配置,以便 sidecar Envoy 进程可以根据请求的 host/authority header 正确路由请求。运行以下命令停止路由保留 host 的行为

$ echo "
apiVersion: configuration.konghq.com/v1
kind: KongIngress
metadata:
    name: do-not-preserve-host
route:
  preserve_host: false
upstream:
  host_header: productpage.default.svc
" | kubectl apply -f -
kongingress.configuration.konghq.com/do-not-preserve-host created

并为现有的 productpage 服务添加注解,设置 service-upstream 为 true

$ kubectl annotate svc productpage Ingress.kubernetes.io/service-upstream="true"
service/productpage annotated

现在我们已经设置好了一切,我们可以看看如何使用 Ingress 资源来帮助将外部流量路由到你的 Istio 网格内的服务。我们将创建一个 Ingress 规则,将所有路径为 / 的流量路由到我们的 productpage 服务

$ echo "
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: productpage
  annotations:
    configuration.konghq.com: do-not-preserve-host
spec:
  rules:
  - http:
      paths:
      - path: /
        backend:
          serviceName: productpage
          servicePort: 9080
" | kubectl apply -f -
ingress.extensions/productpage created

就这样,Kong Ingress Controller 就能够理解你在 Ingress 资源中定义的规则,并将其路由到 productpage 服务!要查看 productpage 服务的 GUI,请在浏览器中访问 $PROXY_URL/productpage。或者在命令行中测试,尝试

$ curl $PROXY_URL/productpage

这就是本次演示的全部内容。如果你喜欢本文中使用的技术,请查阅它们的仓库,因为它们都是开源的,并且非常乐意有更多贡献者!为了方便你,以下是它们的链接

感谢你的阅读!