隔离VPC标准路径:出公网链路的设计与实现

随着托管 VPC、三方子公司 VPC 及沙箱类业务规模的扩大,隔离 VPC 逐渐成为云网络承载敏感业务的默认形态。本文分析了隔离 VPC 出公网场景下传统 SNAT 模式的结构性缺陷,提出以 EIP 网关为统一公网身份绑定点的标准路径方案,并从控制面(LBC isolated 模式)与数据面(DPVS isolate_public)两侧阐述其设计与实现。

一、背景

公司云平台上的 隔离VPC受合规约束,其网络模型必须满足三个条件:

  1. 默认拒绝 :业务与其他内网域(10/11 段)之间不建立任何隐式通路,互通必须显式申请;2. 公网身份专属 :出公网的源地址必须是业务专属的隔离公网 IP,禁止混用平台公共出口------这是 EIP 绑定关系、计费归属与安全策略生效的前提;3. 路径可审计:每一条放行的访问关系都能映射到明确的策略与工单。

满足以上约束的 VPC 即隔离 VPC。隔离机制的实现选择在安全组层面,采用"BASE 放行 + VPC 兜底拒绝"的两层策略模型。

由此形成三条默认策略:

🔹 入向 :classiclink 打通的流量默认放行,由安全组策略做细粒度控制;🔹 出向 :本 VPC 网段允许;10/8、11/8 内其他网段拒绝;基础架构 IP(DNS 等)白名单放行;🔹 出公网:转发面不限制,但源地址经 SNAT 转换为隔离公网 IP,在公网身份层面完成二次隔离。

选择安全组而非独立转发面的原因:实现成本最低,粒度最广(VM 维度 + 优先级语义),且与既有 ACL 工单体系天然衔接。

二、现状与问题

2.1 已有标准路径体系

经过数年建设,隔离 VPC 的跨域访问已形成覆盖三个方向的标准路径矩阵:

其中出公网路径支撑了沙箱、托管业务等所有隔离 VPC 的对外访问,是使用频度最高、链路最复杂的一条。

2.2 传统 SNAT 模式的两个缺陷

传统(normal)SNAT 模式下,同一 snat_rule 的各 SNAT 网关绑定互不相同的 公网EIP,并由每台网关独立完成 BGP 宣告。该模型在隔离 VPC 场景下存在结构性缺陷:

**公网IP浪费:**同一个隔离网段落在不同的SNAT网关,必须使用不同的公网IP,来保证出入同台。一般来说,集群中有几台机器,就至少有几个公网IP,对于只能加白极少数IP的业务,就无法其满足。

**无法统一公网出口:**当前架构公网有统一入口,即EIP网关。但SNAT网关需要通过BGP 宣告将回程流量吸入,导致出口有SNAT和EIP两个。

2.3 方案选型

改造方案的选择上有过权衡:让 SNAT 网关直接做 EIP 绑定(保持直出,回程由每台网关各自宣告),还是引入独立的 EIP 网关作为统一出口。前者省去了隧道开销,但公网身份分散在各网关,绑定与计费策略需要在每个转发点落地,路径不可审计;后者将公网身份收敛到单一绑定点,代价是控制面需要新增端口块编排能力、数据面需要 VXLAN 二次封装。综合评估后选择后者,即把"EIP 归属"从转发面剥离为独立职责。

三、方案设计

标准出公网路径由四项核心决策构成:

端口块分配算法(确定性 NAT):总端口空间 1025--65500(64476 个),按 max_snat_nodes 预切为等长 block,每台 master 网关独占一个 block;控制面将 (网关 IP, port_low, port_high) 三元组持久化至 WanIPPortAlloc 表,并同步至 EIP 网关用于回程映射。

该设计把"运行时端口协商"问题转化为"控制面静态规划"问题:任一会话的源端口必然落在其承载网关的 block 内,EIP 网关只需按 (wan_ip, 端口区间) 二元组即可确定回程隧道,无需维护会话状态。

