kube-vip: Kubernetes HA/负载均衡器

发布时间: 更新时间: 总字数:5096 阅读时间:11m 作者: IP上海 分享 网址

kube-vipKubernetes 集群 提供一个虚拟 IP (VIP)负载均衡器,用于控制平面(以便构建高可用集群)和类型为 LoadBalancerKubernetes Service,而无需依赖任何外部硬件或软件。

为什么选择 Kube-Vip?

kube-vip 的目的是简化 HA Kubernetes 集群的构建,而目前这可能涉及一些都需要管理的组件和配置。thebsdbox 在这里详细撰写了博文

替代的 HA 方案

kube-vip 为您的 Kubernetes 集群提供了一个浮动或虚拟 IP 地址,并负载均衡传入的流量到各个控制平面副本。目前,要复制此功能,至少需要两种工具:

VIP (虚拟 IP):

LoadBalancing (负载均衡):

  • HAProxy
  • Nginx
  • 硬件负载均衡器(功能因厂商而异)

所有这些都需要单独的配置,在某些基础设施中可能需要多个团队才能实施。此外,考虑到软件组件,它们可能需要打包成容器,如果它们是预先打包好的,那么安全性和透明度可能会成为问题。最后,在边缘环境中,我们可能硬件空间有限(没有硬件负载均衡器),或者缺乏正确架构的软件包解决方案(例如 ARM)。幸运的是,kube-vip 是用 GO 语言编写的,它小巧易于为多种架构构建,并具有安全优势,因为它是容器中所需的唯一组件。

模式

ARP

ARP 是一种二层协议,用于通知网络新地址的位置。当为一个设备配置一个新的 IP 地址时,需要一种机制来通知网络是哪个硬件正在承载这个新地址。ARP 就是用于确保网络理解硬件地址 (MAC)逻辑地址 (IP) 之间关联的技术。为了通知整个二层网络一个新的 IP <–> MAC 配对,通常会执行无故 ARP 广播 (gratuitous ARP broadcast),更多细节可在此处找到 https://www.practicalnetworking.net/series/arp/gratuitous-arp/

BGP

BGP 是一种机制,使得依赖于路由 (三层) 的网络能够确保新地址通告给路由基础设施。当这些信息更新后,它透明地意味着路由器将自动把流量转发到正确的设备

路由表 (Routing Table)

路由表模式是为了允许配置额外的路由技术,例如 ECMP 等,以便可以将流量发送到一系列节点(例如您的 Kubernetes 节点)。kube-vip管理这些节点路由表中地址的添加/删除,从而使它们能够接收到正确的流量。

WireGuard

Wireguard 模式允许 Kubernetes Service 通过 WireGuard 接口 (wg0) 进行通告。它的一个主要用例是,分散在多个集群中的服务可以将其所有通告的服务集中到由 WireGuard 控制的中心网络上。

特性

控制平面 (Control Plane)

  • VIP 地址可以是 IPv4IPv6
  • 使用 ARP (二层)BGP (三层) 的控制平面
  • 使用领导者选举 (leader election) 的控制平面
  • 使用 kubeadm (静态 Pod) 的控制平面 HA(高可用性)
  • 使用 K3s/以及其他 (DaemonSets) 的控制平面 HA
  • 使用 ipvs 的控制平面负载均衡

Kubernetes Service (服务)

  • 使用领导者选举 (leader election) 实现 ARP (二层)Service LoadBalancer
  • 通过每个服务的领导者选举实现的分布式二层负载均衡器
  • 使用多个节点BGPService LoadBalancer
  • 使用 WireguardService LoadBalancer
  • 按命名空间全局Service LoadBalancer 地址池
  • 通过 (现有网络 DHCP)Service LoadBalancer 地址
  • 通过 UPNP网关暴露 Service LoadBalancer 地址
  • … 还有清单生成 (manifest generation)厂商 API 集成等等。

部署

Static Pods

