如何使用不同云厂商的服务器搭建 K3S 集群

3273

简介

由于买的国内厂商打折服务器,大部分情况下都无法在同一家厂商买到多台优惠服务器,此时想搭建 K3S 集群就需要走公网,直接通过K3S 的安装方式节点之间无法通信,因此需要使用 WireGuard来组网。

在阅读本篇之前建议你先阅读 WireGuardQuickstart来了解它的概念,这将对接下来配置WireGuard十分重要:

https://www.wireguard.com/quickstart/

本篇以两台服务器为例信息如下:

集群节点类型厂商公网 IP 地址内网 IP 地址操作系统
master腾讯云42.xxx.xxx.60172.17.16.4CentOS Linux 7.9
node-1qingcloud139.xx.xx.4610.190.19.38CentOS Linux 7.9

首先会通过 WireGuard为两台机器创建一块虚拟网卡并指定虚拟 ip 形如:

[root@k3s-master ~]# ifconfig wg0
wg0: flags=209<UP,POINTOPOINT,RUNNING,NOARP>  mtu 1420
        inet 192.168.2.1  netmask 255.255.255.255  destination 192.168.2.1
        unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00  txqueuelen 1000  (UNSPEC)
        RX packets 1764  bytes 441372 (431.0 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 1341  bytes 165156 (161.2 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

最终信息如下:

+---------------------------------------+          +--------------------------------------------+
|                                       |          |                                            |
| Master    腾讯云  公:42.xxx.xxx.60     |          | Node-1    QingCloud    公:139.xx.xx.46     |
|                                       |          |                                            |
| 内:172.17.16.4    虚拟Ip: 192.168.2.1 |          | 内:10.190.19.38        虚拟IP: 192.168.2.2 |
|                                       |          |                                            |
+---------------------------------------+          +--------------------------------------------+

安装WireGuard

在搭建跨云的 k3s 集群前,需要先把 WireGuard 安装好,WireGuard 对内核有要求,要升级到 5.15.2-1.el7.elrepo.x86_64以上

分别在Master(表示腾讯云的服务器在集群中作为master节点使用)和Node-1(表示QingCloud的服务器在集群中作为工作节点使用)执行如下命令以开启 IP 地址转发:

echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf

echo "net.ipv4.conf.all.proxy_arp = 1" >> /etc/sysctl.conf

sysctl -p /etc/sysctl.conf

对两台服务器修改主机名称

# 腾讯云执行
hostnamectl  set-hostname k3s-master
# QingCloud执行
hostnamectl  set-hostname k3s-node-1

修改 iptables 以允许NAT

对两台服务器都进行如下设置,添加 iptables 规则,允许本机的 NAT 转换,执行前需要将如下的192.168.1.1/24修改为在简介中决定设定的虚拟ip:

iptables -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
iptables -A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
iptables -A FORWARD -i wg0 -o wg0 -m conntrack --ctstate NEW -j ACCEPT
iptables -t nat -A POSTROUTING -s 192.168.1.1/24 -o eth0 -j MASQUERADE

释意:

wg0: 为虚拟网卡名称,两台服务器可以都叫wg0

192.168.1.1: 为虚拟 IP 地址段, Master设置为192.168.2.1, Node-1改为192.168.2.2

eth0: 为服务器的物理网卡

升级内核

配置好 iptables 只有升级内核以安装WireGuard,否则安装WireGuard时会出现如下错误:

[#] ip link add wg0 type wireguard
RTNETLINK answers: Operation not supported
Unable to access interface: Protocol not supported
[#] ip link delete dev wg0
Cannot find device "wg0"

在所有节点都执行如下操作:

  1. 载入公钥
rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org
  1. 升级安装 elrepo
rpm -Uvh http://www.elrepo.org/elrepo-release-7.0-5.el7.elrepo.noarch.rpm
  1. 载入 elrepo-kernel元数据
yum --disablerepo=\* --enablerepo=elrepo-kernel repolist
  1. 安装最新版本的内核
yum --disablerepo=\* --enablerepo=elrepo-kernel install  kernel-ml.x86_64  -y
  1. 删除旧版本工具包
yum remove kernel-tools-libs.x86_64 kernel-tools.x86_64  -y
  1. 然后修改默认内核版本,首先查看当前实际启动顺序
grub2-editenv list
  1. 查看内核插入顺序
grep "^menuentry" /boot/grub2/grub.cfg | cut -d "'" -f2
  1. 设置默认启动, 将CentOS Linux (5.15.2-1.el7.elrepo.x86_64) 7 (Core)改为步骤6中列出的最新内核信息
grub2-set-default 'CentOS Linux (5.15.2-1.el7.elrepo.x86_64) 7 (Core)'
  1. 重新创建内核配置
grub2-mkconfig -o /boot/grub2/grub.cfg
  1. 重启服务器
reboot
  1. 验证当前内核版本
uname -r

安装WireGuard

在两台服务器都需要执行如下操作,安装流程非常简单,CentOS 内核更新到 5.15.2以上版本后,其中就已经包含了 WireGuard 的内核模块,只需要安装 wireguard-tools 包即可

yum install epel-release https://www.elrepo.org/elrepo-release-7.el7.elrepo.noarch.rpm
yum install yum-plugin-elrepo kmod-wireguard wireguard-tools -y

配置 WireGuard

wireguard-tools 包提供了我们所需的工具 wgwg-quick,可以使用它们来分别完成手动部署和自动部署。

先按照官方文档描述的形式,生成Master节点和Node-1节点服务器 用于加密解密的密钥

在Master节点操作

wg genkey | tee privatekey | wg pubkey > publickey

然后在当前目录下就生成了 privatekeypublickey 两个文件

注意:

密钥是配置到本机的,而公钥是配置到其它机器里的,结果示例如下:

cat privatekey publickey
EMWcI01iqM4zkb7xfbaaxxxxxxxxDo2GJUA=
0ay8WfGOIHndWklSIVBqrsp5LDWxxxxxxxxxxxxxxQ=

然后编写配置文件,以供 wg-quick 使用

vim /etc/wireguard/wg0.conf

然后写入如下内容

[Interface]
PrivateKey = EMWcI01iqM4zkb7xfbaaxxxxxxxxDo2GJUA=
Address = 192.168.2.1
ListenPort = 5418

[Peer]
PublicKey = Node-1服务器的 publickey后续Node-1生成后再改
EndPoint = 139.xx.xx.46:5418
AllowedIPs = 192.168.2.2/32

在Node-1节点操作

wg genkey | tee privatekey | wg pubkey > publickey

查看结果

[root@k3s-node-1 ~] cat privatekey publickey
QGl72V7FyFokmF15cPGLcLWkOOBV+CHw6KWL+MtUj2o=
b/yQJHLEo1NisJcE3eBewjX+wFBDROQ3njGRQhZpADQ=

然后编写配置文件,以供 wg-quick 使用

vim /etc/wireguard/wg0.conf

然后写入如下内容

[Interface]
PrivateKey = QGl72V7FyFokmF15cPGLcLWkOOBV+CHw6KWL+MtUj2o=
Address = 192.168.2.2
ListenPort = 5418

[Peer]
# PublicKey为Master机器的
PublicKey = 0ay8WfGOIHndWklSIVBqrsp5LDWxxxxxxxxxxxxxxQ=
EndPoint = 42.xxx.xxx.60:5418
AllowedIPs = 192.168.2.1/32

然后到Master机器使用vim /etc/wireguard/wg0.conf编辑Peer下的PublicKeyNode-1PublicKey

开放端口

到云厂商的防火墙(安全组)规则配置处开放 5418 端口,下行规则,协议为UDP

配置说明

Interface: 小节是属于本机的配置.

Address: 是分配给本机在简介部分约定的虚拟 IP,

ListenPort: 是主机之间通讯使用的端口,是 UDP 协议的。

Peer: 是属于需要通信的服务器的信息,有多少需要通信的主机,就添加多少个 Peer 小节,更多内容参阅WireGuard官网配置。

EndPoint: 由于这里是跨厂商所以这里的EndPoint为服务器的公网 IP 与 WireGuard 监听的 UDP 端口,如果你的机器通过内网也能通信,直接用内网 IP 也可以,当然要注意这个 IP 需要所有加入该局域网的主机都能通信才行。

AllowedIPs: 是指本机发起连接的哪些 IP 应该将流量转发到这个节点,比如给主机 B 分配了内网 IP 192.168.1.2,那么在主机 A 上发送到 192.168.1.2 的数据包,都应该转发到这个 EndPoint 上,它其实起的是一个过滤作用。而且多个 Peer 时,这里配置的 IP 地址不能有冲突。

各个节点生产的 privatekey 和 publickey 分别如下

各个节点配置文件如下:

在Master 节点cat /etc/wireguard/wg0.conf:

[Interface]
PrivateKey = EMWcI01iqM4zkb7xfbaaxxxxxxxxDo2GJUA=
Address = 192.168.2.1
ListenPort = 5418

[Peer]
PublicKey = b/yQJHLEo1NisJcE3eBewjX+wFBDROQ3njGRQhZpADQ=
EndPoint = 139.xx.xx.46:5418
AllowedIPs = 192.168.2.2/32

在Node-1节点cat /etc/wireguard/wg0.conf:

[Interface]
PrivateKey = QGl72V7FyFokmF15cPGLcLWkOOBV+CHw6KWL+MtUj2o=
Address = 192.168.2.2
ListenPort = 5418

[Peer]
PublicKey = 0ay8WfGOIHndWklSIVBqrsp5LDWxxxxxxxxxxxxxxQ=
EndPoint = 42.xxx.xxx.60:5418
AllowedIPs = 192.168.2.1/32

启动 WireGuard

边写好配置文件后,对所有节点执行 wg-quick 工具来创建虚拟网卡

wg-quick up wg0

上面命令中的 wg0 对应的是 /etc/wireguard/wg0.conf 这个配置文件,其自动创建的网卡设备,名字就是 wg0

创建好虚拟网卡后测试是否连通

例如在 Master 节点ping Node-1的虚拟ip要能 ping 通否则请检查配置是否正确

[root@k3s-master ~]# ping 139.xx.xx.46
PING 139.xx.xx.46 (139.xx.xx.46) 56(84) bytes of data.
64 bytes from 139.xx.xx.46: icmp_seq=1 ttl=50 time=48.8 ms
64 bytes from 139.xx.xx.46: icmp_seq=2 ttl=50 time=45.1 ms
^C
--- 139.xx.xx.46 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1000ms
rtt min/avg/max/mdev = 45.119/47.008/48.897/1.889 ms

在Node-1上ping Master亦如是

然后就可以使用 wg 命令来查看通信情况

[root@k3s-master ~]# wg
interface: wg0
  public key: 0ay8WfGOIHndWklSIVBqrsp5LDWxxxxxxxxxxxxxxQ=
  private key: (hidden)
  listening port: 5418

peer: 0f0dn60+tBUfYgzw7rIihKbqxxxxxxxxa6Wo=
  endpoint: 122.xx.xx.155:5418
  allowed ips: 192.168.1.3/32
  latest handshake: 3 minutes, 3 seconds ago
  transfer: 35.40 KiB received, 47.46 KiB sent

自动化配置

系统重启后,WireGuard 创建的网卡设备就会丢失,WireGuard提供了自动化的脚本来解决这件事,在两台服务器都执行如下操作

systemctl enable wg-quick@wg0

使用上述命令生成 systemd 守护脚本,开机会自动运行 up 指令。

配置热重载

wg-quick 并未提供重载相关的指令,但是提供了 strip 指令,可以将 conf 文件转换为 wg 指令可以识别的格式。

wg syncconf wg0 <(wg-quick strip wg0)

即可实现热重载。

完成 WireGuard 的安装配置以后,接下来就可以安装 k3s 的集群了。

安装 K3S 集群

Master 节点安装

export MASTER_EXTERNAL_IP=42.xx.xx.60
export MASTER_VIRTUAL_IP=192.168.2.1

安装 K3S

curl -sfL http://rancher-mirror.cnrancher.com/k3s/k3s-install.sh | INSTALL_K3S_MIRROR=cn sh  -s -  --node-external-ip $MASTER_EXTERNAL_IP --advertise-address $MASTER_EXTERNAL_IP --node-ip $MASTER_VIRTUAL_IP --flannel-iface wg0

参数说明:

  • --node-external-ip: 42.xx.xx.60 设置为当前节点的外部 IP
  • --advertise-address: 42.xx.xx.12 用于设置 kubectl 工具以及子节点进行通讯使用的地址,可以是 IP,也可以是域名,在创建 apiserver 证书时会将此设置到有效域中。
  • --node-ip: 10.20.30.1 上文中约定的的虚拟ip
  • --flannel-iface wg0 wg0 是 WireGuard 创建的网卡设备,我需要使用虚拟局域网来进行节点间的通信,所以这里需要指定为 wg0。

由于 WireGuard 的所有流量都是加密传输的,通过它来进行节点间的通信,就已经能够保证通信安全,也就没有必要改用其它的 CNI 驱动,使用默认的就可以了。

在主节点执行上述命令后,一分钟不到就可以看到脚本提示安装完成。通过命令查看下主控端的运行情况

systemctl status k3s

如果运行正常,那么就看看容器的运行状态是否正常

kubectl get pods -A

-A 参数用于查看所有命名空间,如果容器都处于 running 状态,那么安装就成功了,接下来要可以添加被控节点。

Agent 安装

有了上述安装主控的经验,安装 work 节点更加简单,参数需要一定的调整

在Node-1节点 执行

export MASTER_VIRTUAL_IP=192.168.2.1
export NODE_EXTERNAL_IP=139.xx.xx.46
export NODE_VIRTUAL_IP=192.168.2.2
export K3S_TOKEN=K1031c4c705056a0752a09801e99b56cf0f89571b4d678a138a44deb49a0e1d9722::server:5d89600a5330100489c4c3dbcce1dec0

K3S_TOKEN 的值改为在Master节点执行/var/lib/rancher/k3s/server/node-token后得到的值

NODE_EXTERNAL_IP设置为Node-1的公网ip

安装

curl -sfL http://rancher-mirror.cnrancher.com/k3s/k3s-install.sh | INSTALL_K3S_MIRROR=cn K3S_URL=https://$MASTER_VIRTUAL_IP:6443 K3S_TOKEN=$K3S_TOKEN sh -s - --node-external-ip $NODE_EXTERNAL_IP --node-ip $NODE_VIRTUAL_IP --flannel-iface wg0

执行后稍等一会,安装成功后,照例查看服务运行状态

systemctl status k3s-agent

都安装好以后 在 Master 节点检查,可以看到两个节点

kubectl get nodes -o wide 

至此 多云 K3S 集群已经搭建完毕。

参考文档:

[1] cnsre运维博客之搭建 K3S 集群

[2] WireGuard官方文档

[3] Network Address Translation

[4] K3S

[5] struct-net-device