前一段時間寫了使用keepalived+haproxy部署k8s高可用集群,核心思想是利用keepalived生成vip實現主備容災,以及haproxy負載k8s-apiserver流量。k8s高可用部署:keepalived + haproxy
這種方式是自己實現了負載均衡。本文將探討在用戶已有SLB的場景下如何實現k8s高可用
SLB概念
阿里雲文檔中SLB(Server Load Balancer)介紹如下:
負載均衡基礎架構是采用集群部署,提供四層(TCP協議和UDP協議)和七層(HTTP和HTTPS協議)的負載均衡,可實現會話同步,以消除服務器單點故障,提升冗余,保證服務的穩定性。
負載均衡作為流量轉發服務,將來自客戶端的請求通過負載均衡集群轉發至后端服務器,后端服務器再將響應通過內網返回給負載均衡。
本文還涉及到SLB的一個關鍵技術限制:
在 4 層(TCP 協議)服務中,不支持添加進后端的服務器既作為 Real Server,又作為客戶端向所在的 SLB 實例發送請求。因為,返回的數據包只在服務器內部轉發,不經過負載均衡,所以通過配置在 SLB 后端的 服務器去訪問其 VIP 是不通的。
另外對於SLB的健康檢查、調度算法等最佳實踐不做探討,請查閱相關文檔。文本探討的范圍僅限於架構可行性驗證。
架構
1 keepalived+haproxy
由於4層SLB不支持后端服務訪問其VIP,根據kubeadm官方安裝文檔:
指定vip會發生如下超時錯誤:
[etcd] Creating static Pod manifest for local etcd in “/etc/kubernetes/manifests”
[wait-control-plane] Waiting for the kubelet to boot up the control plane as static Pods from directory “/etc/kubernetes/manifests”. This can take up to 4m0s
[kubelet-check] Initial timeout of 40s passed.
查看kubele日志:
# sudo journalctl -u kubelet.service
k8s.io/kubernetes/pkg/kubelet/kubelet.go:442: Failed to list *v1.Service: Get https://172.16.105.26:9443/api/v1/services?limit=500&resourceVersion=0: dial tcp 172.16.105.26:9443: connect: connection refused
還記得之前說的4層負載的技術限制嗎?
基於此我們出了一個比較”臟”的方案:keepalived+haproxy。安裝步驟與上一篇文章一樣,只是結果不同:
- 這種方式還是先啟用keepalived綁定vip,此時對vip的請求屬於本地訪問,不會轉發出去,因此不會出現訪問不通的情況。
- 三台keepalived都必須是leader, 否則只有一台能綁定vip,其他兩台還是加入不了
- 如何使三台都是keepalived leader? 兩種方式: 1)關閉vrrp協議(阿里雲默認關閉),此時keepalived backup收不到其他節點的廣播信息,將自己設為leader; 2)用單播方式啟動keepalived
問題:
1. 這種實現方式相當於在LB的后端又實現一次LB,但是用戶請求多了一次轉發, 顯然不是一個令人滿意的方案。
2. 這種keepalived全主模式不能應用在純vip場景下(如openstack)。這種情況安裝是沒問題的,master1先綁定vip,master2,3通過vip訪問apiserver時走本地流量,由於本地apiserver:6443還未啟動,被haproxy負載到健康節點。這么做安裝是沒問題的。但是不能保證高可用。當master1 done時,子網內部訪問vip還是能找到另外兩台健康節點,但是子網外部訪問時,路由器還是會路由到master1。
2 綁定vip方式
keepalived的解決方式其實是將vip綁定三台k8s-master,使得三台主機初始化時走本地網絡,解決后端訪問不了slb的問題。那么其實我們不需要在keepalived后面再加一層haproxy,使得請求多一次轉發,更進一步,我們不需要keepalived來綁定vip,手動綁定就好了。
安裝步驟:
2.1 init k8s-master-leader
綁定vip:
# ip addr add 172.16.105.26/32 dev eth0
查詢綁定結果:
#ip a| grep eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
inet 172.16.104.54/24 brd 172.16.104.255 scope global eth0
inet 172.16.105.26/32 scope global eth0
kubeadm-config.yaml
apiVersion: kubeadm.k8s.io/v1beta1
kind: ClusterConfiguration
kubernetesVersion: v1.14.1
imageRepository: registry.aliyuncs.com/google_containers
networking:
podSubnet: 10.244.0.0/16
controlPlaneEndpoint: 172.16.105.26:6443
join
sudo kubeadm init –config=kubeadm-config.yaml –experimental-upload-certs
記錄下日志中的join命令
2.2 join k8s-master-follower
分別將k8s-master-follower加入k8s-master-leader
sudo kubeadm join 172.16.105.26:6443 –token c1d2cb.vx086ez76bpggqj5 \
> –discovery-token-ca-cert-hash sha256:bc749b4e7e75f93ea9c0055d1c6e36c814b04247ca9e5bb6168ec3a27e5693bd \
> –experimental-control-plane –certificate-key cdb31f173bf87a573217a4cd1d6e22dc1d396a4da5050e36bdec407bd2aab29d
2.3 為k8s-master-follower綁定vip
您可能注意到follower join時沒有先綁定vip。原因是follower join時需要訪問k8s-apiserver獲取證書等信息,綁定vip直接走本地,獲取失敗。而此時slb健康檢查認為k8s-master-leader是可以負載的,所以直接訪問前端slb會負載到k8s-master-leader,可以訪問k8s-apiserver。
那為什么還要為k8s-master-follower綁定vip呢?在每個k8s-master-follower請求slb時有1/3的幾率負載到自身,此時訪問不通。綁定vip后,每個k8s-master-follower訪問slb都是訪問的本機。
總結
第一篇文章講述了只有vip,沒有實際slb設備的模式下,采用keepalived+haproxy實現高可用的方式。本篇講述了依賴雲廠商SLB高可用和負載均衡時安裝k8s。方案一並不完美,通過改良后形成了方案二。當然業內肯定還有很多其他的解決方案,作者才疏學淺,還沒來得及一一拜讀。
完成本篇的同時又接到了一個新的需要:SLB不是以vip形式提供,而是域名。域名SLB當然比IP要強,大部分雲廠商負載均衡肯定不是一台設備,背后都是大規模的集群,會保證SLB服務本身的高可用。這種場景下已經不能通過綁定vip來實現,如何解決呢?敬請期待第三篇。