y0ngb1n

Aben Blog

欢迎来到我的技术小黑屋ヾ(◍°∇°◍)ノ゙
github

Kubernetes 入門到實踐:借助 WireGuard 跨雲搭建 K3s 集群環境

寫在前面#

最近看從《跨雲廠商部署 k3s 集群》這篇文章中找到了又一種可以窮開心的花樣玩法,于是乎就有了這篇文章。剛好最近各大雲服務商搞起了雙 11 活動大促,像騰訊雲又可以幾十塊錢買台三年的小雞玩了。那么問題來了,每個雲服務商只能活動價購買一台,最終我們雲主機就分布在不同雲服務商上,得不到充分地利用,那么有沒有可能將它們整合起來輸出算力呢?當然是可以的啦!那就是利用 WireGuard 组网搭建 Kubernetes 集群。

由於前面提到文章中使用的版本已經過時了,那我就基於現在最新的軟件版本按文章的方式開搞吧。

PS: 搞完回來了,通過自己動手後發現一個硬道理,有事沒事真的要多看軟件的官方文檔或多水下官方的社區(如 GayHub),其實官方已經提供足夠詳細的文檔,社區裡已經有人早過踩過了幾種坑了。想要柳暗花明,就多看官方文檔吧。

環境準備#

軟件版本
Ubuntu20.04
Docker20.10
WireGuardv1.0.20200513
K3sv1.23.14+k3s1

我在騰訊雲、Vultr 上準備了幾台預裝 Ubuntu 20.04 的雲主機,當然可以是任意雲服務商的雲主機,只需具備公網訪問、可以運行 Linux 系統即可。

雲服務商公網 IP配置節點名稱節點角色OS-IMAGEKERNEL-VERSIONCONTAINER-RUNTIME
騰訊雲42.193.XXX.XXX4C4Gk3s-node-01control-plane,masterUbuntu 20.04 LTS5.4.0-96-genericdocker://20.10.13
Vultr45.63.YYY.YYY1C1Gk3s-node-02agent/workerUbuntu 20.04.3 LTS5.4.0-131-genericdocker://20.10.11
Vultr13.22.ZZZ.ZZZ1C1Gk3s-node-03agent/workerUbuntu 20.04.5 LTS5.4.0-122-genericdocker://20.10.12

安裝 Docker#

sudo apt intall docker.io -y

安裝 WireGuard#

需要確保在每個節點上安裝 WireGuard 軟件,在 Ubuntu 20.04 的安裝細節如下:

# 切換 root 權限
sudo -i

# 更新軟件源
apt update

# 安裝 WireGuard 軟件
apt install wireguard resolvconf -y

# 開啟 IPV4 IP 轉發
echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
sysctl -p

在這裡只需要完成 WireGuard 的正確安裝即可,無需配置和啟動,其他事情就可以交給 K3s 完成配置組網,我們要做的是盡情使喚 K3s 幹活,還要它把活幹漂亮。其實 K3s 也早為我們準備好了,只需簡單配置啟動參數即可。

跨雲搭建 K3s 集群#

由於我的雲主機分布在不同的雲服務商,所以不能通過服務商的內網環境互相訪問,這裡需要借助 WireGuard 完成異地組網。由於 K3s 通過 Flannel 已經集成了 WireGuard,所以我們可以通過一些簡單的配置即可輕鬆完成組網。

You need to install WireGuard on every node, both server and agents before attempting to leverage the WireGuard flannel backend option. The wireguard backend will be removed from v1.26 in favor of wireguard-native backend natively from Flannel.

在開始之前建議大家先通讀官方指引,只有搞清楚了來龍去脈,才能撥開迷霧。其中有提及不同版本的 K3s 配置參數有所差異,值得注意的是從 v1.26 開始啟動參數由原先的 flannel-backend: wireguard  變更為  flannel-backend: wireguard-native

我們可以參考上一篇文章《Kubernetes 入門到實踐:搭建 K3s 集群初體驗 》中的部署命令。

安裝 K3s Server#

在啟動每個 Server 時需要額外增加以下啟動參數,便可激活 WireGuard:

-node-external-ip <SERVER_EXTERNAL_IP> --flannel-backend wireguard-native --flannel-external-ip

