使用本地机器和VPS搭建K3s集群

几年前学着用Docker的时候,很多人把Docker和Kubernetes放在一起说,当时想自己搭建一个K8s服务体验一下,后来发现我当时的需求只用Docker就差不多了,K8s这种复杂的东西根本用不到,就放下不管了。(Kubernetes简写为K8s,下同)

之后听说了K3s,说是简化版的K8s(怎么说,十个字母简化成了五个字母?),但也还是用不到。直到最近我开始整理自己所有的机器上正在跑的服务,发现这些个服务真是太乱了啊,用我土制的启动和管理方法跑在好几个没什么关系的VPS上,实在不像是2022年该有的样子。回学校之后又经常会有创建Docker容器用于测试的需求,于是尝试用VPS和放在学校实验室的电脑、树莓派搭建一个K8s的集群。

一些介绍

K8s和K3s

上面提到的关于K8s和K3s关系的内容只是玩笑,但也不是完全不对,根据K3s的发行商Rancher的介绍,K3s是一个轻量级的Kubernetes发行版,他们希望K3s在内存占用方面只是K8s一半的大小,有Kubernetes一半大的东西就是一个5个字母的单词,简写为K3s。K3s没有全称,也没有官方的发音。

K3s针对边缘计算、物联网等场景进行了高度优化,具有以下增强功能:

  • 打包为单个二进制文件,封装在简单的启动程序中。
  • 使用基于sqlite3的轻量级存储后端作为默认存储机制。
  • 对轻量级环境有合理的默认值,并且在默认情况下安全。
  • 添加了简单但功能强大的内置功能。
  • 最大程度减轻了外部依赖性。

因为K3s所需的资源相对较少,所以比较适合边缘计算、物联网、开发、测试等场景,既可以单机运行,也可以配合其他节点。因为其对ARM架构设备的良好支持,在树莓派上也可以运行K3s节点。

K8s基本知识

注意:以下内容(直至本文末尾)基于我在阅读K8s文档和实际操作K8s集群时的个人理解撰写而成,由于我对相关知识的不熟悉,有可能出现错误,请酌情参考,欢迎通过各种方式指出其中错误。

K8s是用于管理容器的工具,可以提供服务扩展、负载均衡、自动部署和回滚、自我修复等功能。

一个K8s集群由一些作为节点的机器组成,这些节点上运行K8s所管理的容器化应用。节点分为多种,其中工作节点托管作为应用负载的Pod,控制平面节点管理集群中的工作节点和Pod,一个集群至少要有一个工作节点。K8s用于管理的基本调度单元为Pod。

设备列表

把自己手头上能长期运行的设备都找出来了,凑一起性能也还不如一台高配置主机:

  • 国内某云计算厂商“轻量应用服务器”,1核心,2GB内存,1台,公网IPv4,作为master节点,以下未额外说明的都为工作节点
  • 国外某云计算厂商VPS,1核心,1GB内存,1台,公网IPv4/IPv6
  • Raspberry Pi 4B,4核心,4GB内存,1台,实验室内网,即学校内网的内网(什么套娃,下同)
  • 台式机,8核心,16GB内存,1台,实验室内网
  • 虚拟机,4核心,2GB内存,1台,宿主机位于学校内网,NAT方式与主机连接

搭建前提

根据我的理解,集群中所有的节点都应该做到能够互相访问,但我现在显然不满足这个条件。如果任意两节点不能互相访问,那跨节点的Pods之间的通信也就不能实现。

为此,先使用WireGuard组建一个内网(其实并不是,早就组好了)。因为我实在是不喜欢现在的一些WireGuard Mesh组网工具,自己又懒(还菜),没有自己动手写一个。反正设备少,所以就先手动管理配置,不能直连的设备就经过公网节点中转,大概就是这样。

