Kubernetes 负载均衡器 MetalLB

基本情况介绍

一、service

Kubernetes中一个应用服务会有一个或多个实例,每个实例(Pod)的IP地址由网络插件动态随机分配(Pod重启后IP地址会改变)。为屏蔽这些后端实例的动态变化和对多实例的负载均衡,引入了 Service这个资源对象。

type 类型

根据创建 Service 的 type 类型不同,主要分为几下几种:

ClusterIP:通过为 Kubernetes 的 Service 分配一个集群内部可访问的固定虚拟IP(Cluster IP),实现集群内的访问;
NodePort:将 service 的 port 映射到集群内每个节点的相同一个端口,实现通过 nodeIP:nodePort 从集群外访问服务;
LoadBalance:向所使用的公有云申请一个负载均衡器(负载均衡器后端映射到各节点的 nodePort),实现从集群外通过 LB 访问服务;

Port

Service 中主要涉及三种 Port:

port 表示 service 暴露在 clusterIP 上的端口,clusterIP:Port 是提供给集群内部访问 kubernetes 服务的入口;
NodePort:提供给从集群外部访问 kubernetes 服务的入口;
TargetPort:容器port,targetPort 是 pod 上的端口,从 port 和 nodePort 上到来的数据最终经过 kube-proxy 流入到后端 pod 的 targetPort 上进入容器。

port 和 nodePort 都是 service 的端口,前者暴露给从集群内访问服务,后者暴露给从集群外访问服务。从这两个端口到来的数据都需要经过反向代理 kube-proxy 流入后端具体 pod 的 targetPort,从而进入到 pod 上的容器内。

IP

使用 Service 服务会涉及到几种 IP:

Cluster IP:虚拟地址,由 kube-proxy 使用 iptables 规则重新定向到其本地端口,再均衡到后端Pod。当 kube-proxy 发现一个新的 service 后,它会在本地节点打开一个任意端口,创建相应的iptables 规则,重定向服务的 clusterIP 和 port 到这个新建的端口,开始接受到达这个服务的连接。
Pod IP:每个 Pod 启动时,会自动创建一个镜像为 gcr.io/google_containers/pause 的容器,Pod内部其他容器的网络模式使用container模式,指定为 pause 容器的ID(network_mode: “container:pause 容器ID”),使得 Pod 内所有容器共享 pause 容器的网络,与外部的通信经由此容器代理,pause容器的 IP 也可以称为Pod IP。
Node IP: 将服务作为一个应用程序内部的层次,使的服务可以从集群外部访问,指定 service 的spec.type=NodePort,通过 nodeip:nodeport 从集群外访问服务。

工作方式

定义服务的时候通过 selector 指定服务对应的 pods,根据 pods 的地址创建出 endpoints 作为服务后端;Endpoints Controller 会 watch Service 以及 pod 的变化,维护对应的 Endpoint 信息。kube-proxy根据 Service 和 Endpoint 来维护本地的路由规则。当 Endpoint 发生变化,即 Service 以及关联的pod发生变化,kube-proxy 都会在每个节点上更新 iptables,实现一层负载均衡。

MetalLB 基本介绍

官方文档地址:https://metallb.universe.tf/

该项目发布于 2017 年底,当前处于 Beta 阶段。

MetalLB完全支持的网络插件Canal、Cilium、Flannel、Kube-ovn等。如果kube-proxy运行在IPVS模式先,需要设置strictARP: true(后面会详细阐述)

Kubernetes不提供网络负载均衡器的实现(LoadBalancer类型的服务)用于裸机集群。Kubernetes附带的Network LB的实现都是调用各种IaaS平台(GCP,AWS,Azure等)的粘合代码。如果您未在受支持的IaaS平台(GCP,AWS,Azure等)上运行,则LoadBalancers在创建时将无限期保持“待处理”状态。

裸机集群运营商只剩下两个较小的工具,即“ NodePort”和“ externalIPs”服务,可将用户流量引入其集群。这两个选项在生产用途上都有很大的缺点,这使裸金属集群成为Kubernetes生态系统中的二等公民。

MetalLB旨在通过提供与标准网络设备集成的Network LB实现来解决这种不平衡问题,从而使裸机群集上的外部服务也尽可能“正常运行”。