K3s Server 完整的啟動過程如下:

# 指定 K3s 版本
export INSTALL_K3S_VERSION=v1.23.14+k3s1
# 只安裝不啟動
export INSTALL_K3S_SKIP_START=true
# 為您添加到集群的每個節點設計一個獨特的名稱:https://docs.rancher.cn/docs/k3s/installation/installation-requirements/_index#先決條件
export K3S_NODE_NAME=k3s-node-01
# 獲取節點的公網 IP,或手動設置
export PUBLIC_IP=`curl -sSL https://ipconfig.sh`
##
# 自定義啟動執行命令:
# --docker:啟用 Docker 運行時
# --disable servicelb:(可選)禁用 servicelb
# --disable traefik:(可選)禁用 traefik
# --node-ip $PUBLIC_IP --node-external-ip $PUBLIC_IP:設置節點的公網 IP,節點間使用公網 IP 組網通信
# --flannel-backend wireguard-native --flannel-external-ip:啟用 Flannel CNI 並使用 WireGuard 組網
export INSTALL_K3S_EXEC="--docker --disable servicelb --disable traefik --node-ip $PUBLIC_IP --node-external-ip $PUBLIC_IP --flannel-backend wireguard-native --flannel-external-ip"
# 使用阿里雲鏡像源腳本安裝
curl -sfL https://rancher-mirror.oss-cn-beijing.aliyuncs.com/k3s/k3s-install.sh | INSTALL_K3S_MIRROR=cn sh -
# 手動啟動 K3s 服務,由於上面已配置 INSTALL_K3S_SKIP_START=true
systemctl enable --now k3s
# 查看 K3s 服務狀態
systemctl status k3s
# 查看 metrics-server 運行日誌,方便定位問題
kubectl logs -f  pod/metrics-server-5bb8d5f679-btt96 -n kube-system

安裝 K3s Agent#

在啟動每個 Agent 時需要額外增加以下啟動參數,便可激活 WireGuard:

-node-external-ip <AGENT_EXTERNAL_IP>

K3s Agent 完整的啟動過程如下:

# 基本參數與 Server 啟動參數保持一致
export INSTALL_K3S_VERSION=v1.23.14+k3s1
export INSTALL_K3S_SKIP_START=true
# 只需要配置 Agent 特定的參數即可
export K3S_NODE_NAME=k3s-node-02
export PUBLIC_IP=`curl -sSL https://ipconfig.sh`
export INSTALL_K3S_EXEC="--docker --node-ip $PUBLIC_IP --node-external-ip $PUBLIC_IP"
# 設置了 K3S_URL,它將默認為“agent”。如果未設置 K3S_URL,它將默認為“server”
export K3S_URL=
# 用於將 server 或 agent 加入集群的共享 secret
# 在主節點上獲取:cat /var/lib/rancher/k3s/server/node-token
export K3S_TOKEN=K105a308b09e583fccd1dd3a11745826736d440577d1fafa5d9dbaf5213a7150f5f::server:88e21efdad8965816b1da61e056ac7c4
# 由於我的節點在 Vultr 上,這裡走官方源腳本安裝,中國的主機仍可使用阿里雲鏡像源腳本安裝
# curl -sfL https://rancher-mirror.oss-cn-beijing.aliyuncs.com/k3s/k3s-install.sh | INSTALL_K3S_MIRROR=cn sh -
curl -sfL https://get.k3s.io | sh -
# 手動啟動 K3s 服務,由於上面已配置 INSTALL_K3S_SKIP_START=true
systemctl enable --now k3s-agent
# 查看 K3s 服務狀態
$ systemctl status k3s-agent
 k3s-agent.service - Lightweight Kubernetes
     Loaded: loaded (/etc/systemd/system/k3s-agent.service; enabled; vendor preset: enabled)
     Active: active (running) since Sat 2022-11-19 12:23:59 UTC; 50s ago
       Docs: https://k3s.io
    Process: 707474 ExecStartPre=/bin/sh -xc ! /usr/bin/systemctl is-enabled --quiet nm-cloud-setup.service (code=exited, status=0/SUCCESS)
    Process: 707476 ExecStartPre=/sbin/modprobe br_netfilter (code=exited, status=0/SUCCESS)
    Process: 707477 ExecStartPre=/sbin/modprobe overlay (code=exited, status=0/SUCCESS)
   Main PID: 707478 (k3s-agent)
      Tasks: 14
     Memory: 255.6M
     CGroup: /system.slice/k3s-agent.service
             └─707478 /usr/local/bin/k3s agent

