数据包在 Kubernetes 中的一生(4)
原文:Life of a Packet in Kubernetes — Part 4
本篇内容会跟进 Kubernetes 的 Ingress 和 Ingress 控制器。Ingress 控制器会关注 API Server 中 Ingress 对象的更新,并据此配置 Ingress 的负载均衡。
Nginx 控制器和负载均衡/代理服务器
Ingress 控制器一般会是一个以 Pod 形式运行在 Kubernetes 集群中的应用,它会根据集群中的 Ingress 对象的变化对负载均衡器进行配置。这里说的负载均衡器可以是一个集群内运行的软件,也可以是一个硬件,还可以是集群外部运行在云基础设施中。不同的负载均衡器需要不同的 Ingress 控制器。
Ingress 的基本目标是提供一个相对高级的流量(尤其是 http(s))管理能力。使用 Ingress 可以在无需创建多个负载均衡或者对外开放多个 Service 的条件下,为服务流量进行路由。可以给服务配置外部 URL、进行负载均衡、终结 SSL 以及根据主机名或者内容进行路由等。
配置选项
在把 Ingress 对象转换为负载均衡配置之前,Kubernetes Ingress 控制器会用 Ingress Class 对 Kubernetes 的 Ingress 对象进行过滤。这样就允许多个 Ingress 控制器共存,各司其职。
基于前缀
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: prefix-based
annotations:
kubernetes.io/ingress.class: "nginx-ingress-inst-1"
spec:
rules:
- http:
paths:
- path: /video
pathType: Prefix
backend:
service:
name: video
port:
number: 80
- path: /store
pathType: Prefix
backend:
service:
name: store
port:
number: 80
基于主机
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: host-based
annotations:
kubernetes.io/ingress.class: "nginx-ingress-inst-1"
spec:
rules:
- host: "video.example.com"
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: video
port:
number: 80
- host: "store.example.com"
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: store
port:
number: 80
主机加前缀
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: host-prefix-based
annotations:
kubernetes.io/ingress.class: "nginx-ingress-inst-1"
spec:
rules:
- host: foo.com
http:
paths:
- backend:
serviceName: foovideo
servicePort: 80
path: /video
- backend:
serviceName: foostore
servicePort: 80
path: /store
- host: bar.com
http:
paths:
- backend:
serviceName: barvideo
servicePort: 80
path: /video
- backend:
serviceName: barstore
servicePort: 80
path: /store
Ingress 是一个内置 API 对象,但是 Kubernetes 并没有内置任何 Ingress 控制器,需要另行安装控制器才能真正地使用 Ingress。Ingress 功能是由 API 对象和控制器协同完成的。Ingress 对象负责描述集群中 Service 对象的开放需求。而控制器则负责真正的实现 Ingress API,根据 Ingress 对象的定义内容来完成实际工作。市面上有很多不同的 Ingress 控制器,需要根据实际用例谨慎地进行选择使用。
同一集群里可以有多个 Ingress 控制器,并为每个 Ingress 直接指派具体的控制器,在同一个集群中可以根据不同需要为不同服务配置不同的 Ingress。例如某服务用于一个 Ingress 处理来自集群外的 SSL 流量,另外一个用于处理集群内的明文通信。
部署选项
Contour + Envoy
Contour Ingress 控制器由两部分组成:
- Envoy 提供了高性能的反向代理服务;
- Contour 负责对 Envoy 进行管理,为其下发配置。
这些容器是各自部署的,Contour 是一个 Deployment,而 Envoy 则是一个 Daemonset,当然也可以用其他模式进行部署。Contour 是 Kubernetes API 的客户端,会跟踪 Ingress、HTTPProxy、Secret、Service 以及 Endpoint 对象,并承担管理 Envoy 的职责,它会把它的对象缓存转换为 Envoy 的 JSON 报文,Service 转换为 CDS、Ingress 转为 RDS、Endpoint 转换为 EDS 等。
下面的例子展示了启用 Host Network 的 EnvoyProxy:
Nginx
Nginx Ingress 控制器的主要能力之一就是生成配置文件(nginx.conf
)。这个实现还有个需要就是在配置发生变化之后重载 Nginx。在只有 upstream
发生变化时(例如部署调整时产生的 Endpoint 变化)不会进行重载,而是通过 lua-nginx-module 完成任务。
每次 Endpoint 发生变动,控制器会从所有服务中拉取 Endpoint,生成对应的后端对象。这些对象会被发送给 Nginx 中运行的 Lua 处理器。Lua 代码会把这些对象保存到共享内存区域。每次 balancer_by_lua
都会检查一下 upstream 中的有效节点,以此为目标按照预配置的算法进行负载均衡。如果在一个较大的集群中有比较频繁的发布行为,这种避免重载的方式能够大幅减少重载次数,从而更好地保障了响应的延迟时间,达成较高的负载均衡水平。
Nginx+ Keepalived —— 高可用部署
Keepalived 守护进程可以监控服务或者系统,如果发现问题,能够进行自动的切换。配置一个能在节点之间转移的浮动 IP。如果节点宕机,浮动 IP 会自动漂移到其它节点,Nginx 可以绑定到新的 IP 地址。
MetalLB —— 面向具备少量公有 IP 池的私有集群的负载均衡服务
部署到 Kubernetes 中的 MetalLB 为集群提供了一个负载均衡的实现。简单说来,MetalLB 能够在非公有云 Kubernetes 环境中对 LoadBalancer 类型的 Service 提供支持。在托管 Kubernetes 环境中,申请一个负载均衡之后,云平台会给这个新的负载均衡分配 IP;MetalLB 可以负责这个分配过程。MetalLB 给 Service 分配外部 IP 之后,需要声明该 IP 属于本集群,它使用标准路由协议来完成这一任务:ARP、NDP 或 BGP。
在 2 层模式中,集群的一个节点获取这个 Service 的所有权,然后使用标准的地址发现协议(IPv4 使用 ARP、IPv6 使用 NDP)在本地网中让次 IP 可达。从局域网的角度来看,这个节点只是多了一个 IP 地址。
在 BGP 模式中,集群中的所有节点都会对附近的路由器发起 BGP 对等会话,告知路由器如何将流量转发给这些服务。BGP 的策略机制有细粒度的流量控制能力,能真正地在多个节点之间进行负载均衡。
MetalLB 的 Pod:
- Controller(Deployment)是集群级的 MetalLB 控制器,负责 IP 分配。
- Speaker(Daemonset)在每个节点上运行,使用多种发布策略公告服务和外部 IP 的对应关系。
MetalLB 能够用在集群里的任何
LoadBalancer
类型的 Service 中,但是 MetalLB 为大型 IP 地址池工作就不太现实了。