K3s + Easytier 混合云集群部署笔记

一、项目背景与架构

1.1 目标

  • 使用一台云服务器(腾讯云轻量)和多台本地服务器组建 K3s 集群。
  • 通过 Easytier 组建异地虚拟局域网,打通所有节点。
  • 关键应用优先调度在本地节点,本地故障时自动漂移到云端节点。
  • 云端节点同时作为控制平面(Server)和备份工作节点。

1.2 网络拓扑

  • Easytier 虚拟网络172.16.10.0/24
  • K3s Pod 网络10.42.0.0/16(实际按节点分配 /24 子网)
  • K3s Service 网络10.43.0.0/16

1.3 节点角色

节点主机名 虚拟 IP 角色 位置 配置
tccn-k3scoreservice-mm-guangzhou 172.16.10.3 K3s Server + Agent(备份) 云端 2C4G
k3s-node-gzhlss 172.16.10.13 K3s Agent(主工作节点) 本地 Proxmox VM 2C4G
(待加入) 172.16.10.11 K3s Agent 本地 -
(待加入) 172.16.10.12 K3s Agent 本地 -

二、环境准备

2.1 系统信息

  • OS:Debian 12 (Bookworm)
  • 虚拟化:Proxmox VE(本地节点为 VM)
  • 已预装:Easytier 2.4.5(后续统一版本)
  • 云服务器额外组件:1Panel(避免干扰)

2.2 防火墙与端口

系统内部防火墙(iptables/nftables)配置将由 K3s 自动管理。


三、Easytier 组网配置

3.1 统一版本

防止 2.6.x 版本子网代理存在跨版本兼容问题,全部节点统一使用 2.4.5
如果已安装高版本,降级步骤:

1
2
3
4
5
6
wget -O /tmp/easytier-linux-x86_64-v2.4.5.zip https://dingpeng.cc/upload/easytier-linux-x86_64-v2.4.5.zip
unzip /tmp/easytier-linux-x86_64-v2.4.5.zip -d /tmp/easytier-v2.4.5/
sudo cp /tmp/easytier-v2.4.5/easytier-linux-x86_64/easytier-core /opt/easytier/
sudo cp /tmp/easytier-v2.4.5/easytier-linux-x86_64/easytier-cli /opt/easytier/
sudo chmod +x /opt/easytier/easytier-*
sudo systemctl restart easytier@default

3.2 配置文件

所有节点配置文件位于 /opt/easytier/config/default.conf

Server 节点(172.16.10.3)关键配置:

1
2
3
4
5
6
7
8
9
10
11
12
hostname = "TCCN-K3SCoreService-MM-Guangzhou"
ipv4 = "172.16.10.3/24"
dhcp = false
rpc_portal = "127.0.0.1:15888"

[network_identity]
network_name = "你的网络名"
network_secret = "你的网络密钥"

# 宣告 Server 本地 Pod 子网
[[proxy_network]]
cidr = "10.42.0.0/24"

Agent 节点(172.16.10.13)关键配置:

1
2
3
4
5
6
7
8
9
10
11
12
hostname = "K3S-Node-GZHLSS"
ipv4 = "172.16.10.13/24"
dhcp = false
rpc_portal = "127.0.0.1:15888"

[network_identity]
network_name = "你的网络名"
network_secret = "你的网络密钥"

# 宣告 Agent 本地 Pod 子网
[[proxy_network]]
cidr = "10.42.1.0/24"

注意:每个节点只宣告自己本地的 Pod 子网,不要宣告其他节点的子网。

3.3 启动与验证

1
2
3
4
5
6
7
sudo systemctl enable --now easytier@default

# 检查 peer 连接(应显示 p2p 且延迟正常)
easytier-cli peer

# 检查路由宣告(应能看到其他节点宣告的 proxy_cidrs)
easytier-cli route

四、K3s 集群部署

4.1 配置镜像加速(所有节点)

