Service 很有用,但也只能说是“基础设施”,它对网络流量的管理方案还是太简单,离复杂的现代应用架构需求还有很大的差距,所以 Kubernetes 就在 Service 之上又提出了一个新的概念:Ingress。
Service 还有一个缺点,它比较适合代理集群内部的服务。如果想要把服务暴露到集群外部,就只能使用 NodePort 或者 LoadBalancer 这两种方式,而它们都缺乏足够的灵活性,难以管控,这就导致了一种很无奈的局面:我们的服务空有一身本领,却没有合适的机会走出去大展拳脚。
这个 API 对象就顺理成章地被命名为 Ingress,意思就是集群内外边界上的入口。
Service 本身是没有服务能力的,它只是一些 iptables 规则,真正配置、应用这些规则的实际上是节点里的 kube-proxy 组件。如果没有 kube-proxy,Service 定义得再完善也没有用。
Ingress 也只是一些 HTTP 路由规则的集合,相当于一份静态的描述文件,真正要把这些规则在集群里实施运行,还需要有另外一个东西,这就是 Ingress Controller,它的作用就相当于 Service 的 kube-proxy,能够读取、应用 Ingress 规则,处理、调度流量。
Kubernetes 应该把 Ingress Controller 内置实现,作为基础设施的一部分,就像 kube-proxy 一样。
随着 Ingress 在实践中的大量应用,很多用户发现这种用法会带来一些问题,比如:
- 由于某些原因,项目组需要引入不同的 Ingress Controller,但 Kubernetes 不允许这样做;
- Ingress 规则太多,都交给一个 Ingress Controller 处理会让它不堪重负;
- 多个 Ingress 对象没有很好的逻辑分组方式,管理和维护成本很高;
- 集群里有不同的租户,他们对 Ingress 的需求差异很大甚至有冲突,无法部署在同一个 Ingress Controller 上。
Kubernetes 就又提出了一个 Ingress Class 的概念,让它插在 Ingress 和 Ingress Controller 中间,作为流量规则和控制器的协调人,解除了 Ingress 和 Ingress Controller 的强绑定关系。
Kubernetes 用户可以转向管理 Ingress Class,用它来定义不同的业务逻辑分组,简化 Ingress 规则的复杂度。比如说,我们可以用 Class A 处理博客流量、Class B 处理短视频流量、Class C 处理购物流量。
Ingress 也是可以使用 kubectl create 来创建样板文件的,和 Service 类似,它也需要用两个附加参数:
- --class,指定 Ingress 从属的 Ingress Class 对象。
- --rule,指定路由规则,基本形式是“URI=Service”,也就是说是访问 HTTP 路径就转发到对应的 Service 对象,再由 Service 对象转发给后端的 Pod。
Ingress 和 Service、Ingress Class 的关系画成了一张图。
部署 Ingress Controller 不需要我们自己从头编写 Deployment,Nginx 已经为我们提供了示例 YAML,但创建之前为了适配我们自己的应用还必须要做几处小改动:
- metadata 里的 name 要改成自己的名字,比如 ngx-kic-dep。
- spec.selector 和 template.metadata.labels 也要修改成自己的名字,比如还是用 ngx-kic-dep。
- containers.image 可以改用 apline 版本,加快下载速度,比如 nginx/nginx-ingress:2.2-alpine。
- 最下面的 args 要加上 -ingress-class=ngx-ink,也就是前面创建的 Ingress Class 的名字,这是让 Ingress Controller 管理 Ingress 的关键。