Static Pods(静态 Pod) 是由单个节点上的 kubelet 运行的 Kubernetes Pod,它们不由 Kubernetes 集群本身管理。这意味着虽然 Pod 可以出现在 Kubernetes 中,但它无法使用各种 Kubernetes 功能(例如 Kubernetes 令牌或 ConfigMap 资源)。静态 Pod 方法主要为 kubeadm 所需,这是由于 kubeadm 执行的操作顺序所致。理想情况下,我们希望 kube-vip 成为 Kubernetes 集群的一部分,但对于各种功能,我们还需要 kube-vip 在安装过程中提供一个 高可用 (HA) 虚拟 IP。

使用 kubeadm 和 kube-vip 构建高可用 Kubernetes 集群的事件顺序如下:

  1. 在静态 Pod 清单目录中生成一个 kube-vip 清单(参见下面的 generating a manifest 部分)。
  2. 使用生成静态 Pod 清单时提供的 VIP 地址,运行带有 --control-plane-endpoint 标志的 kubeadm init
  3. kubelet 将解析并执行所有清单,包括在第一步中生成的 kube-vip 清单以及其他控制平面组件,包括 kube-apiserver
  4. kube-vip 启动并通告 VIP 地址。
  5. 第一个控制平面上的 kubelet 将连接到上一步通告的 VIP
  6. kubeadm init 在第一个控制平面上成功完成。
  7. 使用第一个控制平面上 kubeadm init 命令的输出,在其余控制平面上运行 kubeadm join 命令。
  8. 将生成的 kube-vip 清单复制到其余控制平面,并将其放置在它们的静态 Pod 清单目录中(默认为 /etc/kubernetes/manifests/)。

kube-vip 作为 HA、负载均衡器,或两者兼具

kube-vip 的功能取决于用于创建静态 Pod 清单的标志。通过传入 --controlplane,我们指示 kube-vip 提供并通告一个供控制平面使用的虚拟 IP。通过传入 --services,我们告诉 kube-vip 为集群内部创建的 Kubernetes Service 资源提供负载均衡。如果两者都启用,kube-vip 将管理一个通过其配置传入的虚拟 IP 地址,以实现高可用的 Kubernetes 集群。它还会监视类型为 LoadBalancer 的 Service,一旦它们的 service.metadata.annotations["kube-vip.io/loadbalancerIPs"]spec.LoadBalancerIP 被更新(通常由云控制器更新,包括(可选地)kube-vip 在 on-prem(本地部署) 场景中提供的控制器),它将使用 BGP/ARP 通告此地址。在本例中,我们在生成清单时将两者都使用。

generating a manifest

为了提供更便捷的使用 kube-vip 各种功能的体验,我们可以使用 kube-vip 容器本身来生成我们的静态 Pod 清单。我们通过将 kube-vip 镜像作为容器运行,并传入我们想要启用的各种功能 标志 来实现这一点。

设置配置详情

我们使用环境变量来预定义提供给 kube-vip 的输入值。

设置用于控制平面的 VIP 地址:

export VIP=192.168.0.40

INTERFACE 名称设置为控制平面上将通告 VIP 的接口名称。在许多 Linux 发行版中,可以使用 ip a 命令找到它。

export INTERFACE=ens160

通过解析 GitHub API 获取最新版本的 kube-vip 发布。此步骤要求安装了 jqcurl

