pre-post()
最近有在学习K8S相关,同时也将自己的所有服务全部都迁移到了K8S集群上,感受到K8S强大的同时也能明显感受到对于我这种一般用户环境的部署不是很友好,例如建议的高可用集群至少要有 三台
Master, 三台
Worker, 对我这种 穷逼 普通玩家来说是很高昂的,但经过几次实践把生产环境搞炸几次后觉得这是有必要的(哭),但我的想法是用K8S作为我主要部署方式,所以还是非常高昂的,像我这种为了能够管理所有节点但是又不会重度使用K8S的,这里推荐 K3S
来代替K8S作为要求不高的生产环境,不过这篇文章还是用完整的K8S来做,但理论上 K3S
是完全通用的。
subject(‘实现目标’)
利用 Kilo
将带有公网IP的NAT云服务器组成K8S集群,支持 P2P
, DDNS
(要求有公网IP且需要端口映射)
subject(‘Kilo介绍’)
Kilo 是一个通过 Wireguard
用于建立混合云网络的工具
subject(‘现有问题’)
我的服务器构成是这样的(以下IP皆为虚拟):
Name | ifc-IP | Location | Role | Nat |
---|---|---|---|---|
k8s-master | 123.123.123.123 | Hetzner | Master | NO |
cn-sh01-node | 10.0.0.4 | QCloud | Worker | YES |
cn-hz01-node | 192.168.1.120 | Home | Worker | YES |
可以看到我的三台服务器都不是同一个网段甚至都不是同一个服务商的。
所以会有几个问题
- kube-proxy 无法正常工作转发流量
- metrics 采集无法工作
- logs/shell 无法工作
subject(‘解决问题’)
之前是用 Weave
来作为CNI的,然后为了解决 kube-proxy
的一些问题换成了 Flannel
, 网上查找一些资料和issues以后发现如果要解决这个问题,就得先将所有节点连起来,连起来的方法就是VPN,然后让通讯流量走VPN接口即可解决,但是按常规理解VPN流量是需要中心服务器转发流量的,那就会导致所有流量转发到同一台服务器,压力和延迟也会非常大不符合需求,然后我去搜了P2P VPN发现 Wireguard
是支持Peer2Peer的,顺势在某个issue里看到有人提到用 Kilo
进行自动组网,并且 Kilo
是支持在 Flannel
之上运行的
端口通讯检查
我是采用 Flannel+Calico+Kilo 的方式设置网络的,所以需要以下端口放通
Port Range | Protocol | Remark |
---|---|---|
8285 | UDP | Flannel |
8472 | UDP | Flannel |
51820 | UDP | Wireguard 默认端口 |
10250 | TCP | Kubelet API |
30000-32767 | TCP+UDP | NodePort 服务端口 |
安装 Kilo
Kubeadm
1 | $ kubectl apply -f https://raw.githubusercontent.com/squat/kilo/master/manifests/kilo-kubeadm-flannel.yaml |
如果要卸载,直接 kubectl delete 就好了
配置外部连接IP
由于目前尚未支持 NAT to NAT(理论可以实现)
,所以每个Node都必须具备外部(公网)访问条件,但是你会发现一件事,每个Node都只会拿到网卡的IP,它没办法发现你的外部IP
所以就像 Flannel
通过 flannel.alpha.coreos.com/public-ip-overwrite
来覆写外部通讯IP一样 Kilo
同样也提供了 kilo.squat.ai/force-endpoint
来指定外部通讯连接点,格式是 "IP:PORT"
或者 "[DOMAIN]:PORT"
,是的,它支持域名,所以就可以实现我们 HOME
worker的DDNS需求,只要防火墙放通端口或者路由器转发端口就可以自由通讯了
编辑 cn-hz01-node
节点,在 metadata.annotations
里加入 kilo.squat.ai/force-endpoint: '[home.mydomain.com]:51820'
,然后过一会通过 kubectl desc node cn-hz01-node
就可以看到它自动解析了域名并且添加了一个新的 kilo.squat.ai/endpoint
annotation,值为你域名指向的IP
同样此方法去更改 cn-sh01-node
的 annotations,过一会就可以看到 metrics 信息已经正常显示了(前提是你已经部署了metrics采集)
建议采用
Flannel
的vxlan
作为后端,不采用IPSec
等加密后端避免不必要的二次开销
关于N2N实现
目前
Kilo
的N2N实现还在讨论并且已经在计划适配,具体可以在这里看到 https://github.com/squat/kilo/issues/109
subject(‘不通过VPN外部直连的可能性’)
说个题外话,假如全部NODE都是有公网IP但是会有一层NAT的能不能正常通讯呢,这个读过一点Kubernetes的代码,这个是有可能的,就是更改Node的 status.addresses
添加一个 Type
为 ExternalIP
的IP地址,但是这里有个问题就是,你没办法直接编辑或者patch一个node的status值,那么这个addresses是怎么来的呢?
addresses 实际上是通过 cloud-provider
设置的,他读取你的网卡并将其IP设置为 InternalIP
的address, 如果你是GCE, Azure等,他们会去跟平台通讯获取你机器的外网绑定网卡信息,并且设置为 ExternalIP
,而 metrics-server
的默认启动参数 --kubelet-preferred-address-types=ExternalIP,InternalIP,Hostname
定义了它会尝试去和外部IP、内部IP、主机名进行通讯,所以如果你是通过云服务商的k8s托管,那么它就会自动设置外部IP,但是手工设置是行不通的,所以如果自己写一个 “Fake” cloud-provider 的话也许也行得通,但其实价值就很低了,不如直接VPN组网来的实在。