简单来说:在裸机集群上(不是公有云厂商的主机,比如阿里云,腾讯云)部署k8s后,外部网络访问集群里的服务,通过ingress-nginx的形式,但是这个ingress-nginx的服务service端口类型对外暴露只能使用“ NodePort”和“ externalIPs”服务,不能使用LoadBalancer的,使用MetalLB则可以解决这个问题,使ingress-nginx的service端口类型对外暴露使用LoadBalancer的形式(不用使用云厂商提供的负载均衡器)

MetalLB是 Kubernetes 集群中关于LoadBalancer的一个具体实现,主要用于暴露k8s集群的服务到集群外部访问。由两个共同提供此服务的工作负载(workload):地址分配和外部公告;对应的就是在 k8s中部署的 controller 和 speaker。

Metallb 会在 Kubernetes 内运行,监控服务对象的变化,一旦察觉有新的 LoadBalancer 服务运行,并且没有可申请的负载均衡器之后,就会完成两部分的工作:

1.地址分配,用户需要在配置中提供一个地址池,Metallb 将会在其中选取地址分配给服务。
2.地址广播,根据不同配置,Metallb 会以二层(ARP/NDP)或者 BGP 的方式进行地址的广播。

地址分配(address allocation)

需要给 MetalLB 分配一段 IP,接着它会根据 service 中的相关配置来给LoadBalancer的服务分配IP,LoadBalancer的IP可以手动指定,也可以让MetalLB自动分配;同时还可以在 MetalLB 的configmap中配置多个 IP 段,并且单独设置每个 IP 段是否开启自动分配。

地址分配(address allocation)主要就是由作为 deployment 部署的 controller 来实现,它负责监听集群中的 service 状态并且分配 IP。

外部公告(external announcement)

外部公告的主要功能就是要把服务类型为LoadBalancer的服务的IP公布到网络中去,确保客户端能够正常访问到这个 IP 。MetalLB 对此的实现方式主要有三种:ARP/NDP和BGP;其中 ARP/NDP 分别对应IPv4/IPv6 协议的 Layer2 模式,BGP路由协议则是对应 BGP 模式。

外部公告主要就是由作为daemonset部署的speaker来实现,它负责在网络中发布 ARP/NDP 报文或者是和 BGP 路由器建立连接并发布 BGP 报文。

工作原理

Metallb 包含两个组件,Controller 和 Speaker,Controller 为 Deployment 部署方式,而 Speaker 则采用 Daemonset 方式部署到集群内部各个Node节点。

具体的工作原理如下图所示,Controller 负责监听 Service 变化,当 Service 配置为 LoadBalancer 模式时,从 IP 池分配给到相应的 IP 地址并对该 IP 的生命周期进行管理。Speaker 则会依据选择的协议进行相应的广播或应答,实现 IP 地址的通信响应。当业务流量通过 TCP/UDP 协议到达指定的 Node 时,由Node 上面运行的 Kube-Proxy 组件对流量进行处理,并分发到对应服务的 Pod 上面。

安装

安装之前的准备检查工作

如果您在IPVS模式下使用kube-proxy,则从Kubernetes v1.14.2开始,您必须启用严格的ARP模式。请注意,如果您将kube-router用作服务代理,则不需要此设置,因为默认情况下它启用了严格的arp。

您可以通过在当前集群中编辑kube-proxy配置来实现:

# kubectl edit configmap -n kube-system kube-proxy

并修改如下图内容

apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: "ipvs"  # 这个在安装时默认选择了ipvs
ipvs:
  strictARP: true # 修改这个

更新kube-proxy pod

# kubectl get pod -n kube-system |grep kube-proxy | awk '{system("kubectl delete pod "$1" -n kube-system")}'

另外一种修改生效方式:

# see what changes would be made, returns nonzero returncode if different
kubectl get configmap kube-proxy -n kube-system -o yaml | \
sed -e "s/strictARP: false/strictARP: true/" | \
kubectl diff -f - -n kube-system

# actually apply the changes, returns nonzero returncode on errors only
kubectl get configmap kube-proxy -n kube-system -o yaml | \
sed -e "s/strictARP: false/strictARP: true/" | \
kubectl apply -f - -n kube-system

安装

# mkdir metallb && cd cd metallb/
# wget https://github.com/metallb/metallb/blob/main/config/manifests/metallb-native.yaml
# vim metallb-native.yaml    #查看里面需要的镜像 