KVVERSION=$(curl -sL https://api.github.com/repos/kube-vip/kube-vip/releases | jq -r ".[0].name")

若要手动设置,请查找所需的 发布标签

export KVVERSION=v0.5.0

创建清单

设置好输入值后,我们可以拉取并运行 kube-vip 镜像,并向其提供所需的标志和值。一旦为所需的方法(ARP 或 BGP)生成了静态 Pod 清单,如果运行多个控制平面节点,请确保将其放置在每个控制平面的静态清单目录中(默认情况下为 /etc/kubernetes/manifests)。

根据容器运行时,使用以下两个别名命令之一来创建一个运行 kube-vip 镜像作为容器的 kube-vip 命令。

对于 containerd,运行以下命令:

alias kube-vip="ctr image pull ghcr.io/kube-vip/kube-vip:$KVVERSION; ctr run --rm --net-host ghcr.io/kube-vip/kube-vip:$KVVERSION vip /kube-vip"

对于 Docker,运行以下命令:

alias kube-vip="docker run --network host --rm ghcr.io/kube-vip/kube-vip:$KVVERSION"

ARP

设置好输入和别名命令后,我们可以运行 kube-vip 容器来生成一个静态 Pod 清单,该清单将被定向到一个文件 /etc/kubernetes/manifests/kube-vip.yaml。因此,这假设在第一个控制平面节点上运行。

此配置将创建一个清单,该清单启动 kube-vip,使用 leaderElection 方法和 ARP 提供控制平面 VIP 和 Kubernetes Service 管理。当此实例被选为 Leader 时,它会将 vip 绑定到指定的 interface。Services 类型为 LoadBalancer 的行为也相同。

注意:在要成为控制平面节点的机器上运行这些命令时,可能需要 sudo 权限以及预先创建 /etc/kubernetes/manifests/ 目录。

kube-vip manifest pod \
    --interface $INTERFACE \
    --address $VIP \
    --controlplane \
    --services \
    --arp \
    --leaderElection | tee /etc/kubernetes/manifests/kube-vip.yaml

ARP 清单示例

apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  name: kube-vip
  namespace: kube-system
spec:
  containers:
    - args:
        - manager
      env:
        - name: vip_arp
          value: 'true'
        - name: port
          value: '6443'
        - name: vip_interface
          value: ens192
        - name: vip_subnet
          value: '32'
        - name: cp_enable
          value: 'true'
        - name: cp_namespace
          value: kube-system
        - name: vip_ddns
          value: 'false'
        - name: svc_enable
          value: 'true'
        - name: vip_leaderelection
          value: 'true'
        - name: vip_leaseduration
          value: '5'
        - name: vip_renewdeadline
          value: '3'
        - name: vip_retryperiod
          value: '1'
        - name: address
          value: 192.168.0.40
      image: ghcr.io/kube-vip/kube-vip:v0.4.0
      imagePullPolicy: Always
      name: kube-vip
      resources: {}
      securityContext:
        capabilities:
          add:
            - NET_ADMIN
            - NET_RAW
            - SYS_TIME
      volumeMounts:
        - mountPath: /etc/kubernetes/admin.conf
          name: kubeconfig
  hostAliases:
    - hostnames:
        - kubernetes
      ip: 127.0.0.1
  hostNetwork: true
  volumes:
    - hostPath:
        path: /etc/kubernetes/admin.conf
      name: kubeconfig
status: {}

注意:自 Kubernetes v1.29 起,kubeadm 引导过程已更改,导致 admin.conf 无法立即使用。可以通过在初始化时使用 super-admin.conf,然后完成后切换到 admin.conf 来解决此问题。有关更多详细信息,请参阅 此问题

BGP

此配置将创建一个清单,该清单启动 kube-vip,提供控制平面 VIP 和 Kubernetes Service 管理。与 ARP 不同,BGP 配置中的所有节点都将通告虚拟 IP 地址。

注意 我们将地址绑定到 lo,因为我们不希望在公共接口上有多个具有相同地址的设备。我们可以使用逗号分隔列表指定所有对等点,格式为 address:AS:password:multihop

export INTERFACE=lo

kube-vip manifest pod \
    --interface $INTERFACE \
    --address $VIP \
    --controlplane \
    --services \
    --bgp \
    --localAS 65000 \
    --bgpRouterID 192.168.0.2 \
    --bgppeers 192.168.0.10:65000::false,192.168.0.11:65000::false | tee /etc/kubernetes/manifests/kube-vip.yaml

BGP 清单示例

apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  name: kube-vip
  namespace: kube-system
spec:
  containers:
    - args:
        - manager
      env:
        - name: vip_arp
          value: 'false'
        - name: port
          value: '6443'
        - name: vip_interface
          value: lo
        - name: vip_subnet
          value: '32'
        - name: cp_enable
          value: 'true'
        - name: cp_namespace
          value: kube-system
        - name: vip_ddns
          value: 'false'
        - name: bgp_enable
          value: 'true'
        - name: bgp_routerid
          value: 192.168.0.2
        - name: bgp_as
          value: '65000'
        - name: bgp_peeraddress
        - name: bgp_peerpass
        - name: bgp_peeras
          value: '65000'
        - name: bgp_peers
          value: 192.168.0.10:65000::false,192.168.0.11:65000::false
        - name: address
          value: 192.168.0.40
      image: ghcr.io/kube-vip/kube-vip:v0.3.9
      imagePullPolicy: Always
      name: kube-vip
      resources: {}
      securityContext:
        capabilities:
          add:
            - NET_ADMIN
            - NET_RAW
            - SYS_TIME
      volumeMounts:
        - mountPath: /etc/kubernetes/admin.conf
          name: kubeconfig
  hostAliases:
    - hostnames:
        - kubernetes
      ip: 127.0.0.1
  hostNetwork: true
  volumes:
    - hostPath:
        path: /etc/kubernetes/admin.conf
      name: kubeconfig
status: {}

DaemonSet

一些 Kubernetes 发行版可以启动 Kubernetes 集群,而无需依赖预先存在的 VIP(但它们可以配置为支持 VIP)。一个主要的例子是 K3s,它可以配置为启动并签署证书,以允许传入流量流向虚拟 IP。鉴于我们不需要在集群之前存在 VIP,我们可以启动 K3s 节点,然后将 kube-vip 作为 DaemonSet 添加到所有控制平面节点。

如果 Kubernetes 安装程序允许将虚拟 IP 作为附加的 SANSubject Alternative Name,主题备用名称)添加到 API 服务器证书,那么一旦第一个节点启动,我们就可以将 kube-vip 应用于集群。

