通Wireguard实现K3S节点跨机房组网

1. kilo作为网络插件

Master节点部署在公有云环境并且具有可访问的公网IP,Agent节点部署在任意机房无需公网IP。

通过在Kubernetes集群中使用wireguard搭建Pod网络,实现跨机房目的。

Flannel 的 WireGuard 模式:

关于rancher官方文档中提到可以配置**–flannel-backend=wireguard**使用wireguard协议作为flannel的后端,实际应用中发现有以下问题:

  • flannel 没有对针对wireguard有专门实现,k3s提供的方案是基于extension机制实现的,非常简陋
  • 需要手工编辑net-conf.json才能实现上述场景的VPN组网

为了满足上述场景选择使用kilo作为网络插件:

  • 安装部署时指定:–flannel-backend=none不使用k3s嵌入的flannel插件,后续手动安装kilo
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# master部署
K3S_TOKEN=<token> \
INSTALL_K3S_SKIP_DOWNLOAD=true \
INSTALL_K3S_EXEC="server --node-external-ip <该节点的外网IP> --advertise-address <apiserver的vip> --tls-san <vip> --flannel-backend none" \
./k3s_install.sh

# agent部署
K3S_TOKEN=<token> \
K3S_URL=https://<apiserver的vip>:6443 \
K3S_NODE_NAME=<agent-node-name> \
INSTALL_K3S_EXEC="agent" \
INSTALL_K3S_SKIP_DOWNLOAD=true \
./k3s_install.sh 

选择集群的区域网关(PS:这里指具有公网IP的节点),所有同区域内的其他节点会主动同leader维护一个UDP心跳

1
2
k3s kubectl annotate nodes <公网网关-NodeName> kilo.squat.ai/force-endpoint="<公网IP>:51820"
k3s kubectl annotate nodes <公网网关-NodeName> kilo.squat.ai/leader="true"

部署kilo网络插件。

kilo要求将k3s.yaml 分发到所有节点。这里可以修改为通过configmap挂载该文件。

1
k3s kubectl apply -f https://raw.githubusercontent.com/squat/kilo/main/manifests/kilo-k3s.yaml

上述方案反复研究,发现不能实现网络分区~~!

2. Fannel与Kilo兼容模式

主机名 公网IP 区域 角色 Kilo Leader
node-master 共有云 Master Leader
node-agent-01 私有机房 Worker Leader(优先指定)
node-agent-02 私有机房 Worker
node-agent-03 私有机房 Worker

执行以下命令安装k8s集群,使用flannel vxlan模式:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# Master
K3S_TOKEN=<token> \
INSTALL_K3S_SKIP_DOWNLOAD=true \
INSTALL_K3S_EXEC="server --advertise-address <公网IP> --tls-san <公网IP>" \
./k3s_install.sh

# Worker
K3S_TOKEN=<token> \
K3S_URL=https://<公网IP>:6443 \
K3S_NODE_NAME="节点名称" \
INSTALL_K3S_EXEC="agent" \
INSTALL_K3S_SKIP_DOWNLOAD=true \
./k3s_install.sh 

执行按照以下配置,构建wireguard的网络拓扑,其中Master主机region为default,其他主机region为nd:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
k3s kubectl label    node node-master topology.kubernetes.io/region=default
k3s kubectl annotate node node-master kilo.squat.ai/force-endpoint="<公网IP>:51820"
k3s kubectl annotate node node-master kilo.squat.ai/leader="true"
k3s kubectl annotate node node-master kilo.squat.ai/wireguard-ip="10.4.0.1/16" --overwrite=true  # 只有Leader节点配置wireguardIP


k3s kubectl annotate node node-agent-01 kilo.squat.ai/leader="true" # 手动指定最优的Leader,避免出现Leader之间竞争
k3s kubectl annotate node node-agent-01 kilo.squat.ai/wireguard-ip="10.4.0.2/16" --overwrite=true  # 只有Leader节点配置wireguardIP

k3s kubectl annotate node node-agent-01 kilo.squat.ai/persistent-keepalive="25"
k3s kubectl annotate node node-agent-02 kilo.squat.ai/persistent-keepalive="25"
k3s kubectl annotate node node-agent-03 kilo.squat.ai/persistent-keepalive="25"

k3s kubectl label    node node-agent-01 topology.kubernetes.io/region=nd
k3s kubectl label    node node-agent-02 topology.kubernetes.io/region=nd
k3s kubectl label    node node-agent-03 topology.kubernetes.io/region=nd

部署kilo,可以参考以下配置:

1
k3s kubectl apply -f https://raw.githubusercontent.com/squat/kilo/main/manifests/kilo-k3s-flannel.yaml

其中修改kilo的启动项如下:

1
2
3
4
5
6
        - --kubeconfig=/etc/kubernetes/kubeconfig
        - --hostname=$(NODE_NAME)      // hostname 这里取的是k8s的节点名称
        - --cni=false
        - --compatibility=flannel
        - --local=false
        - --encapsulate=crosssubnet

修改所有Leader节点DNS解析:将Leader节点NODE_NAME配置成对应的wireguard-ip,kilo在修改路由表时会将NODE_NAME 作为对应的网关地址**

联通性验证

  • 只有Leader的节点的wireguard-ip有意义,可以相互ping通

  • 任意节点上PodIP是互通的

  • 同一个区域内所有kilo设备被配置成一样的,从而实现高可用

    • 同一个区域内,kilo设备的IP相同
    • 同一个区域内,Peer表相同
  • 同一个内区域节点的路由信息不同

    • 访问同区域内PodIP,直接通过flannel.1
    • 访问其他区域的PodIP,通过flannel.1 发送到本区域的Leader,再从Leader上通过kilo.1发送到对应区域的Leader,最后到达对应的Node