写在前面最近看从《跨云厂商部署 k3s 集群 》这篇文章中找到了又一种可以穷开心的花样玩法,于是乎就有了这篇文章。刚好最近各大云服务商搞起了双 11 活动大促,像腾讯云又可以几十块钱买台三年的小鸡玩了。那么问题来了,每个云服务商只能活动价购买一台,最终我们云主机就分布在不同云服务商上,得不到充分地利用,那么有没有可能将它们整合起来输出算力呢?当然是可以的啦!那就是利用 WireGuard 组网搭建 Kubernetes 集群。
由于前面提到文章中使用的版本已经过时了,那我就基于现在最新的软件版本按文章的方式开搞吧。
PS: 搞完回来了,通过自己动手后发现一个硬道理,有事没事真的要多看软件的官方文档或多水下官方的社区(如 GayHub),其实官方已经提供足够详细的文档,社区里已经有人早过踩过了几种坑了。想要柳暗花明,就多看官方文档吧。
环境准备软件 版本 Ubuntu 20.04 Docker 20.10 WireGuard v1.0.20200513 K3s v1.23.14+k3s1
我在腾讯云、Vultr 上准备了几台预装 Ubuntu 20.04
的云主机,当然可以是任意云服务商的云主机,只需具备公网访问、可以运行 Linux 系统即可。
云服务商 公网 IP 配置 节点名称 节点角色 OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME 腾讯云 42.193.XXX.XXX 4C4G k3s-node-01 control-plane,master Ubuntu 20.04 LTS 5.4.0-96-generic docker://20.10.13 Vultr 45.63.YYY.YYY 1C1G k3s-node-02 agent/worker Ubuntu 20.04.3 LTS 5.4.0-131-generic docker://20.10.11 Vultr 13.22.ZZZ.ZZZ 1C1G k3s-node-03 agent/worker Ubuntu 20.04.5 LTS 5.4.0-122-generic docker://20.10.12
安装 Dockersudo apt intall docker.io -y
安装 WireGuard需要确保在每个节点上安装 WireGuard 软件,在 Ubuntu 20.04
的安装细节如下:
sudo -i apt update apt install wireguard resolvconf -y echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.confsysctl -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 完整的启动过程如下:
export INSTALL_K3S_VERSION=v1.23.14+k3s1export INSTALL_K3S_SKIP_START=true export K3S_NODE_NAME=k3s-node-01export PUBLIC_IP=`curl -sSL https://ipconfig.sh`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 - systemctl enable --now k3s systemctl status k3s
kubectl logs -f pod/metrics-server-5bb8d5f679-btt96 -n kube-system
安装 K3s Agent在启动每个 Agent 时需要额外增加以下启动参数,便可激活 WireGuard:
-node-external-ip <AGENT_EXTERNAL_IP>
K3s Agent 完整的启动过程如下:
export INSTALL_K3S_VERSION=v1.23.14+k3s1export INSTALL_K3S_SKIP_START=true export K3S_NODE_NAME=k3s-node-02export PUBLIC_IP=`curl -sSL https://ipconfig.sh`export INSTALL_K3S_EXEC="--docker --node-ip $PUBLIC_IP --node-external-ip $PUBLIC_IP " export K3S_URL=export K3S_TOKEN=K105a308b09e583fccd1dd3a11745826736d440577d1fafa5d9dbaf5213a7150f5f::server:88e21efdad8965816b1da61e056ac7c4curl -sfL https://get.k3s.io | sh - systemctl enable --now k3s-agent
$ 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
$ 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 版本及更旧的版本 查看下默认配置:
$ 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
Describe pod/metrics-server-
, look for ARGS and check those scenarios:-kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname
when flannel-external-ip=false
Do same steps just change flannel-external-ip: true
and look for-kubelet-preferred-address-types=ExternalIP,InternalIP,Hostname
when flannel-external-ip=true
⚠️ 注意事项 ⚠️(不要问为什么,你试试)
安全组防火墙需要放行相关端口 TCP 6443
:K3s Server 端口TCP 10250
:metrics-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
)比如 whoami
、whoami.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:~ Hostname: whoami-84d974bbd6-g894t IP: 127.0.0.1 IP: 10.42.0.6 RemoteAddr: 10.42.0.1:22291 GET / HTTP/1.1 Host: 10.43.77.192 User-Agent: curl/7.68.0 Accept: */* root@k3s-node-01:~ 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:~ 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 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: */* 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: */* 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
如果你觉得内容还算实用,欢迎点赞分享给你的朋友,在此谢过。
如果你想更快的看到后续内容的更新,请戳 “点赞 ”、“分享 ”、“喜欢 ”,这些免费的鼓励将会影响后续有关内容的更新速度。