1
2
3
4
5
6
7
8
9
10
sudo mkdir -p /etc/rancher/k3s
sudo tee /etc/rancher/k3s/registries.yaml << 'EOF'
mirrors:
docker.io:
endpoint:
- "https://docker.1ms.run"
- "https://docker.m.daocloud.io"
- "https://dockerhub.timeweb.cloud"
- "https://registry-1.docker.io"
EOF

4.2 安装 K3s Server(仅云端节点)

1
2
3
4
5
curl -sfL https://rancher-mirror.rancher.cn/k3s/k3s-install.sh | INSTALL_K3S_MIRROR=cn sh -s - server \
--node-ip 172.16.10.3 \
--advertise-address 172.16.10.3 \
--tls-san <外部访问域名> \
--flannel-backend=host-gw

参数说明

  • --node-ip / --advertise-address:使用 Easytier 虚拟 IP,确保 Agent 能通过隧道加入。
  • --tls-san:添加外部访问域名,方便 kubectl 远程连接。
  • --flannel-backend=host-gw:三层转发模式,适合节点间 IP 直达的场景。

获取 token:

1
sudo cat /var/lib/rancher/k3s/server/node-token

4.3 安装 K3s Agent(仅本地节点)

1
2
curl -sfL https://rancher-mirror.rancher.cn/k3s/k3s-install.sh | INSTALL_K3S_MIRROR=cn K3S_URL=https://172.16.10.3:6443 K3S_TOKEN=你的token sh -s - agent \
--node-ip 172.16.10.13

4.4 验证集群

1
sudo kubectl get nodes

两个节点均应显示 Ready

4.5 锁定 K3s 版本(重要)

当前集群版本为 v1.35.4+k3s1。为防止未来重装或新节点加入时版本不一致,需锁定二进制文件。

锁定 Server 节点:

1
2
3
4
5
sudo systemctl stop k3s
sudo cp /usr/local/bin/k3s /usr/local/bin/k3s-v1.35.4
# 修改 /etc/systemd/system/k3s.service,将 ExecStart 中的 /usr/local/bin/k3s 改为 /usr/local/bin/k3s-v1.35.4
sudo systemctl daemon-reload
sudo systemctl start k3s

锁定 Agent 节点:

1
2
3
4
5
sudo systemctl stop k3s-agent
sudo cp /usr/local/bin/k3s /usr/local/bin/k3s-v1.35.4
# 修改 /etc/systemd/system/k3s-agent.service,将 ExecStart 中的 /usr/local/bin/k3s 改为 /usr/local/bin/k3s-v1.35.4
sudo systemctl daemon-reload
sudo systemctl start k3s-agent

未来新节点指定版本安装:

1
2
curl -sfL https://rancher-mirror.rancher.cn/k3s/k3s-install.sh | INSTALL_K3S_VERSION=v1.35.4+k3s1 INSTALL_K3S_MIRROR=cn K3S_URL=https://172.16.10.3:6443 K3S_TOKEN=<token> sh -s - agent \
--node-ip <新节点虚拟IP>

备注:

kubectl 和 crictl 是指向 /usr/local/bin/k3s 的软链接,锁定二进制后它们也会保持对应版本,不影响使用。
如果将来需要升级,可手动下载新版二进制,修改 systemd 服务文件指向新版,然后逐个重启节点实现滚动升级。


五、网络路由配置(关键)

5.1 问题背景

Flannel host-gw 模式依赖二层直连,但 Easytier 提供的是三层隧道,导致:

  • 宿主机无法直接 ARP 学习到对端容器的 MAC 地址。
  • Flannel 的 SNAT 规则会将跨节点 Pod 流量源 IP 改为节点 IP,造成回包路由错误。

5.2 解决方案

在每个节点手动添加前往其他节点 Pod 子网的静态路由。

Server 节点(添加前往 Agent Pod 子网的路由):

1
sudo ip route add 10.42.1.0/24 via 172.16.10.13 dev tun0

Agent 节点(添加前往 Server Pod 子网的路由):

1
sudo ip route add 10.42.0.0/24 via 172.16.10.3 dev tun0

5.3 持久化路由

创建 systemd 服务,确保重启后路由自动添加。

