使用 kube-vip 搭建高可用 Kubernetes 集群
kube-vip 可以在你的控制平面節點上提供一個 Kubernetes 原生的 HA 負載均衡,我們不需要再在外部設置 HAProxy 和 Keepalived 來實現集群的高可用了。
kube-vip 是一個為 Kubernetes 集群內部和外部提供高可用和負載均衡的開源項目,在 Vmware 的 Tanzu 項目中已經使用 kube-vip 替換了用于 vSphere 部署的 HAProxy 負載均衡器,本文我們將先來了解 kube-vip 如何用于 Kubernetes 控制平面的高可用和負載均衡功能。
特點
Kube-Vip 最初是為 Kubernetes 控制平面提供 HA 解決方案而創建的,隨著時間的推移,它已經發展為將相同的功能合并到 Kubernetes 的 LoadBalancer 類型的 Service 中了。
- VIP 地址可以是 IPv4 或 IPv6
- 帶有 ARP(第2層)或 BGP(第3層)的控制平面
- 使用領導選舉或 raft 控制平面
- 帶有 kubeadm(靜態 Pod)的控制平面 HA
- 帶有 K3s/和其他(DaemonSets)的控制平面 HA
- 使用 ARP 領導者選舉的 Service LoadBalancer(第 2 層)
- 通過 BGP 使用多個節點的 Service LoadBalancer
- 每個命名空間或全局的 Service LoadBalancer 地址池
- Service LoadBalancer 地址通過 UPNP 暴露給網關
HAProxy 和 kube-vip 的 HA 集群
在以前我們在私有環境下創建 Kubernetes 集群時,我們需要準備一個硬件/軟件的負載均衡器來創建多控制面集群,更多的情況下我們會選擇使用 HAProxy + Keepalived 來實現這個功能。一般情況下我們創建2個負載均衡器的虛擬機,然后分配一個 VIP,然后使用 VIP 為負載均衡器提供服務,通過 VIP 將流量重定向到后端的某個 Kubernetes 控制器平面節點上。
接下來我們再來看看如果我們使用 kube-vip 的話會怎樣呢?
kube-vip 可以通過靜態 pod 運行在控制平面節點上,這些 pod 通過ARP 對話來識別每個節點上的其他主機,所以需要在 hosts 文件中設置每個節點的 IP 地址,我們可以選擇 BGP 或 ARP 來設置負載平衡器,這與 Metal LB 比較類似。這里我們沒有 BGP 服務,只是想快速測試一下,所以這里我們使用 ARP 與靜態 pod 的方式。
kube-vip 架構
kube-vip 有許多功能設計選擇提供高可用性或網絡功能,作為VIP/負載平衡解決方案的一部分。
Cluster
kube-vip 建立了一個多節點或多模塊的集群來提供高可用性。在 ARP 模式下,會選出一個領導者,這個節點將繼承虛擬 IP 并成為集群內負載均衡的領導者,而在 BGP 模式下,所有節點都會通知 VIP 地址。
當使用 ARP 或 layer2 時,它將使用領導者選舉,當然也可以使用 raft 集群技術,但這種方法在很大程度上已經被領導者選舉所取代,特別是在集群中運行時。
虛擬IP
集群中的領導者將分配 vip,并將其綁定到配置中聲明的選定接口上。當領導者改變時,它將首先撤銷 vip,或者在失敗的情況下,vip 將直接由下一個當選的領導者分配。
當 vip 從一個主機移動到另一個主機時,任何使用 vip 的主機將保留以前的 vip <-> MAC 地址映射,直到 ARP 過期(通常是30秒)并檢索到一個新的 vip <-> MAC 映射,這可以通過使用無償的 ARP 廣播來優化。
ARP
kube-vip可以被配置為廣播一個無償的 arp(可選),通常會立即通知所有本地主機 vip <-> MAC 地址映射已經改變。
下面我們可以看到,當 ARP 廣播被接收時,故障轉移通常在幾秒鐘內完成。
- 64 bytes from 192.168.0.75: icmp_seq=146 ttl=64 time=0.258 ms
- 64 bytes from 192.168.0.75: icmp_seq=147 ttl=64 time=0.240 ms
- 92 bytes from 192.168.0.70: Redirect Host(New addr: 192.168.0.75)
- Vr HL TOS Len ID Flg off TTL Pro cks Src Dst
- 4 5 00 0054 bc98 0 0000 3f 01 3d16 192.168.0.95 192.168.0.75
- Request timeout for icmp_seq 148
- 92 bytes from 192.168.0.70: Redirect Host(New addr: 192.168.0.75)
- Vr HL TOS Len ID Flg off TTL Pro cks Src Dst
- 4 5 00 0054 75ff 0 0000 3f 01 83af 192.168.0.95 192.168.0.75
- Request timeout for icmp_seq 149
- 92 bytes from 192.168.0.70: Redirect Host(New addr: 192.168.0.75)
- Vr HL TOS Len ID Flg off TTL Pro cks Src Dst
- 4 5 00 0054 2890 0 0000 3f 01 d11e 192.168.0.95 192.168.0.75
- Request timeout for icmp_seq 150
- 64 bytes from 192.168.0.75: icmp_seq=151 ttl=64 time=0.245 ms
使用 kube-vip
接下來我們來使用 kube-vip 搭建一個高可用的 Kubernetes 集群。先準備6個節點:
- 3個控制平面節點
- 3個 worker 節點
首先在宿主機上面安裝相關依賴,包括 kubeadm、kubelet、kubectl 以及一個容器運行時,這里我們使用的是 containerd。
獲取 kube-vip 的 docker 鏡像,并在 /etc/kuberentes/manifests 中設置靜態 pod 的 yaml 資源清單文件,這樣 Kubernetes 就會自動在每個控制平面節點上部署 kube-vip 的 pod 了。
- # 設置VIP地址
- export VIP=192.168.0.100
- export INTERFACE=eth0
- ctr image pull docker.io/plndr/kube-vip:0.3.1
- ctr run --rm --net-host docker.io/plndr/kube-vip:0.3.1 vip \
- /kube-vip manifest pod \
- --interface $INTERFACE \
- --vip $VIP \
- --controlplane \
- --services \
- --arp \
- --leaderElection | tee /etc/kubernetes/manifests/kube-vip.yaml
接下來就可以配置 kubeadm 了,如下所示:
- cat > ~/init_kubelet.yaml <<EOF
- apiVersion: kubeadm.k8s.io/v1beta2
- kind: InitConfiguration
- bootstrapTokens:
- - token: "9a08jv.c0izixklcxtmnze7"
- description: "kubeadm bootstrap token"
- ttl: "24h"
- nodeRegistration:
- criSocket: "/var/run/containerd/containerd.sock"
- ---
- apiVersion: kubeadm.k8s.io/v1beta2
- kind: ClusterConfiguration
- controlPlaneEndpoint: "192.168.0.100:6443"
- ---
- apiVersion: kubelet.config.k8s.io/v1beta1
- kind: KubeletConfiguration
- cgroupDriver: "systemd"
- protectKernelDefaults: true
- EOF
- kubeadm init --config init_kubelet.yaml --upload-certs
然后安裝 CNI,比如我們選擇使用 Cilium。
- curl https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash
- helm repo add cilium https://helm.cilium.io/
- helm install cilium cilium/cilium --version 1.9.4 \
- --namespace kube-system
在第一個控制平面節點準備好后,讓其他節點加入你的集群。對于其他控制平面節點,運行如下命令:
- kubeadm join 192.168.0.100:6443 --token hash.hash\
- --discovery-token-ca-cert-hash sha256:hash \
- --control-plane --certificate-key key
對于工作節點,運行類似命令:
- kubeadm join 192.168.0.100:6443 --token hash.hash\
- --discovery-token-ca-cert-hash sha256:hash
正常執行完成后集群就可以啟動起來了:
- # kubectl get node -o wide
- NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
- k8s-master-0 Ready control-plane,master 121m v1.20.2 192.168.0.201 <none> Ubuntu 20.04.2 LTS 5.4.0-45-generic containerd://1.4.3
- k8s-master-1 Ready control-plane,master 114m v1.20.2 192.168.0.202 <none> Ubuntu 20.04.2 LTS 5.4.0-45-generic containerd://1.4.3
- k8s-master-2 Ready control-plane,master 113m v1.20.2 192.168.0.203 <none> Ubuntu 20.04.2 LTS 5.4.0-45-generic containerd://1.4.3
- k8s-worker-0 Ready <none> 114m v1.20.2 192.168.0.204 <none> Ubuntu 20.04.2 LTS 5.4.0-45-generic containerd://1.4.3
- k8s-worker-1 Ready <none> 114m v1.20.2 192.168.0.205 <none> Ubuntu 20.04.2 LTS 5.4.0-45-generic containerd://1.4.3
- k8s-worker-2 Ready <none> 112m v1.20.2 192.168.0.206 <none> Ubuntu 20.04.2 LTS 5.4.0-45-generic containerd://1.4.3
現在可以看到我們的控制面的端點是 192.168.0.100,沒有其他額外的節點,是不是非常方便。
參考文檔:https://inductor.medium.com/say-good-bye-to-haproxy-and-keepalived-with-kube-vip-on-your-ha-k8s-control-plane-bb7237eca9fc