配套的一致性约束:

  1. max_snat_nodes 禁止在线变更 ------block 边界为配置的派生值,运行期变更将导致已分配 block 与新边界错位重叠;2. block 只增不缩 ------网关下线后其 block 不回收,保留索引位以维持分配记录稳定性;3. 上限显式化------网关规模超出 max_snat_nodes 时以错误码 PORT_BLOCKS_EXHAUSTED 拒绝,禁止运行时重切 block。

四、整体架构与实现

4.1 端到端编排视图

业务视角的开通流程完全声明式:建 snat_rule → 建 wan_ip(mode=isolated),其余由平台自动编排。

4.2 控制面:LBC isolated 模式

入口为创建 wan_ip 时的 mode: "isolated"(idc 必填,控制面据此区分传统路径与 isolated 路径)。编排流程如下:

流程要点:

🔹 网关发现 :从 etcd 在线 Agent 注册信息中过滤 role=master 的 SNAT 网关(GetMasterSnatAgents),无可用网关时返回 NO_MASTER_AGENT 并回滚 wan_ip,保证不产生半配置状态;🔹 端口映射下发 :调用 fipctl 新增的 snat-port-mapping 接口,按网关粒度下发 (floating_ip, port_range, snat_node_ip) 三元组;fipctl 落自身 etcd 后由 Agent 异步执行 fipadm snatadd,完成 EIP 网关侧的回程映射;🔹 弹性扩容:新增网关通过 POST /lvs/v2.0/wanips/{id}/port-allocs 从空闲 block 中补分配;block 耗尽时显式报 PORT_BLOCKS_EXHAUSTED,不做隐式扩容。

fipctl 地址按机房路由(fipctl_urls 的 idc → URL 映射)。需要指出的是,调用时取不到地址会整段跳过仅记 warn 日志------fipctl 不可用不阻塞主流程是设计取舍,代价是漏配静默失败,应在初始化阶段补齐存在性校验。

三条一致性约束:

  1. max_snat_nodes 禁止在线变更 ------block 边界按当前配置实时派生,已有 isolated wan_ip 运行期改值会导致已分配 block 与新边界错位重叠。该值必须在首批 isolated wan_ip 创建前固化;2. block 只增不缩 ------网关下线后其 block 不回收,保留索引位以维持分配记录稳定性;3. 上限显式化------网关规模超出 max_snat_nodes 时以 PORT_BLOCKS_EXHAUSTED 拒绝,禁止运行时重切 block 的"自愈"行为。

4.3 数据面:DPVS isolate_public

标记下发链路。 控制面将 isolate_public 标记自 keepalived 配置起,经 dpvs_dest_compat 兼容结构跨进程传递,最终落到每个 worker lcore 的 dp_vs_dest 上供数据面逐包读取;EIP 网关隧道端点由 nat_gw_ip / nat_gw_vni 全局配置(v3 起支持 per-dest 覆盖)定义:

nginx 复制代码
# keepalived.conf --- RS 粒度声明
real_server 10.1.1.11 0 {
    vni   100011
    hip   10.16.0.166
    isolate_public          # 该 VM 公网流量统一牵引至 EIP 网关
}

# dpvs.conf --- EIP 网关隧道端点
vtep_ip_defs {
    nat_gw_ip  10.220.30.1
    nat_gw_vni 7000001
}

去程:三段式出路径决策。 去程封装位于 __dp_vs_out_xmit_snat4(),在 SNAT 源地址改写完成后按优先级三段判断:

三段设计的意义在于存量路径零变更:未打标记的 RS 保持原路径逐字节不变,这是"追加模式"类改造能够安全上线的前提。

回程:去标记化与 MAC 方向交换。 回程封装位于 __dp_vs_xmit_snat4(),沿请求进入的原隧道返回 VM,内层以太网头按方向交换(dmac/smac 对调)。实现上存在两条由故障教训固化下来的不变量:

