






















PS:马上放假了,再折腾一下!!!
手动狗头~
【编程技术专区劝退提示】
上一篇 k3s 文章已经是 2025 年了,当时用的是 WireGuard 做跨云组网。
一年过去了,WireGuard 配置搞来搞去还是太累了
——每加一台机器都得手动改配置、互加 Peer、调路由……
于是今年决定把底层网络全换成 Tailscale。
更具体一点——自建 Headscale 控制面,不依赖官方 SaaS。
这样一来,整个内网想加多少节点就加多少节点,
一行命令入网,不用再手动管 WireGuard Peer 配置了。
同时,k3s 集群从 2 节点寒酸版,
升级到了 4 Master + 4 Edge 的 8 节点 HA 集群。
麻雀虽小,五脏俱全。
直接干。
先放一张架构图,全局概览:
互联网
│
┌─────────────┼─────────────┐
│ │ │
[腾讯云] [Rainyun] [本地]
(国内多台) (海外新加坡) (家庭/办公)
│ │ │
└─────────────┼─────────────┘
│
Tailscale VPN (100.64.0.0/10)
Headscale 自建控制面 (ts.example.com)
Authentik OIDC 登录 (auth.example.com)
│
┌──────────┬──────────┬──────────┐
│ │ │ │
[control1] [control2] [control3] [control4]
vm-0-8 vm-16-12 vm-28-17 vm-0-15
100.64.0.6 100.64.0.5 100.64.0.7 100.64.0.10
(Primary) (Member) (Member) (TS控制面)
│ │ │ │
└──────────┴──────────┴──────────┘
│
K3S HA 集群 (Flannel VXLAN over Tailscale)
Pod: 10.42.0.0/16 | Service: 10.43.0.0/16
│
┌─────────┬─────────┬─────────┐
│ │ │ │
[haru] [lgb-amd] [rainyun] [hc1]
国内 本地 海外 国内
Ready ✅ Ready ✅ Ready ✅ Ready ✅
当前集群实际状态:
| 节点名称 | 角色 | Tailscale IP | 状态 | 说明 |
|---|---|---|---|---|
8 个节点的集群,跑着十几个服务,稳得一比。
2025 年写的那篇文章里,我用的是 WireGuard 原生方案 + k3s Flannel wireguard-native 模式。
说实话,WireGuard 本身很稳,性能也好。但手动管理 Peer 这件事,在节点多了之后简直是噩梦:
所以,这次直接上 Tailscale。
Tailscale 官方的 SaaS 服务当然好用,个人版现在支持最多 100 台设备,数量上完全够用。但有几个问题:
tailscale up 都得先FQ授权,服务器端更是麻烦所以我选择了 Headscale——开源的 Tailscale 控制面实现。
配合 Authentik 做 OIDC 登录,体验和官方 Tailscale 几乎一致,甚至更灵活。
服务器要求:一台 2C2G 的小机器就够了,我用的是腾讯云轻量 Ubuntu 24.04。
核心就是一个 docker-compose.yml,包含:
| 组件 | 说明 |
|---|---|
部署完之后,两个域名就位:
https://ts.example.com → Headscale 控制面https://auth.example.com → Authentik 登录管理详细的部署流程这里不展开了(那是另一篇文章的事),核心要点:
100.64.0.0/10,这是 CGNAT 地址段,不会和内网冲突装好 Headscale 之后,任何一台机器入网就是一行命令的事:
# 安装 Tailscale 客户端
curl -fsSL https://tailscale.com/install.sh | sh
# 连接到自建控制面
tailscale up --login-server=https://ts.example.com --hostname=你的主机名 --accept-dns=false
终端会吐出一个链接,浏览器打开,跳到 Authentik 登录页,输入账号密码,授权完成——节点入网。
就这么简单。
关键建议:
不要依赖公有云内网!
即使你的 Master 节点在同一个云,也建议统一走 Tailscale 通信。
原因很简单:公有云内网是个黑盒,哪天换个机器、换个可用区,内网 IP 就变了。
而 Tailscale IP 是你自己分配的,不会变。所有节点,不管是云端、本地、还是其他云平台,统一用 Tailscale 接入,网络架构干净利落。
当前我的 Tailscale 网络长这样:
100.64.0.2 lgb-macbookair-m4 macOS ← 我的开发机
100.64.0.3 haru linux ← Edge 节点
100.64.0.4 lgb-amd-3700 linux ← 本地 Edge 节点
100.64.0.5 vm-16-12-ubuntu linux ← K3s Master
100.64.0.6 vm-0-8-ubuntu-new linux ← K3s Master (Primary)
100.64.0.7 vm-28-17-ubuntu linux ← K3s Master
100.64.0.8 rainyun-vja2g92e linux ← 海外节点
100.64.0.9 hc1 linux ← Edge 节点
100.64.0.10 ts-headscale linux ← Headscale 控制面 + K3s Master
100.64.0.12 ipv6radar linux ← 海外节点
100.64.0.13 localhost android ← 手机也能入网(摸鱼用)
不管在哪,ping 100.64.0.6 就能通。这才是正确的内网体验。
安装其实没什么花活,看官方文档就好:https://docs.k3s.io/zh/quick-start
但有几个关键参数必须注意。
第一个 Master(初始化集群):
curl -sfL https://rancher-mirror.rancher.cn/k3s/k3s-install.sh | \
INSTALL_K3S_MIRROR=cn \
sh -s - server \
--cluster-init \
--flannel-iface=tailscale0 \
--node-ip=100.64.0.6 \
--tls-san=100.64.0.6
后续 Master 加入集群:
curl -sfL https://rancher-mirror.rancher.cn/k3s/k3s-install.sh | \
INSTALL_K3S_MIRROR=cn \
K3S_TOKEN="你的Token" \
sh -s - server \
--server https://100.64.0.6:6443 \
--flannel-iface=tailscale0 \
--node-ip=$(tailscale ip -4) \
--tls-san=$(tailscale ip -4)
核心参数说明:
| 参数 | 为什么必须 |
|---|---|
--flannel-iface=tailscale0 这个参数是踩了无数坑之后的血泪教训。
如果不加这个参数,Flannel 会默认用物理网卡的 IP(比如公网 IP 或者云内网 IP)来建 VXLAN 隧道。结果就是——同云的节点能通,跨云的节点 Pod 全部不通。
加了这个参数之后,Flannel 的 VXLAN 隧道全部走 Tailscale 虚拟网卡,跨云 Pod 通信完美。
Edge 节点就是 Agent,更简单。
国内节点:
curl -sfL https://rancher-mirror.rancher.cn/k3s/k3s-install.sh | \
K3S_URL="https://100.64.0.6:6443" \
K3S_TOKEN="你的Token" \
INSTALL_K3S_MIRROR=cn \
sh -s - agent \
--node-ip=$(tailscale ip -4) \
--flannel-iface=tailscale0 \
--node-label="node.kubernetes.io/role=edge"
海外节点:
curl -sfL https://get.k3s.io | \
K3S_URL="https://100.64.0.6:6443" \
K3S_TOKEN="你的Token" \
sh -s - agent \
--node-ip=$(tailscale ip -4) \
--flannel-iface=tailscale0 \
--node-label="node.kubernetes.io/role=edge"
差别就是国内用 rancher-mirror.rancher.cn,海外用官方 get.k3s.io。
这里要特别提一下:国内环境下 Docker / containerd 拉取镜像是个大麻烦。
Docker Hub、ghcr.io、gcr.io 这些镜像源在国内基本处于半墙状态,k3s 内置的一些系统组件镜像(比如 pause、coredns、metrics-server)可能拉不下来,导致节点一直 NotReady。
几个解决思路:
/etc/rancher/k3s/registries.yaml 中配置国内可用的 mirror(如果你还能找到活着的)# 在海外节点导出
ctr -n k8s.io images export pause.tar registry.k8s.io/pause:3.9
# 传到国内节点
scp pause.tar root@<国内节点IP>:/tmp/
# 在国内节点导入
ctr -n k8s.io images import /tmp/pause.tar
我的做法是在海外节点上提前拉好需要的镜像,然后 ctr images export 导出,通过 Tailscale 内网传到国内节点再 ctr images import 导入。虽然笨了点,但胜在稳定可靠。
Token 在第一个 Master 上获取:
cat /var/lib/rancher/k3s/server/node-token
没什么问题的话,几秒钟后就能看到新节点上线:
$ kubectl get nodes -o wide
NAME STATUS ROLES AGE VERSION
vm-0-8-ubuntu-new Ready control-plane,etcd,master 30d v1.34.3+k3s3
vm-16-12-ubuntu Ready control-plane,etcd,master 30d v1.34.3+k3s3
vm-28-17-ubuntu Ready control-plane,etcd,master 30d v1.34.3+k3s3
vm-0-15-ubuntu Ready control-plane,etcd,master 1d v1.34.3+k3s3
haru Ready <none> 20d v1.34.3+k3s3
lgb-amd-3700 Ready <none> 15d v1.34.3+k3s3
rainyun-ssh7pavp Ready <none> 10d v1.34.3+k3s3
hc1 Ready <none> 5d v1.34.3+k3s3
8 个节点全部 Ready。
美。
Ingress 流量入口需要公网 IP + 足够的带宽。
我的做法是:
流量路径:用户请求 → 轻量云公网IP → Traefik Ingress → Service → Pod(可能在任意节点上)
Pod 在海外节点上也没关系,Flannel over Tailscale 会把流量打通。
症状:Edge 节点 Ready 了,但跨节点 Pod 通信全挂。
原因:没加 --flannel-iface=tailscale0,Flannel 默认选了公网网卡。
诊断:
kubectl describe node rainyun-ssh7pavp | grep flannel
# 看到 flannel.alpha.coreos.com/public-ip 用的是公网 IP 而不是 100.64.0.x
解决:卸载 k3s agent,重装时加上 --flannel-iface=tailscale0。
这个参数真的太重要了,说三遍:
--flannel-iface=tailscale0--flannel-iface=tailscale0--flannel-iface=tailscale0某台 Vultr 的 VPS,Tailscale 连接三天两头断。
节点在 Ready 和 NotReady 之间反复横跳,kubelet 疯狂报 unable to update node status。
排查下来发现是 VPN 链路问题,跟 K3s 没关系。
解决方案:先用 taint 隔离,后面直接换掉了这台机器。
kubectl taint nodes vultr.guest node-problem=true:NoSchedule --overwrite
kubectl taint nodes vultr.guest node-problem=true:NoExecute --overwrite
教训:不稳定的节点宁可不要,别死磕。 换一台新机器比排查网络问题快得多。
我的第四台 Master(vm-0-15-ubuntu)只有 2G 内存,同时还跑着 Headscale 控制面。
如果让它跑业务 Pod,分分钟 OOM。
解决:加 NoSchedule taint,只跑控制平面组件 + etcd。
kubectl taint nodes vm-0-15-ubuntu node-role.kubernetes.io/control-plane=:NoSchedule
2G 内存跑 k3s control-plane + etcd + Headscale 全家桶,CPU 和内存占用大约 60%,稳得住。
节点加完之后出问题?按这个顺序查:
# 1. 看节点状态
kubectl get nodes -o wide
# 2. 看节点事件
kubectl describe node <节点名>
# 3. 看 Tailscale 连通性
tailscale ping <目标节点Tailscale IP>
# 4. 看 Flannel 配置对不对
kubectl describe node <节点名> | grep flannel
# 5. 看 kubelet 日志
ssh root@<节点IP> "journalctl -u k3s-agent -n 50"
# 6. 测试跨节点 Pod 通信
kubectl run test --image=busybox --rm -it -- wget -qO- http://<其他节点PodIP>
90% 的问题都是前 4 步能查出来的。
对比 2025 年的方案,这次升级的核心变化:
| 项目 | 2025 年 | 2026 年 |
|---|---|---|
一句话总结方案:
整个集群跑了一个月,稳如老狗。
8/8 节点全部可用(之前有 1 台 Vultr 网络不行,已经换掉了)。
完事。
全文在凌晨的书房里完成,
祝大家新年快乐~
手动狗头~
相关链接:
本文使用 AI 辅助写作。
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。