Kubernetes中高可用WireGuard网关的实现及跨集群VPN组网问题
兄弟,你遇到的这个问题我之前帮朋友排查过,其实是Kubernetes里用WireGuard做跨集群网关时的典型坑——ClusterIP访问不了的核心原因是WireGuard Pod的IP转发没开,加上其他Pod的路由表没把目标集群流量指向WireGuard服务,我给你一步步拆解解决方案,刚好匹配你要的多副本HA和负载均衡需求。
一、先解决ClusterIP无法访问的核心问题
你能直接通WireGuard Pod的IP但访问不了ClusterIP,主要卡两个点:
- WireGuard Pod没开启IP转发,导致流量没法在Pod内被转发到隧道接口
- 其他Pod的路由规则没把目标集群的流量导向WireGuard的ClusterIP
1. 调整WireGuard Deployment配置(开启IP转发+HA副本)
先给你一个能直接用的Deployment模板,已经加了多副本、跨节点分布、IP转发等必备配置:
apiVersion: apps/v1 kind: Deployment metadata: name: wireguard-gateway spec: replicas: 3 # 先搞3个副本实现基础HA,后续可按需调整 selector: matchLabels: app: wireguard-gateway template: metadata: labels: app: wireguard-gateway spec: # 强制让副本分布在不同节点,避免单节点故障导致整个VPN挂掉 affinity: podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: app operator: In values: - wireguard-gateway topologyKey: kubernetes.io/hostname # 开启IP转发和WireGuard必备的系统参数 securityContext: sysctls: - name: net.ipv4.ip_forward value: "1" - name: net.ipv4.conf.all.src_valid_mark value: "1" # 解决WireGuard的源IP标记异常问题 containers: - name: wireguard image: linuxserver/wireguard:latest # 用成熟的社区镜像省得自己折腾环境 securityContext: privileged: true # 需要特权修改网络命名空间的路由和iptables volumeMounts: - name: wireguard-config mountPath: /config # 挂载WireGuard的配置文件 ports: - containerPort: 51820 protocol: UDP # WireGuard默认用UDP env: - name: PUID value: "1000" - name: PGID value: "1000" volumes: - name: wireguard-config configMap: name: wireguard-config # 这个ConfigMap用来存你的wg0.conf配置
2. 配置跨集群可访问的WireGuard Service
因为要跨两个Kubernetes集群通信,ClusterIP只能在集群内访问,所以得用LoadBalancer(云环境)或者NodePort(自建集群)类型的Service,这里给云环境的LoadBalancer示例:
apiVersion: v1 kind: Service metadata: name: wireguard-service # 云厂商可加注解固定LB IP,方便后续配置Peer annotations: service.beta.kubernetes.io/aws-load-balancer-eip-allocations: "eip-xxxxxx" spec: selector: app: wireguard-gateway ports: - name: wireguard port: 51820 protocol: UDP targetPort: 51820 type: LoadBalancer # 开启客户端IP亲和性,避免同一客户端流量频繁切换WireGuard Pod导致隧道重建 sessionAffinity: ClientIP sessionAffinityConfig: clientIP: timeoutSeconds: 3600
二、配置WireGuard隧道的跨集群Peer
假设:
- 集群A的Pod CIDR是
10.0.0.0/16,Service CIDR是10.96.0.0/12 - 集群B的Pod CIDR是
10.1.0.0/16,Service CIDR是10.97.0.0/12
集群A的wg0.conf示例(存到ConfigMap里)
[Interface] PrivateKey = <集群A WireGuard节点的私钥> Address = 192.168.100.1/24 # 隧道内的专属IP,每个副本可以设不同值(比如192.168.100.1/2/3) ListenPort = 51820 # 集群B的WireGuard Peer,填集群B的LB IP [Peer] PublicKey = <集群B WireGuard节点的公钥> AllowedIPs = 10.1.0.0/16, 10.97.0.0/12 # 包含集群B的Pod和Service网段 Endpoint = <集群B WireGuard Service的LB IP>:51820 PersistentKeepalive = 25 # 保持隧道连接,避免NAT超时
集群B的wg0.conf反过来配置即可,AllowedIPs填集群A的Pod和Service网段,Endpoint填集群A的LB IP。如果是多副本,你可以给每个副本配置多个Peer(对方集群的所有WireGuard Pod),或者直接用对方的LB IP做Peer,LB会自动负载均衡到对方的WireGuard副本。
三、让其他Pod的流量通过WireGuard网关转发
你需要让集群内的Pod把发往对方集群的流量路由到WireGuard的ClusterIP,有两种方式:
1. 全局节点路由(适合所有Pod都需要跨集群访问)
在集群的每个节点上执行以下命令,把对方集群的网段路由到WireGuard的ClusterIP:
# 集群A执行,把集群B的网段指向WireGuard Service的ClusterIP ip route add 10.1.0.0/16 via <集群A WireGuard Service的ClusterIP> dev cni0
可以把这个命令加到节点的启动脚本里,避免节点重启后路由丢失。
2. 单个Pod路由(适合部分Pod需要跨集群访问)
在需要跨集群访问的Pod YAML里添加一个init容器,启动时自动添加路由:
initContainers: - name: set-vpn-route image: busybox:latest command: ["ip", "route", "add", "10.1.0.0/16", "via", "<集群A WireGuard Service的ClusterIP>"] securityContext: capabilities: add: ["NET_ADMIN"] # 需要NET_ADMIN权限修改Pod内的路由表
四、HA和负载均衡的优化细节
- 副本分布:用Deployment的
podAntiAffinity确保WireGuard副本分布在不同节点,避免单节点故障导致VPN中断 - 流量负载均衡:kube-proxy会自动把UDP流量负载均衡到所有WireGuard副本,配合
sessionAffinity: ClientIP减少隧道重建开销 - 监控告警:可以用Prometheus+Grafana监控WireGuard的连接状态、流量统计,确保所有副本都正常工作
这样一套配置下来,你就能实现两个Kubernetes集群通过多副本WireGuard网关的跨集群VPN,同时满足HA和负载均衡的需求了。
备注:内容来源于stack exchange,提问作者user3980196