与将 kube-vip 作为静态 Pod 运行不同,将 kube-vip 作为 DaemonSet 运行时,可能需要配置更多内容。下将主要介绍这些差异

kube-vip 作为 HA、负载均衡器或两者

kube-vip 的功能取决于用于创建 Daemonset 清单的标志。通过传入 --controlplane,我们指示 kube-vip 提供和广播一个用于控制平面的虚拟 IP。通过传入 --services,我们告知 kube-vip 为集群内创建的 Kubernetes Service 资源提供负载均衡。两者都启用后,kube-vip 将管理一个通过其配置传入的虚拟 IP 地址,用于高可用性的 Kubernetes 集群。它还将监控 LoadBalancer 类型的 Service,一旦它们的 service.metadata.annotations["kube-vip.io/loadbalancerIPs"]spec.LoadBalancerIP 被更新(通常由云控制器更新,包括(可选)kube-vip 在 on-prem 场景中提供的云控制器),它将使用 BGP/ARP 来广播此地址。在此示例中,我们将在生成清单时同时使用两者

routing table 模式下,可以配置 kube-vip 不使用任何形式的领导者选举。在这种情况下,每个 kube-vip 实例将监控所有配置的 Service,如果运行 kube-vip 实例的节点具有与该 Service 关联的端点,它将配置路由。为此,不应设置 leaderElectionservicesElection 标志。

创建 RBAC 设置

由于作为 DaemonSet 运行的 kube-vip 是作为常规资源而不是静态 Pod 运行,因此它仍然需要正确的访问权限才能监控 Kubernetes Service 和其他对象。为此,必须创建 RBAC 资源,包括 ServiceAccountClusterRoleClusterRoleBinding,可以使用以下命令应用:

kubectl apply -f https://kube-vip.io/manifests/rbac.yaml

生成清单

为了更容易地使用 kube-vip 中的各种功能,我们可以使用 kube-vip 容器本身来生成我们的静态 Pod 清单。我们通过将 kube-vip 镜像作为容器运行,并传入我们想要启用的各种 标志 来实现此目的。

设置配置详细信息