提前将镜像下载好,上传至私有仓库 (quay.io是Red Hat运营的镜像库,虽然没有被墙,但下载还是比较慢。可以从这个里面找到使用镜像的最新版本,然后再使用自己的github代理拉取,推送到自己的dockerhub仓库里)
(下载quay.io的镜像,可以参考这个文章:https://www.cnblogs.com/hahaha111122222/p/17097890.html)

使用私库里的镜像,需要修改metallb-native.yaml文件中使用的镜像名

Metallb 安装,会生成自己的命名空间以及 RBAC 配置。

# kubectl apply -f metallb-native.yaml
# kubectl -n metallb-system get all

创建密钥,否则会出现报错 ===》 这一步没看懂要干啥,可以暂不操作的
# kubectl create secret generic -n metallb-system memberlist --from-literal=secretkey="$(openssl rand -base64 128)"
# kubectl -n metallb-system get secrets

配置

接下来我们要生成一个 Configmap 文件,为 Metallb 设置网址范围以及协议相关的选择和配置,这里以一个简单的二层配置为例:

# vim config.yml
apiVersion: v1
kind: ConfigMap
metadata:
  namespace: metallb-system
  name: config
data:
  config: |
    address-pools:
    - name: default
      protocol: layer2
      addresses:
      - 172.25.1.100-172.25.1.200

# kubectl apply -f config.yml

注意:这里的 IP 地址范围需要跟集群实际情况相对应。(跟集群主机节点的私网IP对应,可以理解成同网段尚未使用的IP所在网段范围)

注意: 新版本使用的配置文件内容有变化,网址:https://metallb.universe.tf/configuration/_advanced_l2_configuration/

测试

我们创建一个svc进行测试

# vim  nginx.yaml 
apiVersion: v1
kind: Service
metadata:
  name: nginx-svc
spec:
  selector:
    app: nginx
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
  #externalIPs:
  #- 172.25.2.100
  #clusterIP: None
  #type: NodePort
  type: LoadBalancer  #指定一个 LoadBalancer 类型的 Service
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: demo
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: myapp:v1

可以看到我们部署的nginx-svc已经分配到了一个地址池中的ip

集群内部访问

集群外部访问

metallb跟ingress结合起来使用

对于ingress的yaml文件,可以复制过来进行修改,需要修改网络模式

去除之前做的节点绑定,不监听主机的端口

从DeamonSet 类型修改成 Deployment类型

生效并查看
# kubectl apply -f deploy.yaml
# kubectl -n ingress-nginx get all

此时访问路径为: user -> vip(metallb) -> ingress-nginx -> svc -> pod

示例

# cat nginx-svc.yml 
apiVersion: v1
kind: Service
metadata:
  name: nginx-svc
spec:
  selector:
    app: nginx
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
  type: LoadBalancer
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: myapp:v1

# cat ingress-demo.yml 
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: nginx-test
spec:
 # tls:
 #   - hosts:
 #     - www1.westos.org
 #     secretName: tls-secret
  rules:
    - host: www1.westos.org
      http:
        paths:
        - path: /
          backend:
            serviceName: nginx-svc
            servicePort: 80
# kubectl apply -f nginx-svc.yml
# kubectl apply -f  ingress-demo.yml 
# kubectl get ingress
# kubectl describe ingress nginx-test

# kubectl get svc nginx-svc

这里需要给这个ip做好地址解析,然后在外部访问域名查看效果。

calico网络插件

calico简介:

flannel实现的是网络通信,calico的特性是在pod之间的隔离。
通过BGP路由,但大规模端点的拓扑计算和收敛往往需要一定的时间和计算资源。纯三层的转发,中间没有任何的NAT和overlay,转发效率最好。
Calico 仅依赖三层路由可达。Calico 较少的依赖性使它能适配所有 VM、Container、白盒或者混合环境场景。

calico网络架构

Felix:监听ECTD中心的存储获取事件,用户创建pod后,Felix负责将其网卡、IP、MAC都设置好,然后在内核的路由表里面写一条,注明这个IP应该到这张网卡。同样如果用户制定了隔离策略,Felix同样会将该策略创建到ACL中,以实现隔离。

BIRD:一个标准的路由程序,它会从内核里面获取哪一些IP的路由发生了变化,然后通过标准BGP的路由协议扩散到整个其他的宿主机上,让外界都知道这个IP在这里,路由的时候到这里来。

IPIP工作模式:适用于互相访问的pod不在同一个网段中,跨网段访问的场景。

BGP工作模式:适用于互相访问的pod在同一个网段,适用于大型网络。

posted @ 2023-03-16 15:12  哈喽哈喽111111  阅读(1314)  评论(0编辑  收藏  举报