Server 节点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
sudo tee /etc/systemd/system/k3s-route-agent.service << 'EOF'
[Unit]
Description=Add route to Agent Pod subnet
After=easytier@default.service
BindsTo=easytier@default.service

[Service]
Type=oneshot
ExecStart=/sbin/ip route replace 10.42.1.0/24 via 172.16.10.13 dev tun0
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target
EOF
sudo systemctl enable k3s-route-agent.service

Agent 节点(类似,注意修改网段和下一跳):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
sudo tee /etc/systemd/system/k3s-route-server.service << 'EOF'
[Unit]
Description=Add route to Server Pod subnet
After=easytier@default.service
BindsTo=easytier@default.service

[Service]
Type=oneshot
ExecStart=/sbin/ip route replace 10.42.0.0/24 via 172.16.10.3 dev tun0
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target
EOF
sudo systemctl enable k3s-route-server.service

5.4 允许跨节点 Pod 流量(NetworkPolicy)

由于 K3s 自带的网络策略控制器会默认拦截非本地 Pod 流量,需创建 NetworkPolicy 放行:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
cat <<EOF | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-all-ingress
namespace: default
spec:
podSelector: {}
ingress:
- from:
- ipBlock:
cidr: 10.42.0.0/16
policyTypes:
- Ingress
EOF

六、调度策略配置

6.1 节点标签

1
2
kubectl label nodes k3s-node-gzhlss node-role=local
kubectl label nodes tccn-k3scoreservice-mm-guangzhou node-role=cloud

6.2 Pod 软亲和性

关键应用配置 preferredDuringSchedulingIgnoredDuringExecution,优先调度到 node-role=local 的节点:

1
2
3
4
5
6
7
8
9
10
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
preference:
matchExpressions:
- key: node-role
operator: In
values:
- local

七、验证与测试

7.1 跨节点 Pod 通信测试

部署两个强绑定的测试 Pod(分别落在云端和本地),互相 ping,确认双向可达,延迟约 24-40ms。

7.2 调度验证

部署 nginx-test 应用,观察是否优先调度到本地节点 k3s-node-gzhlss

7.3 故障转移测试

  1. 在本地节点停止 Easytier:sudo systemctl stop easytier@default
  2. 约 5 分钟后,Pod 自动驱逐并在云端节点重建。
  3. 恢复 Easytier 后,Pod 不会自动迁回。如需迁回,可手动重启 Deployment:
    1
    kubectl rollout restart deployment <name>

八、关键问题排查记录

问题 原因 解决方案
镜像拉取失败 (pause/netshoot) 国内访问 Docker Hub 超时 配置 registries.yaml 使用国内镜像代理(docker.m.daocloud.io
Agent 加入后 Pod 跨节点不通 1. Easytier 子网宣告错误(Server 宣告了 Agent 的子网,导致路由混乱)
2. 缺失手动路由(host-gw 依赖二层 ARP,隧道环境无法自动学习)
1. 每个节点只宣告自己本地的 Pod 子网
2. 在各节点手动添加前往其他节点 Pod 子网的静态路由
NetworkPolicy 默认拦截跨节点流量 K3s 自带的网络策略控制器会拦截发往非本地 Pod 的流量 default 命名空间创建 allow-all-ingress NetworkPolicy,放行 10.42.0.0/16
重启后手动路由丢失 静态路由未持久化 创建 systemd 服务,绑定 Easytier 启动后自动添加路由

九、后续优化方向

  • 自动迁回机制:部署 Descheduler 或 CronJob,实现本地节点恢复后 Pod 自动回迁。
  • 外部访问:使用不计量费的服务器反向代理 K3s 服务。
  • 存储备份:通过腾讯云 LightCOS 实现有状态应用的数据异地备份。
  • 多本地节点扩展:新节点加入时,按相同方式宣告自己的 Pod 子网,并在所有节点添加对应静态路由。
  • 高可用:未来可增加云端 Server 节点,配置嵌入式 etcd 实现控制平面高可用。

最后更新:2026-05-17
适用版本:K3s v1.35.4 + Easytier 2.4.5+