使用WireGuard配置你的私有网络时,在Linux内核版本>=5.6,使用Systemd的设备上(内核比这老,或者不用Systemd的自己看着办吧),你只需要安装一个wireguard-tools软件包,使用wg genkey | tee privatekey | wg pubkey > publickey命令生成每个节点的公钥、私钥,并编辑/etc/wireguard/<wg_interface_name>.conf文件。(wg_interface_name为你希望WireGuard在该设备创建的虚拟网卡的名称,例如wg0)

公网节点(国内云服务器)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[Interface]
Address = <ip_cidr> # 在你创建的网络里,你为此节点设定的IP,例如172.18.1.1/24,注意使用CIDR表示法
ListenPort = <port> # 这个节点对外开放的端口
PrivateKey = <private_key> # 此节点的私钥

# 以前好像是不需要的,后来iptables配置大概是被K3s改了,所以得加上,在开始连接前,创建iptables规则,允许进出WireGuard网络设备的包被转发,关闭连接后把相关规则删掉
# 还有一个需要用sysctl改的系统内核参数,关于转发的,我手头的几个机器默认都是开的,很多文档上都提到了,这里就不写了
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT;
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT;

# 某个内网节点
[Peer]
PublicKey = <peer_public_key> # 对面节点的公钥
AllowedIPs = <peer_ip_cidr> # 需要路由到该节点的IP,像这种内网节点,可以只路由他本身的IP,例如172.18.1.11/32,如果你还需要他转发一些流量,可以扩大子网掩码范围或者添加其他IP段,示例详见内网节点配置

# 某个公网节点,没写的配置介绍同上
[Peer]
PublicKey = <peer_public_key>
AllowedIPs = <peer_ip_cidr>
EndPoint = <peer_public_ip>:<peer_port> # 对面节点的IP和开放的端口 例如1.2.3.4:5678

# 参考上面这两个,你可以添加很多节点

内网节点(实验室设备等)

1
2
3
4
5
6
7
8
9
10
[Interface]
Address = <ip_cidr>
ListenPort = <port>
PrivateKey = <private_key>

[Peer]
PublicKey = <peer_public_key>
AllowedIPs = <peer_ip_cidr> # 如果当前节点到其他WireGuard内网节点的流量需要公网节点转发,那么可以填写你组建的整个网络的IP范围,例如172.18.1.0/24(别问我为啥用B类地址组/24的网络,我乐意)
Endpoint = <peer_public_ip>:<peer_port> # 对面节点的IP和端口,一般是公网节点的
PersistentKeepalive = <time_in_sec> # 保持持续连接的心跳包时间,数字,单位为秒,例如25

然后呢,就在每个机器上都执行systemctl enable wg-quick@<wg_interface_name>.service --now命令,启用并启动WireGuard服务就可以了。

搭建步骤

主节点

在主节点执行以下命令:

1
2
3
4
5
# 在国内,使用Rancher-CN提供的加速镜像
curl -sfL http://rancher-mirror.cnrancher.com/k3s/k3s-install.sh | INSTALL_K3S_MIRROR=cn sh -

# 在国外,使用官方源。注意,两者是替代关系,二选一执行即可
curl -sfL https://get.k3s.io | sh -

由于我使用的云服务器的公网IP地址并没有绑定在其网卡上,就算绑定了,K3s也不一定能选中正确的网卡,所以需要修改启动参数,手动指定其外部IP地址和flannel使用的网卡(其实在安装命令里指定也一样,没啥区别,但这样安装命令会比较长,我觉得不好写也不好看)。执行完成之后,编辑/etc/systemd/system/k3s.service,在修改最后的ExecStart处内容:

1
2
3
4
5
6
7
8
9
ExecStart=/usr/local/bin/k3s \
server \
'--node-external-ip' \
'<your_public_ip>' \
'--flannel-iface' \
'<your_network_device>'

