Skip to content
赞赏-微信扫码

主要内容:frp 实现内网穿透

kubernetes 知识点:DaemonSet 工作负载

方案选型

硬件选型

一台有公网ip的云服务器,是必不可少的。我居然已经是 阿里云 的10年老用户了。

买最便宜的ECS服务器,最小的硬盘容量,不要分配公网ip地址。5年不到500块。

再 绑定一个按量付费的弹性公网ip。每个月有20G的国内公网流量免费额度。海外实例还有180G的每月免费流量额度。(用不完,根本用不完。)


家里的千兆宽带,上传部分基本是 50Mb 带宽(突发流量可以到 60Mb 以上)。弹性公网ip按量付费的性能可以选 200Mb 带宽。最便宜的 ECS 服务器的网卡性能是 80Mb。所以,跑满上传带宽是没问题的。


尽量选离自己家地理位置近的地域,ping 时延能短一些。

踩坑小贴士

新买的便宜服务器,要 配一下交换空间。配个 512M 就好。

因为最低配服务器的内存不是很够。默认也没配交换空间。Ubuntu 系统,它自带的包管理工具,apt,默认会定时检查更新,这个行为还是很消耗系统资源的,尤其在内存不足的情况下,会有雪崩的连锁反应。。。

软件选型

ssh -R

在很长的一段时间里(有十几年了吧),内网穿透我一直用的 ssh 端口转发 的方案,还积累了提升 稳定性 的方法。

但是对比发现,这个方案的 性能不太好,换成其他方案后,肉眼可见的延迟降低了。

如果你在端口转发之上,再包一层 nginx 来提供公网服务,还会发现 nginx 对背后服务的 健康检查 在这个时候并不友好 :此时 nginx 在代理 localhost 的端口,即使端口转发已经故障了,localhost 的端口还正常监听,只能等待应用层的超时。本来可以通过 端口连接失败 或者 ip路由失败 来快速识别出故障的。

贝锐蒲公英

贝锐蒲公英 是我用过的另一个方案。其实不算 内网穿透,算 组网。它在连接故障时,可以通过 路由层面的失败 达到快速失败的效果。另外,正常访问时,延迟也是肉眼可见的比 ssh -R 低。

但是,绝对不要在生产系统中使用 贝锐公司的产品!!!

我在 5 年前,使用它的 linux 客户端,发现不能开机自启动,提工单找来技术人员登我的服务器也没查出原因。

这次特地买了它的工业路由器(可以设置4G流量做备用网络),就又尝试了新出的 docker 客户端,结果 docker 客户端修改我服务器的路由表,把 172.0.0.0/8 的网络都给接管了。正常局域网地址的范围是 172.16.0.0/12。导致服务器无法访问 Let's Encrypt 申请 https 证书。这回提工单还遭到各种踢皮球,几经波折,最后也来了个技术人员登录我的服务器,查完确认了bug,问题还是没得到解决。

而且它的组网中间服务器需要发布更新,一般是半夜发布,偶尔会出现组网客户端掉线不自动恢复登录的情况。

虽然不会在生产系统中使用贝锐的产品,但是个人日常使用还是可以的。目前我把它当成一个 vpn 服务,在外出的时候连上,可以继续用内网地址访问家里的服务器。比起折腾各种开源组网软件,要快捷的多。

frp

frp 是我最终的软件选型。无论是 性能、稳定性、重启时的平滑程度、故障时的自动恢复能力、安装配置的学习成本 试用下来都是 毫无短板。稳定到我都忘记了内网穿透的存在。甚至,我愿意把它安装到 kube-system 命名空间下。

它分为 服务端(frps)、客户端(frpc)两个部分。

frps 服务端 配置

官方文档中的安装说明,安装成系统服务。

frps.toml

完整的配置项,还是希望大家自己把官方文档通读一遍。这里给出我自己用的最终的配置(密码部分都用 xxx、123 代替了)。