Nov 19 12:23:59 vultr k3s[707478]: I1119 12:23:59.986059  707478 network_policy_controller.go:163] Starting network policy controller
Nov 19 12:24:00 vultr k3s[707478]: I1119 12:24:00.057408  707478 network_policy_controller.go:175] Starting network policy controller full sync goroutine
Nov 19 12:24:00 vultr k3s[707478]: I1119 12:24:00.698216  707478 kube.go:133] Node controller sync successful
Nov 19 12:24:00 vultr k3s[707478]: I1119 12:24:00.702931  707478 kube.go:331] Overriding public ip with '45.63.XXX.XXX' from node annotation 'flannel.alpha.coreos.com/public-ip-overwrite'
Nov 19 12:24:00 vultr k3s[707478]: time="2022-11-19T12:24:00Z" level=info msg="Wrote flannel subnet file to /run/flannel/subnet.env"
Nov 19 12:24:00 vultr k3s[707478]: time="2022-11-19T12:24:00Z" level=info msg="Running flannel backend."
Nov 19 12:24:00 vultr k3s[707478]: I1119 12:24:00.865979  707478 wireguard_network.go:78] Watching for new subnet leases
Nov 19 12:24:00 vultr k3s[707478]: I1119 12:24:00.866258  707478 wireguard_network.go:172] Subnet added: 10.42.0.0/24 via 42.193.XXX.XXX:51820
Nov 19 12:24:00 vultr k3s[707478]: I1119 12:24:00.956299  707478 iptables.go:260] bootstrap done
# 查看集群節點信息,會發現 k3s-node-02 的 INTERNAL-IP 為公網 IP
$ kubectl get nodes -owide
NAME          STATUS   ROLES                  AGE   VERSION         INTERNAL-IP     EXTERNAL-IP      OS-IMAGE             KERNEL-VERSION      CONTAINER-RUNTIME
k3s-node-01   Ready    control-plane,master   19m   v1.23.14+k3s1   10.0.20.12      42.193.XXX.XXX   Ubuntu 20.04 LTS     5.4.0-96-generic    docker://20.10.13
k3s-node-02   Ready    <none>                 14m   v1.23.14+k3s1   45.63.YYY.YYY   45.63.YYY.YYY    Ubuntu 20.04.3 LTS   5.4.0-131-generic   docker://20.10.11

關於 metrics-server 問題#

metrics-server
  無法獲取指標,是由於kubelet-preferred-address-types
值首選是 InternalIP,而雲伺服器的 InternalIP 為內網 IP,不同雲廠商的內網 IP 段不同,無法通訊

問題就是 metrics-server 無法獲取 CPU、內存等利用率核心指標,需要人工干預下配置。在剛發布的新版本 **v1.23.14+k3s1** 中修正了啟用 flannel-external-ip=true 选项后會動態調整 -kubelet-preferred-address-types=ExternalIP,InternalIP,Hostname 地址的優先級順序。

下面將展開說說這個特性的調整對 K3s 集群的影響:

在 v1.23.13+k3s1 版本及更舊的版本#

查看下默認配置:

# 無法獲取 CPU、內存等利用率核心指標
$ kubectl top node
Error from server (ServiceUnavailable): the server is currently unable to handle the request (get nodes.metrics.k8s.io)

$ kubectl top node
NAME          CPU(cores)   CPU%        MEMORY(bytes)   MEMORY%
k3s-node-01   133m         3%          2232Mi          56%
k3s-node-02   <unknown>    <unknown>   <unknown>       <unknown%

$ kubectl describe pod/metrics-server-d76965d8f-t2sll -n kube-system | grep -i types
      --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname

需要修改 metrics-server 的 manifests,使用以下命令在線編輯 metrics-server 的 manifests:

kubectl -n kube-system edit deploy metrics-server

調整以下執行參數後保存退出:

    spec:
      containers:
      - args:
        - --cert-dir=/tmp
        - --secure-port=10250
