WireGuard 虚拟内网 — 让跨机房节点互通

为什么需要 WireGuard?

我们的 5 台服务器分布在洛杉矶和香港两个机房,公网 IP 大多是 NAT 映射的(不在本地网卡上)。K8s 的 kubelet 要求 --node-ip 必须是本地网卡上的地址,而且 API Server 需要能通过这个 IP 回连 kubelet。

WireGuard 在每台机器上创建虚拟网卡 wg0,分配统一的私有 IP,通过加密隧道走公网通信。

网络拓扑

公网 IP                  WireGuard IP (wg0)     角色
107.148.176.193    →    10.10.0.1/24           Master
107.148.164.118    →    10.10.0.2/24           Worker-1
154.9.27.60        →    10.10.0.3/24           Worker-2
38.76.221.17       →    10.10.0.4/24           Worker-3
154.219.104.66     →    10.10.0.5/24           Worker-4

WireGuard 原理(面试级理解)

与传统 VPN 的区别

特性OpenVPNIPSecWireGuard
运行层用户态内核态内核态
代码量~10 万行~40 万行~4000 行
加密协议可配置多种可配置多种固定最优组合
性能较慢中等接近裸机
配置复杂度高(需要 CA)很高极简

加密原理

WireGuard 使用固定的密码学组合(不可配置,消除了选错算法的风险):

  • Curve25519 — 密钥交换(ECDH)
  • ChaCha20 — 对称加密(比 AES 在无硬件加速时更快)
  • Poly1305 — 消息认证
  • BLAKE2s — 哈希

每个节点有一对密钥(私钥 + 公钥)。通信时用对方公钥 + 自己私钥做 Diffie-Hellman 交换,派生出共享密钥加密数据。

安装与配置

# 安装
apt-get install -y wireguard-tools

# 生成密钥对
wg genkey | tee /etc/wireguard/privatekey | wg pubkey > /etc/wireguard/publickey
chmod 600 /etc/wireguard/privatekey

配置文件 /etc/wireguard/wg0.conf(以 Master 为例):

[Interface]
Address = 10.10.0.1/24          # 本机 WireGuard IP
PrivateKey = <本机私钥>
ListenPort = 51820               # UDP 监听端口

[Peer]                           # 每个对端一个 [Peer] 段
PublicKey = <Worker-1 公钥>
AllowedIPs = 10.10.0.2/32       # 只允许这个 IP 从此 peer 来
Endpoint = 107.148.164.118:51820 # 对端公网地址
PersistentKeepalive = 25         # 每 25s 发心跳,保持 NAT 映射

AllowedIPs 的双重作用:

  1. 出站路由: 发往 10.10.0.2 的包走这个 peer 的隧道
  2. 入站过滤: 只接受源 IP 为 10.10.0.2 的包从这个 peer 来
# 启动并开机自启
systemctl enable --now wg-quick@wg0

实测延迟

LA 内部(10.10.0.1 ↔ 10.10.0.2): ~1.5ms
LA ↔ HK(10.10.0.1 ↔ 10.10.0.4): ~155ms

WireGuard 几乎不增加额外延迟(内核态加密 + UDP 封装开销极小)。

为什么用 Full Mesh 而不是 Hub-Spoke?

我们配置了全互联(每个节点都知道所有其他节点),而不是所有流量经过 Master 中转。原因:

  • K8s Pod 跨节点通信需要节点之间直连
  • Hub-Spoke 模式下 Master 成为流量瓶颈
  • 延迟翻倍(Worker→Master→Worker 变成 Worker→Worker)

清理方法

systemctl disable --now wg-quick@wg0
rm -rf /etc/wireguard/