toml
bindPort = 7000
auth.token = "xxx123"

transport.maxPoolCount = 1024

webServer.addr = "0.0.0.0"
webServer.port = 7001
webServer.user = "xxx"
webServer.password = "123"

踩坑提示,配置项说明

  1. transport.maxPoolCount 默认为5。实测下来发现,需要改大,不然完全不够用,连接用满后新的请求会在那一直等待。
  2. webServer.xxx 的配置,对应到 frp 它在服务端有一个简易的后台页面,可以查看当前的服务状态。
  3. auth.token 这个密码,后面需要在客户端上也配成一样的。。。当然 bindPort 服务端监听的端口也是要配到客户端上。。。
  4. 提醒不熟悉云服务器的小伙伴,配置中的 7000 和 7001 端口, 要去安全组规则里开放下。

frpc 客户端 在 k3s 里部署

全文重点来了,客户端这边怎么安装。

首先,我把它安装到 kube-system 命名空间下面。

它是一个 守护进程集(DaemonSet)类型的工作负载。这种类型的工作负载,会在每个物理节点都启动一个实例。

我们要的就是这个效果,每个物理节点都启动一个客户端,客户端的本地目标都设置成自身所在的物理节点,任意一个物理节点关机的话,其他节点上的客户端还能让内网穿透继续正常工作。

大家以官方文档为线索,能找到官方的 github 仓库,看到 fatedier 这个账号是官方作者的账户名。然后去 docker hub 上搜镜像的时候。优先用 fatedier 空间下的镜像。

fatedier/frpc:v0.61.1

-c /etc/frp/frpc.toml

NODE_NAME  容器组信息  spec.nodeName
TZ                    Asia/Shanghai

这个镜像没什么说明文档。我们可以用 docker inspect 查看容器信息,找它的 Entrypoint 信息。就能推测出 要配置 -c 参数来指定自定义的配置文件。那我们就挂载一个配置文件进去。

配置文件内容如图:

frpc.toml 配置项说明

frpc.toml
toml
serverAddr = "apihub.net"
serverPort = 7000
auth.token = "xxx123"

[[proxies]]
name = "{{.Envs.NODE_NAME}}-tcp80"
type = "tcp"
localIP = "{{.Envs.NODE_NAME}}"
localPort = 80
remotePort = 80
loadBalancer.group = "web"
loadBalancer.groupKey = "web"
transport.useCompression = true
healthCheck.type = "tcp"
healthCheck.timeoutSeconds = 2
healthCheck.maxFailed = 3
healthCheck.intervalSeconds = 10


[[proxies]]
name = "{{.Envs.NODE_NAME}}-tcp443"
type = "tcp"
localIP = "{{.Envs.NODE_NAME}}"
localPort = 443
remotePort = 443
transport.useEncryption = true
transport.useCompression = true
transport.proxyProtocolVersion = "v2"
loadBalancer.group = "websecure"
loadBalancer.groupKey = "websecure"
healthCheck.type = "tcp"
healthCheck.timeoutSeconds = 2
healthCheck.maxFailed = 3
healthCheck.intervalSeconds = 10

每个配置项的作用,建议大家看一遍官方文档自己学习。这里重点说明一下 transport.proxyProtocolVersion = "v2".Envs.NODE_NAME

对 http 接触比较多,可能会知道 nginx 做 http 的代理,会在 http 请求头添加一些信息,比如 x-real-ip,来标识客户端的真实ip。TCP 协议中,对中间代理也有类似的规定,开启 transport.proxyProtocolVersion = "v2" 的配置,有助于后面应用程序拿到真实的客户端ip。

localIP 取的环境变量 NODE_NAME。是我们 “工作负载-容器信息” 截图中就有圈出来的,设置的是物理节点的主机名称。配合 DaemonSet 每个物理节点启动一个实例的特点。每个实例会把穿透的本地目标定成实例自身所在物理节点的 80/443 端口。