-       - --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname
+       - --kubelet-preferred-address-types=ExternalIP
        - --kubelet-insecure-tls
        - --kubelet-use-node-status-port
        - --metric-resolution=15s

保存後稍等資源重新調度後,這樣就可以讓 metrics-server 使用公網 IP 來和 node 通信了。重新查看核心指標:

$ kubectl top node
NAME          CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%
k3s-node-01   259m         6%     2269Mi          57%
k3s-node-02   203m         20%    534Mi           54%

$ kubectl top pods -A
NAMESPACE     NAME                                      CPU(cores)   MEMORY(bytes)
default       nginx-85b98978db-659cl                    0m           5Mi
default       nginx-85b98978db-tt2hh                    0m           5Mi
default       nginx-85b98978db-zr47g                    0m           2Mi
kube-system   coredns-d76bd69b-k8949                    4m           15Mi
kube-system   local-path-provisioner-6c79684f77-nc2xn   1m           7Mi
kube-system   metrics-server-d76965d8f-t2sll            6m           25Mi

v1.23.14+k3s1 版本及更新的版本#

  1. Describe pod/metrics-server-, look for ARGS and check those scenarios:-kubelet-preferred-address-types=InternalIP,ExternalIP,Hostnamewhen flannel-external-ip=false
  2. Do same steps just change flannel-external-ip: true and look for-kubelet-preferred-address-types=ExternalIP,InternalIP,Hostnamewhen flannel-external-ip=true

⚠️  注意事項 ⚠️#

(不要問為什麼,你試試)

  • 安全組防火牆需要放行相關端口
    • TCP 6443:K3s Server 端口
    • TCP 10250metrics-server 服務端口,用於 K3s Server 與 Agent 通信收集指標,否則會無法獲取 CPU、內存等利用率核心指標
    • UDP 51820:開啟 flannel-backend: wireguard-native 默認端口,Flannel 後端使用 WireGuard 的端口
    • TCP 30000-32767:K8s NodePort 範圍,方便外網調試
  • 選配啟動參數
    • --tls-san
      • 在 TLS 證書中添加其他主機名或 IP 作為主機備用名稱
      • 即在公網環境下允許通過公網 IP 訪問控制、操作遠程集群
      • 或者部署多個 Server 並使用 LB 進行負責,就需要保留公網地址
    • --disable servicelb
    • --disable traefik
  • 禁用未使用上的組件,節約性能
    • Service Load Balancer
      • K3s  提供了一個名為  Klipper Load Balancer的負載均衡器,它可以使用可用的主機端口。 允許創建  LoadBalancer  類型的  Service,但不包括  LB  的實現。某些  LB  服務需要雲提供商,例如  Amazon EC2。相比之下,K3s service LB使得可以在沒有雲提供商的情況下使用  LB  服務。
      • 要禁用嵌入式 LB,請使用 --disable servicelb 选项啟動每個 Server。
    • Traefik Ingress Controller
      • Traefik 是一個現代的 HTTP 反向代理和負載均衡器。啟動 Server 時,默認情況下會部署 Traefik。Traefik ingress controller 將使用主機上的 80 和 443 端口(即這些端口不能用於 HostPort 或 NodePort)。
      • 要禁用它,請使用 --disable traefik 选项啟動每個 server。

驗證 K3s 跨雲集群及網絡#

驗證跨雲集群#

$ kubectl get nodes -owide
NAME          STATUS   ROLES                  AGE   VERSION         INTERNAL-IP     EXTERNAL-IP      OS-IMAGE             KERNEL-VERSION      CONTAINER-RUNTIME
k3s-node-01   Ready    control-plane,master   69m   v1.23.14+k3s1   10.0.20.12      42.193.XXX.XXX   Ubuntu 20.04 LTS     5.4.0-96-generic    docker://20.10.13
k3s-node-02   Ready    <none>                 63m   v1.23.14+k3s1   45.63.XXX.XXX   45.63.YYY.YYY    Ubuntu 20.04.3 LTS   5.4.0-131-generic   docker://20.10.11
k3s-node-03   Ready    <none>                 16m   v1.23.14+k3s1   13.22.ZZZ.ZZZ   13.22.ZZZ.ZZZ    Ubuntu 20.04.5 LTS   5.4.0-122-generic   docker://20.10.12
$ kubectl create deploy whoami --image=traefik/whoami --replicas=3
deployment.apps/whoami created