不变量 1 · 回程判断去标记化回程仅依据连接自身携带的隧道属性(conn->vxlan_id、vtep_peer_addr),不读取 dest->isolate_public。RS 标记可能被 keepalived 重载在连接存活期内改写,而回程隧道在建连时即已确定------依赖标记将导致标记变更后存量连接回包路径错误。

不变量 2 · 内层 MAC 按方向交换请求方向内层帧为 src=VM_MAC / dst=GW_MAC,回程必须对调,否则 VM 侧直接丢弃。实现上利用 vxlan_encap() 的 (dmac, smac) 参数序,回程调用点交换实参顺序即可完成。

关键陷阱:SNAT 方向语义与直觉相反。 SNAT 模式下连接由内网 VM 发起,dp_vs_in() 将 VM→公网方向标记为 DPVS_CONN_DIR_OUTBOUND (对应 conn->packet_out_xmit),而公网→VM 的回包方向为 INBOUND(对应 conn->packet_xmit)------与"入请求/出响应"的直觉相反。v1 版本按函数名直觉将封装挂载于 FNAT 出路径(__dp_vs_out_xmit_fnat4),而隔离公网 VM 的流量归属 SNAT 服务,根本不会进入该路径,最终整体回退。

配套机制:sapool 端口区间。 数据面配合控制面的端口块规划:inet_ifaddr 新增 sapool_low / sapool_high 并透传至 sa_pool_create(),源端口仅在区间内分配。Agent 侧下发命令相应演变为:

bash 复制代码
dpip addr add {ip}/32 dev dpdk0 sapool low {port_low} high {port_high}

该命令的 low/high 参数与控制面 WanIPPortAlloc 记录中的端口块一一对应,多实例部署下各网关的源端口区间互不重叠,从机制上消除了 EIP 网关侧的四元组冲突。同时 isolated 模式下 Agent 跳过 BGP 宣告流程(wan_ip 的可达性由 EIP 网关负责)。

五、故障定位

上述编排链路同时定义了故障域边界,排障时按段定位:

值得强调的是 fipctl_urls 漏配这类静默失败:控制面调用被跳过而不报错,故障在链路末端才显现,排查成本远高于 fail-fast。因此对跨系统依赖的配置项,应在初始化阶段做存在性校验,而非依赖运行期日志。

六、后续计划

✅ fipctl_urls 等跨系统配置项增加初始化期存在性校验,将静默失败转为 fail-fast;✅ backup SNAT 节点参与端口块分配与自动故障转移;✅ 端口块支持动态缩容与回收,配合网关下线流程闭环;✅ Agent 健康检查与异常节点自动摘除,降低人工介入


相关推荐
紫金桥软件1 小时前
紫金桥国产组态软件:安全稳定护航工业现场
数据库·自动化·跨平台·scada·组态软件
qq_436962181 小时前
金蝶云星空数据分析怎么做?
java·数据库·数据分析
非凡ghost1 小时前
Photo Supreme:专业高效的照片收藏管理专家
服务器·前端·人工智能·电脑·软件需求
碧海银沙音频科技研究院1 小时前
基于炬芯ATS308X的BLE 无线方式离线日志传输导出功能实现
java·linux·服务器
gz927cool1 小时前
在 Harness 上搭建 Agent-Native 应用:可迁移经验
服务器·人工智能·ai·系统架构
坐吃山猪1 小时前
ChromaDB09-数据库操作
数据库·chromadb
IntoTech英途汇骏1 小时前
数据虚拟化平台选型分析:主流厂商解决方案与技术能力对比
数据库
Android系统攻城狮1 小时前
Linux Gstreamer深度解析之gst_audio_aggregator_set_sink_caps调用流程与实战(九十一)
linux·运维·服务器·gstreamer音视频·音视频进阶
nece0012 小时前
win10家庭版安装Android模拟器(AVD 安卓虚拟设备)
android·模拟器