本文发布时间已超过一年。较旧的文章可能包含过时的内容。请检查页面上的信息自发布以来是否已变得不正确。

Kong Ingress Controller 和服务网格:在 Kubernetes 上设置 Ingress 到 Istio

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

Ingress 是一组规则,用于将入站连接代理到后端定义的端点。但是,如果没有 Ingress 控制器,Kubernetes 就不知道如何处理 Ingress 资源,而开源控制器可以在这里发挥作用。在这篇文章中,我们将使用其中一个选项:Kong Ingress Controller。Kong Ingress Controller 一年前开源,最近下载量达到一百万次。在最近的 0.7 版本中,还增加了服务网格支持。此版本的其他功能包括

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

K4K-gRPC

如果您想深入了解 Kong Ingress Controller 0.7,请查看 GitHub 存储库

但是,让我们回到服务网格支持,因为这将是这篇博文的主要重点。服务网格允许组织通过将服务间通信抽象到一个网格层来解决与安全性、可靠性和可观察性相关的微服务挑战。但是,如果我们的网格层位于 Kubernetes 内,并且我们仍然需要将某些服务暴露到集群之外呢?那么您需要一个 Ingress 控制器,例如 Kong Ingress Controller。在这篇博文中,我们将介绍如何将 Kong Ingress Controller 作为 Ingress 层部署到 Istio 网格。让我们开始吧

Kong Kubernetes Ingress Controller

第 0 部分:在 Kubernetes 上设置 Istio

本博客将假设您已在 Kubernetes 上设置了 Istio。如果您需要了解此步骤,请查看 Istio 文档。它将引导您完成在 Kubernetes 上设置 Istio 的过程。

1. 安装 Bookinfo 应用程序

首先,我们需要标记将托管我们的应用程序和 Kong 代理的命名空间。要标记 bookinfo 应用程序所在的默认命名空间,请运行以下命令

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

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

$ kubectl create namespace kong
namespace/kong created

因为 Kong 将位于默认命名空间之外,请确保您也使用启用的 istio-injection 标记 Kong 命名空间

$ 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

让我们仔细检查我们的服务和 Pod,以确保我们都已正确设置

$ 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 网关 来暴露必要的服务。要检查 Pod,请运行以下命令

$ 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 Pod,但只有一个 review 服务。Envoy sidecar 将负载均衡流量到包含不同版本的三个不同 review Pod,从而使我们能够对更改进行 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 作为上游本地地址,而不是服务的集群 IP。但我们想要服务的集群 IP,以便 Envoy 可以正确地进行负载均衡。

添加此项后,您现在应该可以访问您的产品页面了!

$ 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 控制器。它使用 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

接下来,我们需要更改一些配置,以便 side-car Envoy 进程可以根据请求的主机/授权标头正确路由请求。运行以下命令以停止路由保留主机

$ 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 服务!要查看产品页面服务的 GUI,请在浏览器中转到 $PROXY_URL/productpage。或者,要在命令行中进行测试,请尝试

$ curl $PROXY_URL/productpage

这就是我这次演练的全部内容。如果您喜欢这篇文章中使用的技术,请查看它们的存储库,因为它们都是开源的,并且很乐意拥有更多的贡献者!为了方便起见,这里是它们的链接

感谢您的关注!