$ kubectl get pod -owide
NAME                      READY   STATUS    RESTARTS   AGE   IP          NODE          NOMINATED NODE   READINESS GATES
whoami-84d974bbd6-57bnt   1/1     Running   0          10m   10.42.1.4   k3s-node-02   <none>           <none>
whoami-84d974bbd6-hlhdq   1/1     Running   0          10m   10.42.2.2   k3s-node-03   <none>           <none>
whoami-84d974bbd6-g894t   1/1     Running   0          10m   10.42.0.6   k3s-node-01   <none>           <none>

$ kubectl create deploy nginx --image=nginx --replicas=3
deployment.apps/nginx created

$ kubectl get pod -owide
NAME                      READY   STATUS    RESTARTS   AGE   IP           NODE          NOMINATED NODE   READINESS GATES
whoami-84d974bbd6-hlhdq   1/1     Running   0          82m   10.42.2.2    k3s-node-03   <none>           <none>
whoami-84d974bbd6-g894t   1/1     Running   0          82m   10.42.0.6    k3s-node-01   <none>           <none>
whoami-84d974bbd6-57bnt   1/1     Running   0          82m   10.42.1.4    k3s-node-02   <none>           <none>
nginx-85b98978db-ptvcb    1/1     Running   0          32s   10.42.1.5    k3s-node-02   <none>           <none>
nginx-85b98978db-m2nlm    1/1     Running   0          32s   10.42.2.3    k3s-node-03   <none>           <none>
nginx-85b98978db-fs8gk    1/1     Running   0          32s   10.42.0.17   k3s-node-01   <none>           <none>

驗證跨雲網絡#

通過集群內置的 CoreDNS、Service、Pod 相互間調試網絡,驗證不同節點的網絡是否可達。

開始前先快速創建一個名為 whoami 的 Service:

$ kubectl expose deploy whoami --type LoadBalancer --port 80 --external-ip 42.193.XXX.XXX
service/whoami exposed

$ kubectl get svc -owide
NAME         TYPE           CLUSTER-IP     EXTERNAL-IP      PORT(S)        AGE   SELECTOR
kubernetes   ClusterIP      10.43.0.1      <none>           443/TCP        75m   <none>
whoami       LoadBalancer   10.43.77.192   42.193.XXX.XXX   80:32064/TCP   12s   app=whoami

$ kubectl describe svc whoami
Name:                     whoami
Namespace:                default
Labels:                   app=whoami
Annotations:              <none>
Selector:                 app=whoami
Type:                     LoadBalancer
IP Family Policy:         SingleStack
IP Families:              IPv4
IP:                       10.43.77.192
IPs:                      10.43.77.192
External IPs:             42.193.XXX.XXX
Port:                     <unset>  80/TCP
TargetPort:               80/TCP
NodePort:                 <unset>  32064/TCP
Endpoints:                10.42.0.6:80,10.42.1.4:80,10.42.2.2:80
Session Affinity:         None
External Traffic Policy:  Cluster
Events:                   <none>

那怎麼測試 Service 的負載均衡效果呢?#

因為 Service、Pod 的 IP 地址都是 Kubernetes 集群的內部網段,所以我們需要用 kubectl exec 進入到 Pod 內部(或者 ssh 登錄到集群的任一節點),再通過 curl 等工具來訪問 Service。

