learn-tech/专栏/Kubernetes入门实战课/加餐谈谈KongIngressController.md
2024-10-16 06:37:41 +08:00

16 KiB
Raw Blame History

                        因收到Google相关通知网站将会择期关闭。相关通知内容
                        
                        
                        加餐 谈谈Kong Ingress Controller
                        你好我是Chrono。

课程已经完结三个多月了还记得结课时我说的那句话吗“是终点更是起点”课程的完结绝不意味着我们终止对Kubernetes的钻研相反不论你我都会在这个学习的道路上持续地走下去。

当初开课时我计划了很多内容不过Kubernetes的领域实在太广加上我日常工作比较忙时间和精力有限所以一些原定的知识点没有来得及展现比较可惜我一直想找机会做个补偿。

这几天开发任务略微空闲了些我就又回到了专栏准备使用另一个流行的工具Kong Ingress Controller再来讲讲对Kubernetes集群管理非常重要的Ingress。

认识Kong Ingress Controller

我们先快速回顾一下Ingress的知识[第21讲])。

Ingress类似Service基于HTTP/HTTPS协议是七层负载均衡规则的集合但它自身没有管理能力必须要借助Ingress Controller才能控制Kubernetes集群的进出口流量。

所以基于Ingress的定义就出现了各式各样的Ingress Controller实现。

我们已经见过了Nginx官方开发的Nginx Ingress Controller但它局限于Nginx自身的能力Ingress、Service等对象更新时必须要修改静态的配置文件再重启进程reload在变动频繁的微服务系统里就会引发一些问题。

而今天要说的Kong Ingress Controller则是站在了Nginx这个巨人的肩膀之上基于OpenResty和内嵌的LuaJIT环境实现了完全动态的路由变更消除了reload的成本运行更加平稳而且还有很多额外的增强功能非常适合那些对Kubernetes集群流量有更高、更细致管理需求的用户图片来源Kong官网

安装Kong Ingress Controller

接下来我们就来看看如何在Kubernetes集群里引入Kong Ingress Controller。

简单起见这次我选择了minikube环境版本还是1.25.2对应的Kubernetes也是之前的1.23.3

