開場
kubernetes本身架構屬於主從模式(Master/Slave),本篇是第一篇筆記,所以在此先分享並順便紀錄一下,kubernetes裡主從節點如何分工。
Kubernetes中主從節點的功能以及元件
Master Node (Control Plane)
此節點類型為kubernetes集群的大腦,負責容器的調度以及資源的管理,節點內包含以下元件
- kube-apiserver
提供API介面,用於當作集群中各個節點的溝通橋樑,以及接收來自使用者使用API呼叫或者kubectl工具下達的命令,是集群中的關鍵應用,若此元件故障,將導致整個集群無法操作
每個 Node 之間的溝通一定要透過此元件,彼此之間無法直接互相溝通
- etcd
CNCF畢業的專案之一,負責存放整個存放整個集群的狀態及資料的資料庫,也是當集群故障時恢復集群最重要的關鍵
- kube-scheduler
負責集群的資源調配,未指定運行節點的容器將被此元件協調後指派至最符合的Worker Node運行
- kube-controller-manager
負責管理並運行各類kubernetes controller的元件,例如Node Controller、Replication Controller或ServiceAccounts Controller
此元件的操作也都需要仰賴kube-apiserver,必須通過kube-apiserver完成
Worker Node
此節點類型為kubernetes集群的四肢,負責執行容器負載,節點內包含以下元件
- kubelet
Worker Node的管理進程,負責管理此節點上所有Pods的狀態並負責與Master Node溝通
- kube-proxy
負責更新此Woker Node上的iptables,以反映Master Node上service與endpoint的設定,使得流量得以與Pod溝通
- Container Runtime
負責容器的執行,使用符合container runtime interface(CRI)的引擎來執行容器,例如Docker Engine、Containerd以及CRI-O
在此架構上kubernetes集群會有至少一個Master Node(Control Plane)負責容器的調度以及資源的管理,以及至少一個Worker Node負責執行容器負載。
在上述的介紹中,有提到Master Node裡的kube-apiserver元件對整個kubernetes集群至關重要。若集群內只有一個Master Node,那在此Master Node故障時,將失去對整個kubernetes集群的控制,所以希望在集群中有多個Master Node做備援,避免Master Node成為SPOF。
但若集群裡有多個Master Node時,就會需要設定Load Balancer做為單一入口來將控制流量分配到各個Master Node上,並且為了避免Load Balancer本身成為SPOF,此Load Balancer本身也必須處於高可用的狀態。
此篇筆記主要是關於HAProxy與KeepAlived這兩個套件的設定,這兩個套件可以互相搭配來搭建出一套高可用的Load Balancer,並且此套方案已經行之有年,已經可被視為非常成熟可靠的方案。
HAProxy與KeepAlived負責的就是整體架構圖中HA LoadBalancer的部分,完整架構圖請參考Kubernetes學習筆記(一) - 起點
介紹與實作
【提醒】架構圖、機器IP列表以及作業系統資訊請參考Kubernetes學習筆記(一) - 起點,本系列一律使用Ubuntu來實作練習
此次示範的HAProxy與KeepAlived版本為
- HA-Proxy version 2.0.13-2ubuntu0.3 2021/08/27
- Keepalived v2.0.19 (10/19,2019)
HAProxy是一個使用C語言編寫的開源軟體,可提供高可用性的負載均衡器功能,以及基於TCP和HTTP的應用程式反向代理功能。
與Nginx一樣,也分為社群版以及企業版,企業版基本上就是多了24*7支援、內建VRRP(等等KeepAlived的部分會講)與RHI(Route Health Injection)等等功能,詳細比較可參考官方網站比較表。基本上社群版已經涵蓋了非常完整的核心功能,這次實作練習完全夠用。
這次會使用HAProxy作為多個Master Node的應用程式反向代理,並且分別在兩台伺服器上,k8s-lb-1與k8s-lb-2,配置一模一樣的HAProxy服務來配合待會要介紹的KeepAlived做高可用備援設定使用。
安裝
sudo apt-get install haproxy -y
|
於終端使用上述指令即可安裝HAProxy
設定
在kubernetes集群中,kube-apiserver預設監聽的端口為6443。
我們需要設定HAProxy監聽6443端口,並將接收到的流量導向我們集群中的多個Master Node的6443端口上,也就是k8s-master-1、k8s-master-2以及k8s-master-3這三台機器上的6443端口。這麼一來當有Master Node故障時,HAProxy可用Master Node上的Health Check Entry未有回應來判斷並自動跳過故障的節點不代理,待節點恢復後才會繼續代理流量。
HAProxy的設定檔的路徑於/etc/haproxy/haproxy.cfg,我們先在k8s-lb-1上編輯此設定檔
以我的環境為例,打開後原設定檔長相如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| global log /dev/log local0 log /dev/log local1 notice chroot /var/lib/haproxy stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners stats timeout 30s user haproxy group haproxy daemon
# Default SSL material locations ca-base /etc/ssl/certs crt-base /etc/ssl/private
# See: https://ssl-config.mozilla.org/#server=haproxy&server-version=2.0.3&config=intermediate ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384 ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256 ssl-default-bind-options ssl-min-ver TLSv1.2 no-tls-tickets
defaults log global mode http option httplog option dontlognull timeout connect 5000 timeout client 50000 timeout server 50000 errorfile 400 /etc/haproxy/errors/400.http errorfile 403 /etc/haproxy/errors/403.http errorfile 408 /etc/haproxy/errors/408.http errorfile 500 /etc/haproxy/errors/500.http errorfile 502 /etc/haproxy/errors/502.http errorfile 503 /etc/haproxy/errors/503.http errorfile 504 /etc/haproxy/errors/504.http
|
我們需要在設定檔最後加入應用程式代理設定,加入以下設定並以你自身情況自行修改
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| # 全域設定區塊 global log /dev/log local0 log /dev/log local1 notice chroot /var/lib/haproxy stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners stats timeout 30s user haproxy group haproxy daemon
# Default SSL material locations ca-base /etc/ssl/certs crt-base /etc/ssl/private
# See: https://ssl-config.mozilla.org/#server=haproxy&server-version=2.0.3&config=intermediate ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384 ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256 ssl-default-bind-options ssl-min-ver TLSv1.2 no-tls-tickets
# 若設定區塊沒有指定以下設定,則自動套用以下設定 defaults log global mode http option httplog option dontlognull timeout connect 5000 timeout client 50000 timeout server 50000 errorfile 400 /etc/haproxy/errors/400.http errorfile 403 /etc/haproxy/errors/403.http errorfile 408 /etc/haproxy/errors/408.http errorfile 500 /etc/haproxy/errors/500.http errorfile 502 /etc/haproxy/errors/502.http errorfile 503 /etc/haproxy/errors/503.http errorfile 504 /etc/haproxy/errors/504.http
#--------------------------------------------------------------------- # 設定代理入口所使用的監聽端口、代理模式以及配對的後端應用程式代理設定 #--------------------------------------------------------------------- frontend apiserver # 代理入口設定區塊,名為 apiserver bind *:6443 # 監聽此機器上的 6443 端口當作代理入口 mode tcp # 使用 TCP Layer 4 代理模式 option tcplog # 紀錄 TCP 連接的 Log default_backend apiserver # 指定後端應用程式代理設定使用名為 apiserver 的設定區塊
#--------------------------------------------------------------------- # 設定後端應用程式代理,以RR循環的方式將請求分配到後端的Master Node上 #--------------------------------------------------------------------- backend apiserver # 後端應用程式代理設定區塊,名為apiserver mode tcp # 使用 TCP Layer 4 代理模式 option tcplog # 紀錄 TCP 連接的 Log option ssl-hello-chk # 傳送SSLv3 Hello封包測試SSL連線是否正常 balance roundrobin # 使用 Round Robin 循環的方式分配流量到以下後端清單 # server ${HOST_ID} ${HOST_ADDRESS}:${APISERVER_SRC_PORT} check -- 代理送往的執行個體IP與端口,最後的 check 表示啟用 TCP health check 功能,以自動剔除故障流量 server k8s-master-1 10.0.254.250:6443 check # 換成你練習或正式環境的 Master Node 主機資訊 server k8s-master-2 10.0.254.249:6443 check # 換成你練習或正式環境的 Master Node 主機資訊 server k8s-master-3 10.0.254.248:6443 check # 換成你練習或正式環境的 Master Node 主機資訊
|
再來重啟HAProxy並設定自動啟動
sudo systemctl restart haproxy
|
於終端使用上述指令來重啟HAProxy使設定生效
sudo systemctl enable haproxy
|
於終端使用上述指令來讓HAProxy於開機時自動執行
完成上述動作後,我們可以使用以下指令來檢查HAProxy是否有正確的啟動並監聽在指定的端口上
IP帶入你Load Balancer的IP,端口這邊帶入我們先前設定的6443,成功會顯示succeeded,失敗則顯示failed: Connection refused
圖例:
成功
失敗
當然也可以在裝有HAProxy的主機上使用以上指令來列出系統上所有正在占用監聽的端口,以檢查是否有6443出現
圖例:
同樣在k8s-lb-2主機上建置一模一樣的設定檔,我們就會得到兩台一樣功能與設定的Load Balancer,接下來再配合KeepAlived套件即可實現HAProxy的備援並完成本篇筆記目標。
有了兩台一樣的HAProxy後,接下來就是要解決如何在一台HAProxy故障時,如何使請求自動切換到另外一台好的HAProxy,且使用的IP又不需要特別更換。
KeepAlived是一個基於VRRP(Virtual Router Redundancy Protocol)協議來實現的服務高可用方案,使用C語言編寫的開源軟體,其套件會在多台設定KeepAlived的機器間以權重為依據來推選出一台MASTER,並賦予其MASTER一組Virtual IP。當MASTER不幸當機或Health Check腳本檢查未通過時,其機器上的權重就會因此減少(以Priority值為基準)。當MASTER不再是權重最高者,多台設定KeepAlived的機器間就會重新再選出一台MASTER並賦予同樣的Virtual IP,以達到服務熱備切換的目的,故權重的配置設定正確與否非常重要,配錯的話將導致無法正常進行主從切換,或造成網路上有多個MASTER存在(稱為Split Brain)。
附記,當主備切換時,KeepAlived會傳送GARP(稱為無故ARP或免費ARP)來刷新ARP快取,以將流量正確導向新的MASTER
有了KeepAlived配合HAProxy,就可以讓KeepAlived提供一組虛擬IP,並在兩台HAProxy之間熱備切換,完成高可用性的建置。
安裝
sudo apt-get install keepalived -y
|
於終端使用上述指令即可安裝KeepAlived
設定
KeepAlived的設定檔的存於/etc/keepalived/內,初始資料夾內全空狀態,需要自己創建設定檔。
我們先在k8s-lb-1上編輯此設定檔,創建並編輯/etc/keepalived/keepalived.conf檔案,加入以下設定並以你自身情況自行修改
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| # Health Check 腳本設定 vrrp_script chk_haproxy { # 新增一個腳本設定區塊,名為chk_haproxy script "killall -0 haproxy" # 要執行的腳本,可以是sh檔也可以是指令,此處使用killall傳送signal 0來確定進程是否存在,存在將回傳0,不存在則回傳1 interval 2 # 檢測的時間間格,單位為秒 weight 2 # 此腳本作動時的權重值,分為以下情況 # 當 weight > 0 # 腳本回傳值為0時,優先級為 priority + abs(weight),優先級會增加 # 腳本回傳值非0時,優先級不變 # 當 weight < 0 # 腳本回傳值為0時,優先級不變 # 腳本回傳值非0時,優先級為 priority - abs(weight),優先級會減少 } vrrp_instance haproxy-vip { # 新增一個 VRRP 執行個體設定區塊,名為 haproxy-vip state MASTER # 初始狀態,若為 MASTER 則為啟用中的伺服器,BACKUP 則為備援伺服器,但實際是誰為 MASTER 主要還是要看權重 priority 101 # 此伺服器的初始優先級, MASTER 的優先級應該要比 BACKUP 還要高,範圍為0~255 interface ens160 # 作用的網路介面卡,可使用 ip add 或 ifconfig 工具查看 virtual_router_id 60 # 識別編號,同一組 KeepAlived 中所有主備伺服器的編號應設定一致 advert_int 1 # 主備伺服器同步檢查間隔,單位為秒 authentication { # 驗證設定,可防止未經授權加入 auth_type PASS auth_pass k8s-lb@lab # 密碼 } unicast_src_ip 10.0.254.252 # 單播通告的來源IP,設定為此台伺服器的IP即可 unicast_peer { # 同儕IP,也就是同群組內的其他主備援伺服器IP地址 10.0.254.251 # k8s-lb-2 的IP地址,請視自身情況修改 } virtual_ipaddress { # KeepAlived 使用的 Virtual IP 地址,請視自身情況修改 10.0.254.253/16 # 這裡我使用之前規劃好,預留的 Virtual IP 地址,請填寫 CIDR 格式 } track_script { # 設定此 VRRP 個體要執行的 Health Check 腳本,可編寫多個腳本在Priority基準上加減 chk_haproxy } }
|
附記,可以使用 sudo killall -0 haproxy;echo $? 命令來觀察killall的回傳值,其中$?為linux的特殊變量,可印出上個執行命令的返回值
關於vrrp_script,官方文檔中也有提出一個基於HTTP Entry來檢測HAProxy服務狀態的腳本,這裡順便紀錄一下,可以參考,這次直接使用進程狀態判斷
1 2 3 4 5 6 7 8 9 10 11
| #!/bin/sh
errorExit() { echo "*** $*" 1>&2 exit 1 }
curl --silent --max-time 2 --insecure https://localhost:${APISERVER_DEST_PORT}/ -o /dev/null || errorExit "Error GET https://localhost:${APISERVER_DEST_PORT}/" if ip addr | grep -q ${APISERVER_VIP}; then curl --silent --max-time 2 --insecure https://${APISERVER_VIP}:${APISERVER_DEST_PORT}/ -o /dev/null || errorExit "Error GET https://${APISERVER_VIP}:${APISERVER_DEST_PORT}/" fi
|
再來重啟KeepAlived並設定自動啟動
sudo systemctl restart keepalived
|
於終端使用上述指令來重啟KeepAlived使設定生效
sudo systemctl enable keepalived
|
於終端使用上述指令來讓KeepAlived於開機時自動執行
接著,在另一台Load Balancer的主機上,也就是k8s-lb-2,用上面的設定檔做適當的修改並配置KeepAlived,就可以來驗證我們部屬的成果了。
驗證
一開始倘若HAProxy與KeepAlived服務皆正常,就可以觀察到k8s-lb-1的網路介面多了一組IP,也就是上面設定的Virtual IP
接著,我們將k8s-lb-1上的HAProxy服務停止,可以觀察到一段時間後,因為服務停止造成權重低於k8s-lb-2,Virtual IP就消失在k8s-lb-1主機上,轉而跑到k8s-lb-2的網路介面上了
總結
到此我們就成功部屬了一套高可用的Load Balancer,並且有個單一入口可用來將控制流量分配到集群內的多個Master Node上,避免單點故障而失去對集群的控制,下一篇筆記我們就會來正式創建並設定高可用的kubernetes集群。