# <your_public_ip>为该节点的公网IP
# <your_network_device>为你希望该节点与其他节点使用flannel通信时使用的网络设备,在我们当前的条件下,为了使设备之间可以通信,应当选择WireGuard创建的虚拟网卡,即上文提到的<wg_interface_name>

还有一个小技巧,当你的主机访问各种镜像仓库时有困难(无法连接、连接速度慢等),而你的主机上恰巧运行着一些代理工具的情况下,可以使用代理工具开启一个本地代理(SOCKS5, HTTP等),然后在K3s service的配置文件中加入Environment="ALL_PROXY=socks5://127.0.0.1:xxxx",为启动的K3s通过环境变量的方式设置代理,当然你这个代理工具最好能够支持对私有地址、国内地址等不转发,要不然你的K3s流量全都被代理转发走了,还能不能连接上其他节点就不好说了。同理,你也可以用ALL_PROXY环境变量为kubectl设置代理,让你apply一些来自网络的配置文件的时候速度快一些。

工作节点

执行以下命令,安装K3s并设置主节点:

1
2
3
4
5
6
7
8
9
10
11
# 国内镜像
curl -sfL http://rancher-mirror.cnrancher.com/k3s/k3s-install.sh | INSTALL_K3S_MIRROR=cn \
K3S_TOKEN='<master_node_token>' \
K3S_URL=https://<master_node_ip>:6443 sh -

# 官方源,同上,二选一
curl -sfL https://get.k3s.io | \
K3S_TOKEN='<master_node_token>' \
K3S_URL=https://<master_node_ip>:6443 sh -

# 这里的<master_node_ip>,如果主节点有公网IP,那填公网IP或自建网络的IP都可以,否则就写你自建的WireGuard网络里,你的K3s master节点的IP。

然后和主节点类似,修改cat /etc/systemd/system/k3s-agent.service文件:

1
2
3
4
5
6
7
8
ExecStart=/usr/local/bin/k3s \
agent \
'--node-external-ip' \
'<wireguard_network_ip>' \
'--flannel-iface' \
'<your_network_device>'

# <wireguard_network_ip>为这台主机在WireGuard网络中的IP,或这台主机的公网IP(如果有)

树莓派

安装方式和其他工作节点基本相同,但要注意,安装之前先在/boot/firmware/cmdline.txt的最后添加以下内容并重启。(和原有内容在同一行就可以,空格分隔)

1
cgroup_memory=1 cgroup_enable=memory

此外,要注意你树莓派上的操作系统应当是64位的。

管理

安装KubeSphere

使用kubectl命令管理集群当然是非常合适的,但只用命令,有时候也不那么方便,所以我使用了来自青云的开源项目:KubeSphere容器平台,方便对集群的管理。其可以直接部署在现有的K8s集群上,具体方法可以参考官方文档。如果安装后不能正常访问管理平台,请重点检查ks-consoleks-apiserver两个Pod。

工作节点相关

将新节点设为工作节点

在添加新节点后,新节点的身份默认为none,执行以下命令,为某节点添加worker标签:

1
kubectl label node <node_name> node-role.kubernetes.io/worker=worker

主节点不作为工作节点

执行以下命令,为主节点设置NoExecute的污点:

1
kubectl taint nodes <node_name> k3s-controlplane=true:NoExecute

展望

此后,我的这一个凑数集群可能会用于搭建我校网络安全校赛平台,或者给我们实验室的同学做云安全研究和实验使用。在应用过程中,如果有值得分享的内容,也会写成博客的。

关于标签,污点等K8s中的概念,我也在学习当中,而且我写博客一般不太愿意重复网上已经有很详细资料的内容,所以与本篇主要内容无关,我也写不出新东西来的内容,就不多说了。等我有什么值得分享的新想法,再回来更新这篇文章。

使用本地机器和VPS搭建K3s集群

https://d6s3.ac.cn/posts/a-simple-k3s-cluster/

作者

DD6181S03

发布于

2022-03-09

更新于

2022-03-20

许可协议