得助於集群內置的 CoreDNS,我們可以在集群內部通過域名的方式訪問相應的 Service、Pod:

  • Service 對象的域名完全形式是 “對象。名字空間.svc.cluster.local”,但很多時候也可以省略後面的部分,直接寫 “對象。名字空間” 甚至 “對象” 就足夠了,默認會使用對象所在的名字空間(比如這裡就是 default
    • 比如 whoamiwhoami.default
  • Kubernetes 也為每個 Pod 分配了域名,形式是 “IP 地址。名字空間.pod.cluster.local”,但需要把 IP 地址裡的 . 改成 -
    • 比如 10.42.2.2,它對應的域名就是 10-42-2-2.default.pod

這樣我們就無需再關心 Service、Pod 對象的 IP 地址,只需要知道它的名字,就可以用 DNS 的方式去訪問後端服務了。

通過外網訪問#

$ curl http://42.193.XXX.XXX:32064
Hostname: whoami-84d974bbd6-57bnt
IP: 127.0.0.1
IP: 10.42.1.4
RemoteAddr: 10.42.0.0:42897
GET / HTTP/1.1
Host: 42.193.XXX.XXX:32064
User-Agent: curl/7.68.0
Accept: */*

$ curl http://42.193.XXX.XXX:32064
Hostname: whoami-84d974bbd6-hlhdq
IP: 127.0.0.1
IP: 10.42.2.2
RemoteAddr: 10.42.0.0:3478
GET / HTTP/1.1
Host: 42.193.XXX.XXX:32064
User-Agent: curl/7.68.0
Accept: */*

$ curl http://42.193.XXX.XXX:32064
Hostname: whoami-84d974bbd6-g894t
IP: 127.0.0.1
IP: 10.42.0.6
RemoteAddr: 10.42.0.1:3279
GET / HTTP/1.1
Host: 42.193.XXX.XXX:32064
User-Agent: curl/7.68.0
Accept: */*

通過外網訪問 Service,經過多次請求後,可以發現從主節點 [http://42.193.XXX.XXX:32064](http://42.193.XXX.XXX:32064) 作为访问入口,可以負載到不同節點上的 Pod 並正確響應了。

通過集群各節點訪問 Service CLUSTER-IP#

root@k3s-node-01:~# curl 10.43.77.192:80
Hostname: whoami-84d974bbd6-g894t
IP: 127.0.0.1
IP: 10.42.0.6
RemoteAddr: 10.42.1.5:36010
GET / HTTP/1.1
Host: 10.43.77.192
User-Agent: curl/7.68.0
Accept: */*

root@k3s-node-01:~# curl 10.43.77.192:80
Hostname: whoami-84d974bbd6-57bnt
IP: 127.0.0.1
IP: 10.42.1.4
RemoteAddr: 10.42.0.0:23957
GET / HTTP/1.1
Host: 10.43.77.192
User-Agent: curl/7.68.0
Accept: */*

root@k3s-node-01:~# curl 10.43.77.192:80
Hostname: whoami-84d974bbd6-hlhdq
IP: 127.0.0.1
IP: 10.42.2.2
RemoteAddr: 10.42.0.0:26130
GET / HTTP/1.1
Host: 10.43.77.192
User-Agent: curl/7.68.0
Accept: */*

通過節點間直接訪問 Service,經過多次請求後,也可以正常負載到不同節點上的 Pod 並正確響應了。

從集群內部訪問 Service、Pod#

$ kubectl exec -it nginx-85b98978db-ptvcb -- sh
# curl whoami
Hostname: whoami-84d974bbd6-g894t
IP: 127.0.0.1
IP: 10.42.0.6
RemoteAddr: 10.42.1.5:36010
GET / HTTP/1.1
Host: whoami
User-Agent: curl/7.74.0
Accept: */*

# curl whoami.default
Hostname: whoami-84d974bbd6-57bnt
IP: 127.0.0.1
IP: 10.42.1.4
RemoteAddr: 10.42.1.5:33050
GET / HTTP/1.1
Host: whoami.default
User-Agent: curl/7.74.0
Accept: */*

# curl whoami.default.svc.cluster.local
Hostname: whoami-84d974bbd6-hlhdq
IP: 127.0.0.1
IP: 10.42.2.2
RemoteAddr: 10.42.1.5:57358
GET / HTTP/1.1
Host: whoami.default.svc.cluster.local
User-Agent: curl/7.74.0
Accept: */*

經過多方面的網絡驗證,證明使用 Flannal 集成 WireGuard 的多雲組網環境是可用的,可以放心玩耍了。

參考鏈接#


原文地址:https://y0ngb1n.github.io/a/setup-k3s-cluster-multicloud-with-wireguard.html

如果你覺得內容還算實用,歡迎點讚分享給你的朋友,在此謝過。

如果你想更快的看到後續內容的更新,請戳 “點讚”、“分享”、“喜歡”,這些免費的鼓勵將會影響後續有關內容的更新速度。


載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。