我们使用环境变量来预定义要提供给 kube-vip 的输入值

设置用于控制平面的 VIP 地址

export VIP=192.168.0.40

INTERFACE 名称设置为将广播 VIP 的控制平面上的接口名称。在许多 Linux 发行版中,可以使用 ip a 命令找到它。

export INTERFACE=ens160

通过解析 GitHub API 获取最新版本的 kube-vip 版本。此步骤需要安装 jqcurl

KVVERSION=$(curl -sL https://api.github.com/repos/kube-vip/kube-vip/releases | jq -r ".[0].name")

手动设置,请查找所需的 release tag

export KVVERSION=v0.5.0

创建清单

设置输入值后,我们可以拉取并运行 kube-vip 镜像,向其提供所需的标志和值。

根据容器运行时,使用以下两个别名命令之一来创建运行 kube-vip 镜像作为容器的 kube-vip 命令。

对于 containerd,运行以下命令:

alias kube-vip="ctr image pull ghcr.io/kube-vip/kube-vip:$KVVERSION; ctr run --rm --net-host ghcr.io/kube-vip/kube-vip:$KVVERSION vip /kube-vip"

对于 Docker,运行以下命令:

alias kube-vip="docker run --network host --rm ghcr.io/kube-vip/kube-vip:$KVVERSION"

DaemonSet 的 ARP 示例

当创建作为 DaemonSet 的 kube-vip 安装清单时,manifest 子命令采用的值是 daemonset,而不是 pod 值。还需要 --inCluster--taint 标志来配置 DaemonSet 使用 ServiceAccount 并将 kube-vip Pods 亲和到控制平面节点,从而阻止它们在工作实例上运行。

kube-vip manifest daemonset \
    --interface $INTERFACE \
    --address $VIP \
    --inCluster \
    --taint \
    --controlplane \
    --services \
    --arp \
    --leaderElection

ARP 清单示例

apiVersion: apps/v1
kind: DaemonSet
metadata:
  creationTimestamp: null
  name: kube-vip-ds
  namespace: kube-system
spec:
  selector:
    matchLabels:
      name: kube-vip-ds
  template:
    metadata:
      creationTimestamp: null
      labels:
        name: kube-vip-ds
    spec:
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
              - matchExpressions:
                  - key: node-role.kubernetes.io/master
                    operator: Exists
              - matchExpressions:
                  - key: node-role.kubernetes.io/control-plane
                    operator: Exists
      containers:
        - args:
            - manager
          env:
            - name: vip_arp
              value: 'true'
            - name: port
              value: '6443'
            - name: vip_interface
              value: ens160
            - name: vip_subnet
              value: '32'
            - name: cp_enable
              value: 'true'
            - name: cp_namespace
              value: kube-system
            - name: vip_ddns
              value: 'false'
            - name: svc_enable
              value: 'true'
            - name: vip_leaderelection
              value: 'true'
            - name: vip_leaseduration
              value: '5'
            - name: vip_renewdeadline
              value: '3'
            - name: vip_retryperiod
              value: '1'
            - name: address
              value: 192.168.0.40
          image: ghcr.io/kube-vip/kube-vip:v0.4.0
          imagePullPolicy: Always
          name: kube-vip
          resources: {}
          securityContext:
            capabilities:
              add:
                - NET_ADMIN
                - NET_RAW
                - SYS_TIME
      hostNetwork: true
      serviceAccountName: kube-vip
      tolerations:
        - effect: NoSchedule
          operator: Exists
        - effect: NoExecute
          operator: Exists
  updateStrategy: {}
status:
  currentNumberScheduled: 0
  desiredNumberScheduled: 0
  numberMisscheduled: 0
  numberReady: 0

DaemonSet 的 BGP 示例

此配置将创建一个清单,该清单启动 kube-vip 以提供控制平面 VIPKubernetes Service 管理。与 ARP 不同,BGP 配置中的所有节点都将广播虚拟 IP 地址。

注意:我们将地址绑定到 lo,因为我们不希望公共接口上有多个设备具有相同的地址。我们可以用逗号分隔列表的形式指定所有对等点,格式为 address:AS:password:multihop

export INTERFACE=lo

kube-vip manifest daemonset \
    --interface $INTERFACE \
    --address $VIP \
    --inCluster \
    --taint \
    --controlplane \
    --services \
    --bgp \
    --localAS 65000 \
    --bgpRouterID 192.168.0.2 \
    --bgppeers 192.168.0.10:65000::false,192.168.0.11:65000::false

BGP 清单示例

apiVersion: apps/v1
kind: DaemonSet
metadata:
  creationTimestamp: null
  name: kube-vip-ds
  namespace: kube-system
spec:
  selector:
    matchLabels:
      name: kube-vip-ds
  template:
    metadata:
      creationTimestamp: null
      labels:
        name: kube-vip-ds
    spec:
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
              - matchExpressions:
                  - key: node-role.kubernetes.io/master
                    operator: Exists
              - matchExpressions:
                  - key: node-role.kubernetes.io/control-plane
                    operator: Exists
      containers:
        - args:
            - manager
          env:
            - name: vip_arp
              value: 'false'
            - name: port
              value: '6443'
            - name: vip_interface
              value: ens160
            - name: vip_subnet
              value: '32'
            - name: cp_enable
              value: 'true'
            - name: cp_namespace
              value: kube-system
            - name: vip_ddns
              value: 'false'
            - name: svc_enable
              value: 'true'
            - name: bgp_enable
              value: 'true'
            - name: bgp_routerid
              value: 192.168.0.2
            - name: bgp_as
              value: '65000'
            - name: bgp_peeraddress
            - name: bgp_peerpass
            - name: bgp_peeras
              value: '65000'
            - name: bgp_peers
              value: 192.168.0.10:65000::false,192.168.0.11:65000::false
            - name: address
              value: 192.168.0.40
          image: ghcr.io/kube-vip/kube-vip:v0.4.0
          imagePullPolicy: Always
          name: kube-vip
          resources: {}
          securityContext:
            capabilities:
              add:
                - NET_ADMIN
                - NET_RAW
                - SYS_TIME
      hostNetwork: true
      serviceAccountName: kube-vip
      tolerations:
        - effect: NoSchedule
          operator: Exists
        - effect: NoExecute
          operator: Exists
  updateStrategy: {}
status:
  currentNumberScheduled: 0
  desiredNumberScheduled: 0
  numberMisscheduled: 0
  numberReady: 0

routerID 作为 DaemonSet 进行管理

routerID 需要在参与 BGP 广播的每个节点上都是唯一的。为此,我们可以修改清单,以便 kube-vip 启动时会查找其本地地址并将其用作 routerID。将以下内容添加到容器的 env[] 数组中:

- name: bgp_routerinterface
  value: 'ens160'

或者,我们可以使用 Pod 本身的 IP 地址作为 routerID 的唯一值:

- name: bgp_routerid
  valueFrom:
    fieldRef:
      fieldPath: status.podIP

DaemonSet 清单概述

一旦生成了作为 DaemonSet 的 kube-vip 清单,以下是与静态 Pod 清单相比的一些显著差异及其重要性:

  • nodeSelector:确保 DaemonSet Pods 仅在控制平面节点上运行
  • serviceAccountName: kube-vip:指定将用于获取/更新 Kubernetes Service 资源的 ServiceAccount 名称
  • tolerations:允许调度到通常指定 NoScheduleNoExecute 污点的控制平面节点。

参考

  1. https://kube-vip.io/
  2. https://github.com/kube-vip/kube-vip
  3. https://thebsdbox.co.uk/2020/01/02/Designing-Building-HA-bare-metal-Kubernetes-cluster/#Networking-load-balancing
  4. https://inductor.medium.com/say-good-bye-to-haproxy-and-keepalived-with-kube-vip-on-your-ha-k8s-control-plane-bb7237eca9fc
本文总阅读量 次 本站总访问量 次 本站总访客数
Home Archives Categories Tags Statistics