目前Kong Ingress Controller的最新版本是2.7.0你可以从GitHub上(https://github.com/Kong/kubernetes-ingress-controller)直接获取它的源码包:

wget https://github.com/Kong/kubernetes-ingress-controller/archive/refs/tags/v2.7.0.tar.gz

Kong Ingress Controller安装所需的YAML文件都存放在解压缩后的“deploy”目录里提供“有数据库”和“无数据库”两种部署方式这里我选择了最简单的“无数据库”方式只需要一个 all-in-one-dbless.yaml 就可以完成部署工作,也就是执行这条 kubectl apply 命令:

kubectl apply -f all-in-one-dbless.yaml

我们可以再对比一下两种 Ingress Controller的安装方式。Nginx Ingress Controller是由多个分散的YAML文件组成的需要顺序执行多次 kubectl apply 命令有点麻烦而Kong Ingress Controller则把Namespace、RBAC、Secret、CRD等对象都合并在了一个文件里安装很方便同时也不会发生遗忘创建资源的错误。

安装之后Kong Ingress Controller会创建一个新的名字空间“kong”里面有一个默认的Ingress Controller还有对应的Service你可以用 kubectl get 来查看:

看这里的截图,你可能会注意到,在 kubectl get pod 输出的“READY”列里显示的是“2/2”意思是这个Pod里有两个容器。

这也是Kong Ingress Controller与Nginx Ingress Controller在实现架构方面的一个明显不同点。

Kong Ingress Controller在Pod里使用两个容器分别运行管理进程Controller和代理进程Proxy两个容器之间使用环回地址Loopback通信而Nginx Ingress Controller则是因为要修改静态的Nginx配置文件所以管理进程和代理进程必须在一个容器里图片表示Kong架构设计

两种方式并没有优劣之分但Kong Ingress Controller分离的好处是两个容器彼此独立可以各自升级维护对运维更友好一点。

Kong Ingress Controller还创建了两个Service对象其中的“kong-proxy”是转发流量的服务注意它被定义成了“LoadBalancer”类型显然是为了在生产环境里对外暴露服务不过在我们的实验环境无论是minikube还是kubeadm中只能使用NodePort的形式这里可以看到80端口被映射到了节点的32201。

现在让我们尝试访问一下Kong Ingress ControllerIP就用worker节点的地址如果你和我一样用的是minikube则可以用 $(minikube ip) 的形式简单获取:

curl $(minikube ip):32201 -i

从curl获取的响应结果可以看到 Kong Ingress Controller 2.7内部使用的Kong版本是3.0.1因为现在我们没有为它配置任何Ingress资源所以返回了状态码404这是正常的。

我们还可以用 kubectl exec 命令进入Pod查看它的内部信息

虽然Kong Ingress Controller里有两个容器但我们不需要特意用 -c 选项指定容器它会自动进入默认的Proxy容器另一个Controller容器里因为不包含Shell也是无法进入查看的

使用Kong Ingress Controller

安装好了我们看如何使用。和第21讲里的一样我们仍然不使用默认的Ingress Controller而是利用Ingress Class自己创建一个新的实例这样能够更好地理解掌握Kong Ingress Controller的用法。

首先定义后端应用还是用Nginx来模拟做法和[第20讲]里的差不多用ConfigMap定义配置文件再加载进Nginx Pod里然后部署Deployment和Service比较简单你也比较熟悉就不列出YAML 代码了,只看一下运行命令后的截图:

显示我创建了两个Nginx PodService对象的名字是ngx-svc。

接下来是定义Ingress Class名字是“kong-ink” “spec.controller”字段的值是Kong Ingress Controller的名字“ingress-controllers.konghq.com/kong”YAML的格式可以参考[第21讲]

apiVersion: networking.k8s.io/v1 kind: IngressClass metadata: name: kong-ink

spec: controller: ingress-controllers.konghq.com/kong

然后就是定义Ingress对象了我们还是可以用 kubectl create 来生成YAML 样板文件,用 --rule 指定路由规则,用 --class 指定Ingress Class

kubectl create ing kong-ing --rule="kong.test/=ngx-svc:80" --class=kong-ink $out

生成的Ingress对象大概就是下面这样域名是“kong.test”流量会转发到后端的ngx-svc服务

apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: kong-ing

spec: ingressClassName: kong-ink

rules:

  • host: kong.test http: paths:
    • path: / pathType: Prefix backend: service: name: ngx-svc port: number: 80

最后,我们要从 all-in-one-dbless.yaml 这个文件中分离出Ingress Controller的定义。其实也很简单只要搜索“Deployment”就可以了然后把它以及相关的Service代码复制一份另存成“kic.yml”。

当然了刚复制的代码和默认的Kong Ingress Controller是完全相同的所以我们必须要参考帮助文档做一些修改要点我列在了这里

Deployment、Service里metadata的 name 都要重命名,比如改成 ingress-kong-dep、ingress-kong-svc。 spec.selector 和 template.metadata.labels 也要修改成自己的名字一般来说和Deployment的名字一样也就是ingress-kong-dep。 第一个容器是流量代理Proxy它里面的镜像可以根据需要改成任意支持的版本比如Kong:2.7、Kong:2.8或者Kong:3.1。 第二个容器是规则管理Controller要用环境变量“CONTROLLER_INGRESS_CLASS”指定新的Ingress Class名字 kong-ink同时用“CONTROLLER_PUBLISH_SERVICE”指定Service的名字 ingress-kong-svc。 Service对象可以把类型改成NodePort方便后续的测试。

改了这些之后一个新的Kong Ingress Controller就完成了大概是这样修改点我也加注释了你可以对照着看

apiVersion: apps/v1 kind: Deployment metadata: name: ingress-kong-dep # 重命名 namespace: kong spec: replicas: 1 selector: matchLabels: app: ingress-kong-dep # 重命名 template: metadata: labels: app: ingress-kong-dep # 重命名 spec: containers: - env: # 第一个容器, Proxy ... image: kong:3.1 # 改镜像

  - env:                       # 第二个容器Controller
    - name: CONTROLLER_INGRESS_CLASS
      value: kong-ink                  # 改Ingress Class
    - name: CONTROLLER_PUBLISH_SERVICE
      value: kong/ingress-kong-svc     # 改Service
    ...

apiVersion: v1 kind: Service metadata: name: ingress-kong-svc # 重命名 namespace: kong spec: ... selector: app: ingress-kong-dep # 重命名 type: NodePort # 改类型

在我们专栏的配套GitHub项目里你也可以直接找到改好的YAML 文件。- 把这些都准备好我们就可以来测试验证Kong Ingress Controller了

kubectl apply -f ngx-deploy.yml kubectl apply -f ingress.yml kubectl apply -f kic.yml

这个截图显示了这些对象的创建结果其中新Service对象的NodePort端口是32521。

下面我们就来用curl发送HTTP请求注意应该用“resolve”或者“-H”参数指定Ingress里定义的域名“kong.test”否则Kong Ingress Controller会找不到路由

curl $(minikube ip):32521 -H 'host: kong.test' -v

你可以看到Kong Ingress Controller正确应用了Ingress路由规则返回了后端Nginx应用的响应数据而且从响应头“Via”里还可以发现它现在用的是Kong 3.1。

扩展Kong Ingress Controller

到这里Kong Ingress Controller的基本用法你就掌握了。

不过只使用Kubernetes标准的Ingress资源来管理流量是无法发挥出Kong Ingress Controller的真正实力的它还有很多非常好用、非常实用的增强功能。

我们在[第27讲]里曾经说过annotation是Kubernetes为资源对象提供的一个方便扩展功能的手段所以使用annotation就可以在不修改Ingress自身定义的前提下让Kong Ingress Controller更好地利用内部的Kong来管理流量。

目前Kong Ingress Controller支持在Ingress和Service这两个对象上添加annotation相关的详细文档可以参考官网https://docs.konghq.com/kubernetes-ingress-controller/2.7.x/references/annotations/这里我只介绍两个annotation

第一个是“konghq.com/host-aliases”它可以为Ingress规则添加额外的域名。

你应该知道吧Ingress的域名里可以使用通配符 *,比如 .abc.com但问题在于 * 只能是前缀,不能是后缀,也就是说我们无法写出 abc. 这样的域名,这在管理多个域名的时候就显得有点麻烦。

有了“konghq.com/host-aliases”我们就可以用它来“绕过”这个限制让Ingress轻松匹配有不同后缀的域名。

比如我修改一下Ingress定义在“metadata”里添加一个annotation让它除了“kong.test”还能够支持“kong.dev”“kong.ops”等域名就是这样

apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: kong-ing annotations: konghq.com/host-aliases: "kong.dev, kong.ops" #注意这里 spec: ...

使用 kubectl apply 更新Ingress再用curl来测试一下

你就会发现Ingress已经支持了这几个新域名。

第二个是“konghq.com/plugins”它可以启用Kong Ingress Controller内置的各种插件Plugins

插件是Kong Ingress Controller的一个特色功能你可以理解成是“预制工件”能够附加在流量转发的过程中实现各种数据处理并且这个插件机制是开放的我们既可以使用官方插件也可以使用第三方插件还可以使用Lua、Go等语言编写符合自己特定需求的插件。

Kong公司维护了一个经过认证的插件中心https://docs.konghq.com/hub/你可以在这里找到涉及认证、安全、流控、分析、日志等多个领域大约100多个插件今天我们看两个常用的 Response Transformer、Rate Limiting。

Response Transformer插件实现了对响应数据的修改能够添加、替换、删除响应头或者响应体Rate Limiting插件就是限速能够以时分秒等单位任意限制客户端访问的次数。

定义插件需要使用CRD资源名字是“KongPlugin”你也可以用kubectl api-resources、kubectl explain 等命令来查看它的apiVersion、kind等信息

下面我就给出这两个插件对象的示例定义:

apiVersion: configuration.konghq.com/v1 kind: KongPlugin metadata: name: kong-add-resp-header-plugin

plugin: response-transformer config: add: headers: - Resp-New-Header:kong-kic


apiVersion: configuration.konghq.com/v1 kind: KongPlugin metadata: name: kong-rate-limiting-plugin

plugin: rate-limiting config: minute: 2

KongPlugin对象因为是自定义资源所以和标准Kubernetes对象不一样不使用“spec”字段而是用“plugin”来指定插件名用“config”来指定插件的配置参数。

比如在这里我就让Response Transformer插件添加一个新的响应头字段让Rate Limiting插件限制客户端每分钟只能发两个请求。

定义好这两个插件之后我们就可以在Ingress对象里用annotations来启用插件功能了

apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: kong-ing annotations: konghq.com/plugins: | kong-add-resp-header-plugin, kong-rate-limiting-plugin

现在让我们应用这些插件对象并且更新Ingress

kubectl apply -f crd.yml

再发送curl请求

curl $(minikube ip):32521 -H 'host: kong.test' -i

你就会发现响应头里多出了几个字段,其中的 RateLimit-* 是限速信息,而 Resp-New-Header 就是新加的响应头字段。

把curl连续执行几次就可以看到限速插件生效了

Kong Ingress Controller会返回429错误告诉你访问受限而且会用“Retry-After”等字段来告诉你多少秒之后才能重新发请求。

小结

好了今天我们学习了另一种在Kubernetes管理集群进出流量的工具Kong Ingress Controller小结一下要点内容

Kong Ingress Controller的底层内核仍然是Nginx但基于OpenResty和LuaJIT实现了对路由的完全动态管理不需要reload。 使用“无数据库”的方式可以非常简单地安装Kong Ingress Controller它是一个由两个容器组成的Pod。 Kong Ingress Controller支持标准的Ingress资源但还使用了annotation和CRD提供更多的扩展增强功能特别是插件可以灵活地加载或者拆卸实现复杂的流量管理策略。

作为一个CNCF云原生项目Kong Ingress Controller已经得到了广泛的应用和认可而且在近年的发展过程中它也开始支持新的Gateway API等下次有机会我们再细聊吧。

课下作业

最后是课下作业时间,给你留两个思考题:

你能否对比一下Kong Ingress Controller和Nginx Ingress Controller这两个产品你看重的是它哪方面的表现呢 你觉得插件这种机制有什么好处,能否列举一些其他领域里的类似项目?

好久不见了,期待看到你的想法,我们一起讨论,留言区见。