从 Cloudflare Tunnel 到 Tailscale:为家庭实验室增加网络后备方案
背景:遭遇 Cloudflare 连通性问题
自己在家维护着一个 Kubernetes 集群,对外暴露了一些服务方便自己在外面随时随地访问,这些服务的监控可以点这里查看:https://status-dev.tomyail.com/
最近发现这些服务的连接性不好,比如在使用 git pull
拉取部署在家里的 gitea 的代码总是失败,必须挂代理才能访问。我使用的是 Cloudflare Tunnel 方案,后来看到一篇文章 部分 Cloudflare 的域名近期在大陆无法访问 才明白,文章提到以 .1
结尾的 IP 地址,估计都是被防火墙特殊照顾的。
通过 nslookup
查看我的域名解析,果然全是这类 IP:
❯ nslookup gitea.tomyail.comServer: 11.11.11.11Address: 11.11.11.11#53
Non-authoritative answer:Name: gitea.tomyail.comAddress: 104.21.32.1Name: gitea.tomyail.comAddress: 104.21.48.1Name: gitea.tomyail.comAddress: 104.21.80.1Name: gitea.tomyail.comAddress: 104.21.64.1Name: gitea.tomyail.comAddress: 104.21.96.1Name: gitea.tomyail.comAddress: 104.21.16.1Name: gitea.tomyail.comAddress: 104.21.112.1
现在也不确定这个屏蔽是暂时的还是永久的,总之得先搞个 Plan B。
方案选择:为什么选择 Tailscale
面对内网穿透方案的选择,我主要在 frp 和 Tailscale 之间纠结了一下。最终选择 Tailscale 的原因如下:
- 退可守:与 frp 相比,Tailscale 自带中继服务,可用性更高
- 进可攻:如果需要,tailscale 的 derp 中继服务也能自己搭建
- Kubernetes 友好:Tailscale 有官方的 Kubernetes Operator,部署更简单
考虑到自己也维护着一个美国的线上集群,所以最终选择了 Tailscale + 美国集群作为入口 的方案。
美国集群在这个架构中扮演着关键的桥梁角色:
- 流量转发枢纽:将外部流量通过 Tailscale 网络转发到国内家庭集群
- DNS 自动化管理:配合 External-DNS 可以自动声明和管理 DNS 记录,无需手动维护域名解析
网络架构演进
原架构:
外部用户 → Cloudflare(❌) → Cloudflare Tunnel → 家庭集群服务
新架构:
外部用户 → 美国VPS公网IP(✅) → Nginx Ingress → Tailscale网络 → 家庭集群服务
说明:本文不讨论
外部用户 → Tailscale客户端 → 家庭集群服务
这种方案,因为需要每个用户都安装 Tailscale 客户端,不够通用。
技术实现详解
1. 家庭集群部署 Tailscale Operator
1.1 准备工作
首先需要在 Tailscale 控制台创建 OAuth 应用:
- 访问 Tailscale OAuth 设置
- 创建 OAuth 客户端,权限选择:
- ✅ Devices Core (写权限)
- ✅ Auth Keys (写权限)
1.2 配置 ACL 权限
在 Tailscale 控制台的 ACL 页面添加:
{ "tagOwners": { "tag:k8s-operator": [], "tag:k8s": ["tag:k8s-operator"] }, "acls": [{ "action": "accept", "users": ["*"], "ports": ["*:*"] }]}
1.3 部署 Operator
---apiVersion: helm.toolkit.fluxcd.io/v2kind: HelmReleasemetadata: name: &app tailscale namespace: networkspec: interval: 30m chart: spec: chart: tailscale-operator version: 1.84.3 interval: 30m sourceRef: kind: HelmRepository name: tailscale namespace: flux-system values: operatorConfig: hostname: tailscale podAnnotations: reloader.stakater.com/auto: 'true' apiServerProxyConfig: mode: 'true' valuesFrom: - kind: Secret name: tailscale-secret valuesKey: client_id targetPath: oauth.clientId - kind: Secret name: tailscale-secret valuesKey: client_secret targetPath: oauth.clientSecret
成功部署后,会在 Tailscale 的 Machines 后台看到一个新机器(我这里定义的名字是 tailscale
):
2. 暴露服务到 Tailscale 网络
对于需要暴露的服务,只需要添加一个注解即可(参考:官方文档):
如果要暴露的服务已经存在,可以通过对象注解的方式将其暴露到 Tailscale 网络。
在服务的 metadata.annotations
下添加注解 tailscale.com/expose
,值设为 "true"
。注意这里的 "true"
需要加引号,因为注解值必须是字符串类型,不加引号的 true
会被错误地解释为布尔值。
使用这种模式时,Kubernetes 不会直接告诉你 Tailscale 机器名称。你可以在 Tailscale 管理控制台的 Machines 页面查看设备名称。默认情况下,暴露服务的机器名称格式为 <k8s-namespace>-<k8s-servicename>
,当然这个名称是可以自定义的。
以下配置片段来自我的实际配置:
service: app: annotations: tailscale.com/expose: "true" controller: echo ports: http: port: *port
部署后,服务会自动获得:
- ✅ Tailscale IP
- ✅ Tailscale 域名:
default-echo.shark-pentatonic.ts.net
(其中shark-pentatonic.ts.net
是 tailnet name,每个人都不一样,并且只有 Tailscale 网络内部能访问)
如果成功,会在 Tailscale Machines 页面出现一个新节点,这个节点就是对应的 Kubernetes 服务。
3. 美国集群配置
3.1 安装 Tailscale
在美国 VPS 上安装 Tailscale 客户端:
curl -fsSL https://tailscale.com/install.sh | shsudo tailscale up --authkey=<your-auth-key>
# 验证连接tailscale statusping default-prowlarr.shark-pentatonic.ts.net
3.2 配置代理服务
# 美国集群配置---apiVersion: v1kind: Servicemetadata: name: tailscale-echospec: type: ExternalName externalName: default-echo.shark-pentatonic.ts.net---apiVersion: networking.k8s.io/v1kind: Ingressmetadata: name: tailscale-echo-ingress annotations: external-dns.alpha.kubernetes.io/target: 'external-us.tomyail.com' external-dns.alpha.kubernetes.io/cloudflare-proxied: 'false'
spec: rules: - host: echo-tailscale.tomyail.com http: paths: - path: / pathType: Prefix backend: service: name: tailscale-echo port: number: 80
问题排查指南
在实施过程中,我遇到了几个典型问题,这里分享一下解决经验:
常见问题及解决方案
1. Tailscale Operator 启动失败
错误现象:
oauth2: cannot fetch token: 401 Unauthorized
解决方案:
必须是 Oauth Client,不是 Auth keys 或者 API access tokens; OAuth clients 生成的 secret 会带上 tskey-client 的前缀
2. 暴露的服务无法访问
错误现象:
curl -v http://default-prowlarr.shark-pentatonic.ts.net # 失败
解决方案:
- 确认美国 VPS 已正确加入同一个 Tailnet
- 检查 Tailscale ACL 配置是否允许访问
- 验证服务是否在 Tailscale 控制台正确显示
总结
通过这次方案升级,成功解决了 Cloudflare 在国内的连通性问题。
不过尴尬的是,截止发文当天,似乎 Cloudflare 的连通性又恢复正常了 😂,所以折腾半天权当给内网穿透加一个后备方案吧。
实际效果对比
Cloudflare Tunnel 恢复后的表现:
Tailscale + VPS 方案的表现:
优化节点和非优化节点的区别:(使用国内优化节点响应可以在1秒以内,否则还是延迟比较高)
从监控数据可以看出:
- Cloudflare Tunnel:恢复后连通性确实不错,响应时间也比较快
- Tailscale + VPS:连通性稳定,虽然速度略慢于 Cloudflare(毕竟 VPS 不是国内优化节点),但胜在稳定可控
- Tailscale + VPS 的入口vps速度很影响响应速度(图三9:12PM-2:48PM 是dmit 入口的延迟,后面为普通线路),因为我国内优化节点的流量不是很多,就切换到非优化节点了
方案优劣对比
方案 | 连通性 | 速度 | 成本 | 可控性 | 维护难度 | 安全性 |
---|---|---|---|---|---|---|
Cloudflare Tunnel | ⚠️ 国内不稳定 🌍 国外优秀 | 🏍️ 国内一般 | 💰 免费 | ❌ 依赖第三方 | 🟢 简单 | ✅ IP 隐藏 |
Tailscale + VPS | ✅ 连通性稳定 💡 适合作后备 | 🟡 取决于vps的速度和derp的速度 | 💰 $5-20/月 | ✅ 完全自控 | 🟡 中等 | ⚠️ IP 暴露 |
相关资源:
PS:整个方案是通过与 Cursor 的 Claude 4 聊天逐步完善的。AI 提供了整体思路,但具体实施细节不能全信,还需要结合官方文档自己排查解决问题。