使用 Tailscale 异地组网搭建 K3s 集群
前段时间在家里的小主机上安装了一个单节点的 K3s 作为未来的服务运行环境以及开发环境(以及帕鲁服务器的运行环境),在使用的时候萌生了一个想法——是不是可以用家里的服务器与吃灰的羊毛云服务器一起组成一个 K3s 集群呢?
打开 K3s 文档,可以看到 K3s 直接集成了两种组建「多云」集群的方案:
- 内置的「多云」方案:使用 WireGuard 建立一个 VPN Mesh 供集群使用,这个方案要求每个节点都有一个可以直接访问的唯一 IP(通常是公网 IP)
- 集成 Tailscale 方案(实验功能):K3s 集成 Tailscale,直接使用 Tailscale 组建底层的 Mesh 网络
这里考虑到还需要接入家里的服务器,所以选择了 Tailscale 方案,从实践上来看这个方案也足够简单,并且看起来能满足我的需求。
准备工作
知识储备
K3s 集成 Tailscale 的方式
K3s 集成 Tailscale 的方案是如何实现的呢?这里稍微看了下代码,发现 K3s 并没有做什么太多的事情,核心代码就是下面这一行:
1 | func StartVPN(vpnAuthConfigFile string) error { |
K3s 只是在启动前根据传入的参数把 Tailscale 的参数构建好,调用 tailscale up
建立 Tailscale 网络,然后使用 tailscale0
网卡来初始化集群即可。
从代码上来看,K3s 目前只支持 Tailscale。同时还从代码中得到一个文档中没有的信息,--vpn-auth
参数还支持设置 extraArgs
,通过它可以透传自己希望设置的其它 Tailscale 参数,不得不说还是很贴心的,正好后面我们会用到这个参数。
再说说 Tailscale
Tailscale 的使用方式足够简单,但是功能又足够强大。基于 Tailscale,甚至不需要我们感知任何公网 IP,没有云服务器照样可以组跨地域的集群。
得益于 Tailscale 强大的内网穿透能力,即使是运行在防火墙后面的云服务器,不开放任何端口(仅 22 端口用于 SSH 连接)也可以通过 Tailscale 构建一个私有网络。
组网后,直接 Ping 另外的节点可以看到没有走任何中继服务器,只有一跳直接到达目的地
1 | tailscale ping multicloud-home-nuc |
Subnet Route 与 Exit Node
通过上面提到的 extraArgs
参数,我们直接利用 Tailscale 特性玩点花活。
首先 Subnet Route 这个特性是 K3s 所依赖的,K3s 需要利用这个配置使得 Pod 间网络是可达的,在部署后,我们还可以通过 tailscale set
命令继续设置新的 Subnet Route,使得网络中的节点可以访问其它网段,比如家里的局域网。
Exit Node 也是一个有趣的特性,我们可以指定一个节点作为 Exit Node,所有 Tailscale 网络中的公共流量都会从这个节点进出。这不妨让我们想到云服务器的网络通常不是很理想,而为云服务器单独配置科学上网也是比较麻烦的事情,这时候如果我们 Tailscale 网络中的某台设备所在的网络的出口上有一个透明代理,那么一切都通达了起来。
服务器准备
- 大于 1 台的包括但不限于云服务器、物理主机、虚拟机等计算设备。
- 所有服务器安装 Linux 系统,建议内核版本大于 5.6,不需要安装 WireGuard 组件,我使用的都是
Ubuntu 22.04
,内核版本为5.15
。
Tailscale 配置
首先需要登录到 Tailscale,可以用任意第三方账号登录,这里我使用 Github 登录,如果第一次使用 Tailscale,会进入一个使用引导,直接跳过就好。
登录后,进入到
Settings > Keys
中,生成一个 Auth Key,需要注意的是需要勾选Reusable
选项以支持多设备复用同一个 Key。配置
autoApprovers
,将 Pod 子网添加到自动通过配置中,使得 Pod 网络可以正常互相访问,这需要我们在Access controls
中添加相应的配置,这里直接使用了默认的 Pod CIDR,中括号中的名字是在Users
中看到的内容,如我是microud@github
1
2
3
4
5
6"autoApprovers": {
"routes": {
"10.42.0.0/16": ["your_account@xyz.com"],
"2001:cafe:42::/56": ["your_account@xyz.com"],
},
},设置好后如下
一切准备就绪,开始搭建我们的集群了~
搭建集群
做好前面的准备后搭建集群就很简单了,几条命令即可,本章节的内容可以当一个操作手册供参考。
安装 Tailscale
执行如下命令在所有节点安装 Tailscale
1 | curl -fsSL https://tailscale.com/install.sh | sh |
安装完毕后不需要启动,K3s 会根据传入的设备来执行 tailscale up
启动 Tailscale。
初始化 Server 节点
配置 K3s 使用 Tailscale 网络,只需要在执行 K3s 的安装脚本添加如下参数即可
1 | --vpn-auth="name=tailscale,joinKey=$AUTH_KEY |
通过环境变量设置 AUTH_KEY
后,执行下面的完整的命令
1 | curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="server" sh -s - \ |
还可以按需禁用 traefik ingress。
如果是国内的云服务器网络受限的话,可以换用如下的命令来安装
1 | curl -sfL https://rancher-mirror.oss-cn-beijing.aliyuncs.com/k3s/k3s-install.sh | INSTALL_K3S_MIRROR=cn INSTALL_K3S_EXEC="server" sh -s - \ |
Server 节点可以在任意服务器上,无所谓是否有公网 IP。
创建 Agent 节点
由于在 Server 节点未设定 Token,查看 k3s 生成的 token 文件, server:
后的部分即为 Token
1 | sudo cat /var/lib/rancher/k3s/server/token |
其次查看 Server 节点上 tailscale0
网卡的 IP 地址,拿到 IP 后就可以部署 Agent 了
1 | curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="agent" sh -s - \ |
经过上面的步骤,集群就初步搭建好了,如果还有新的节点可以继续添加 Agent。这里我直接查看一下 Node
1 | kubectl get nodes |
整点花活
还记得上面提到的 Subnet Routes 与 Exit Node 吧,在这里讲一下具体的操作。
Subnet Routes
K3s 在 Tailscale 启动完毕后,Flannel 会根据 PostStartupCommand
配置来进一步配置 VPN 以确保 Pod 间的网络联通
1 | { |
其中 %Routes%
会被具体替换为 IPv4 或者 IPv6 的地址,具体根据配置决定。
在安装好的节点上执行命令可以看到设置的结果,这也正是我们在前面配置的 autoApprovers
1 | tailscale status --json | jq ".Self.PrimaryRoutes" |
我们想扩展支持的网段,首先需要在待添加网段中的某个节点上执行如下命令
1 | tailscale set --advertise-routes "10.42.0.0/24,192.168.5.0/24" |
这次由于我们没有设置 autoApproves
,还需要到 Tailscale 后台中通过一下,点击「Edit route setting」可以看到如下设置
通过后就可以在 Tailscale 任意节点中访问这个网段了。
Exit Node
Exit Node 的申请可以直接在 k3s 安装阶段完成比较简单,安装命令调整如下:
1 | curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="server" sh -s - \ |
节点同样只是可以申请成为 Exit Node,启动后我们还需要去 Tailscale Admin 通过一下,依旧是在编辑 Route 菜单项中,勾选 Exit Node 保存即可。
配置好 Exit Node 后,不代表其他节点就会使用,还需要在期望使用的节点上手动设置一下
1 | 使用 IP 设置 Exit Node |
设置 Exit Node 后,所有的外网流量都会走 Exit Node,如果是云服务器那公网 IP 是不能再用来 SSH 了,不过可以通过 Tailscale 网卡的 IP SSH 到节点再设置取消 Exit Node。
如此操作下来,云服务器也能享受到家庭网络中的科学配置了,可以在必要的时候使用,如果不介意公网 IP 不可用,还可以一直启用。
小结
至此集群就已经搭建好了,在 Tailscale + K3s 场景下还能继续怎么玩呢?我准备继续折腾一下,挖掘一些有趣的内容再分享出来~