MetalLB才是给Ingress这个老登做负重前行的那个男人

前文ingress这个老6, 记录了我对于ingress-nginx的默认部署方式的认知:

在集群内产生nginx服务,与集群内服务互访,利用nginx 走7层转发;

产生的nginx服务对外以nodeport形式暴露。

但是读者也发现了这种默认的ingress-nginx并没有解决:

  • 节点负载均衡
  • 端口受限,且不够优雅的问题

所以文章说ingress前面还得有一个负载均衡器。

这个鸡生蛋,蛋生鸡的问题还是得从k8s原教旨找答案。

1. nodeport vs loadbalancer

k8s 提供多种服务对外暴露的能力选项:

  • nodeport:某个节点上的端口被用于路由请求到某一个后端服务,端口范围是30000-32767,所以你不能通过NodePort像80或443端口这样常见的端口。

  • loadbalancer:是一项服务,通常由云服务提供商作为外部服务实现(需额外付费);但是,loadbalancer也可采用MetalLB这样的软件负载均衡方案来安装到自建k8s集群, 这也是本文我要强化的技术漏洞。

    loadbalancer 提供了单一ip(跨多节点的)来访问upstream 服务的能力。

那我们为什么还要ingress?

ingress本身是一个nginx svc,提供了统一的入站请求规则入口,收敛了访问k8s内部服务的能力。规则可以是uri、path、host name、https。

2.ingress nginx controller

ingress nginx controller 是一个流行的ingress。

既然ingress也是一个k8s服务(收敛了upstream服务的访问能力), 那么上面k8s对外暴露服务的两种方式 也可以作用在 ingress上,打通整个南北链路。

2.1 以nodeport形式安装ingress

这是最简单的安装形式, 通过安装我们能看到产生的的svc(nodeport形式)和deploy(nginx pod)。

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.1.3/deploy/static/provider/baremetal/deploy.yaml

使用nodeport给出的端口访问这个ingress-nginx。

curl <worker_external_ip>:<node_port>

访问上游服务,可通过curl <worker-external-ip>:<node-port> -H 'Host: web.example.com'

这种也是上文着重聊的ingress基础原理,但是很明显,nodeport形式暴露的服务达不到生产级别。

2.2 使用loadbalancer形式安装ingress

我的误区是认为:只有云上k8s才能以loadbalancer形式暴露服务。

实际上在自建k8s集群,MetalLB这种软件负载均衡器也是同样的作用。

在自建k8s集群,第一步是使用MetalLB提供loadbalancer能力。

  1. 我们先来验证k8s集群是否有 loadbalancer能力。

kubectl apply -f example-lb.yaml

example-lb.yaml 复制代码
apiVersion: v1
kind: Service
metadata:
  name: example-load-balancer
spec:
  selector:
    app: web
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
  type: LoadBalancer

执行下列命令,kubectl get service example-load-balancer, 你会看到一个external ip

如果云上/自建k8s集群没有loadbalancer能力, 你将看不到 externalip, 将会显示pending

验证有效,那么咱们就可以把ingress-nginx svc改成这个形式对外暴露。

  1. 修改ingres-nginx svc为loadbalancer形式

kubectl edit svc ingress-nginx-controller -n ingress-nginx

---> 关注spec.type

  1. 使用 external-ip 访问服务

3. 聚焦MetalLB

Why:

k8s并没有为裸金属k8s集群 提供网络负载均衡器 (svc type = loadbalancer),k8s源码中的loadbalancer是为云服务商提供的胶水代码。

如果你不是在受支持的IaaS云平台(GCP、AWS、Azure 等)上运行k8s,创建的负载均衡器将保持"pending"状态。

裸金属k8s集群的操作员只有使用"NodePort"和"externalIPs服务"将用户流量引入他们的集群,

这两种选项在生产环境中都有显著的缺点,这使得裸金属集群在 Kubernetes 生态系统中成为二等公民。

MetalLB 旨在通过提供一种可与标准网络设备集成的网络负载均衡器实现方案来纠正这种失衡,使裸金属k8s集群上也能"开箱即用"地使用loadbalancer服务能力。

MetalLB做了两个事情

  1. 地址分配(controller): 当创建loadbalancer类型的服务时,MetalLb为其分配ip,这个ip是从预先分配的ip地址池中获取的。

    当服务删除时, 已分配的ip也会被回收。

  2. 对外广播(speaker): 给服务分配ip地址后,要让集群外的网络知道这个地址的存在,MetalLB使用了标准路由协议:ARP、NDP、BGP。

有两种模式:L2、BGP, 区别在于IP通告的方式不一样。

Layer2 模式是一种基础、通用的实现,能用易用,但是有局限(单点瓶颈和故障转移慢);

BGP模式 有依赖有门槛,尽量用,用不了用L2模式。


注意MetalLB在安装时要先修改 kube-proxy配置

总结

  • k8s 对外暴露服务的方式:只有nodeport 和loadbalancer

  • loadbalancer 可以是云上提供,也可以是以软件负载均衡器MetalLB来自建,

    -- MetalLB行为: 从地址池分配IP给服务;对外公告IP

  • ingress 本身不是一个对外暴露服务的最佳生产实践,它的重点是一个规则入口收敛了众多upstream的服务访问, 它本身是一个 nginx svc,故做成loadbalancer形式就做到了统一对外暴露upstream服务。