|
| 1 | += 三层网络IPAM |
| 2 | + |
| 3 | +ZStack IPAM 负责管理三层网络(L3)的 IP 地址分配与回收,支持以下三种方式: |
| 4 | + |
| 5 | +. 自动分配:ZStack 云平台根据 L3 网络配置的 IP range 自动分配。 |
| 6 | +. 手动分配:用户在创建云主机时手动指定 IP 地址。 |
| 7 | +. QGA 获取:通过 QEMU Guest Agent(QGA)从云主机内部读取并上报 IP 地址。 |
| 8 | + |
| 9 | +== 自动分配 |
| 10 | + |
| 11 | +自动分配需要满足以下两个条件: |
| 12 | + |
| 13 | +. L3 网络已配置 IP range。 |
| 14 | +. L3 网络已启用 DHCP 服务。 |
| 15 | ++ |
| 16 | +这是历史遗留行为:扁平网络使用 DHCP 服务作为自动分配功能的开关,其他网络类型不受影响。 |
| 17 | + |
| 18 | +系统根据用户输入的 L3 网络 UUID 以及可选的 IP 地址,按照分配算法分配一个可用地址。返回的地址信息包括:IP 地址、掩码(或前缀长度)、网关。 |
| 19 | + |
| 20 | +=== 自动分配算法 |
| 21 | + |
| 22 | +* 随机分配:从可用地址池中随机选择一个 IP 地址。 |
| 23 | +* 顺序分配:从可用地址池中按顺序选择一个 IP 地址。 |
| 24 | +* 循环分配:从可用地址池中按顺序分配,分配到最后一个 IP 后回到第一个 IP 继续分配。 |
| 25 | + |
| 26 | +=== 当前状况 |
| 27 | + |
| 28 | +Cloud 5.5 版本中: |
| 29 | + |
| 30 | +. 扁平网络有三种情况:无 IP range、有 IP range 且未启用 DHCP、有 IP range 且已启用 DHCP。 |
| 31 | +. 公有网络与 VPC 网络有两种情况:有 IP range 且未启用 DHCP、有 IP range 且已启用 DHCP。 |
| 32 | +. 管理网络与流量网络仅有一种情况:有 IP range 且未启用 DHCP。 |
| 33 | + |
| 34 | +=== 工作时机 |
| 35 | + |
| 36 | +以下操作会触发自动分配: |
| 37 | + |
| 38 | +. 创建云主机(`APICreateVmInstanceMsg`) |
| 39 | +. 云主机添加网卡(`APIAttachL3NetworkToVmMsg`, `APICreateVmNicMsg`) |
| 40 | +. 修改云主机 IP(`APISetVmStaticIpMsg`, `APIChangeVmNicNetworkMsg`) |
| 41 | +. 创建 appliance VM(`APICreateVpcVRouterMsg`, `APICreateSlbInstanceMsg`, `APICreateNfvInstMsg`) |
| 42 | +. 创建 VIP(`APICreateVipMsg`) |
| 43 | + |
| 44 | +== 手动分配 |
| 45 | + |
| 46 | +手动指定仅对云主机生效,对 appliance VM 不生效。 |
| 47 | + |
| 48 | +在前述场景 1、2、3 中,用户可以指定 IP 地址,分为两种情况: |
| 49 | + |
| 50 | +. 指定 IP 在 IP range 之内:后端仍执行自动分配流程。 |
| 51 | +. 指定 IP 不在 IP range 之内:按手动分配流程处理。 |
| 52 | +.. 如果指定 IP 不在 L3 CIDR 内,必须指定掩码,网关可选。 |
| 53 | +.. 如果指定 IP 在 L3 CIDR 内,可不指定掩码和网关;如指定,必须与 L3 CIDR 一致。 |
| 54 | + |
| 55 | +=== 工作时机 |
| 56 | + |
| 57 | +. 5.5.12 之前:扁平网络在“无 IP range”或“有 IP range 但未启用 DHCP”两种情况下,允许指定不在 IP range 内的地址。 |
| 58 | +. 5.5.12 及以后:任意网络都可通过修改云主机 IP(`APISetVmStaticIpMsg`, `APIChangeVmNicNetworkMsg`)设置不在 IP range 内的地址。 |
| 59 | + |
| 60 | +如果指定 IP 在 IP range 之外、但在 L3 CIDR 之内,则掩码和网关可不指定,系统会自动从 L3 CIDR 推导。 |
| 61 | + |
| 62 | +如果指定 IP 在 L3 CIDR 之外,用户必须同时提供 IP 与掩码(或前缀长度);若为默认网卡,还必须指定网关,且网关必须位于 L3 CIDR 内。 |
| 63 | + |
| 64 | +== QGA 获取 |
| 65 | + |
| 66 | +该方式需要开启全局配置 `VmGlobalConfig.ENABLE_VM_INTERNAL_IP_OVERWRITE`(默认值为 `false`)。 |
| 67 | + |
| 68 | +ZStack KVM Agent 会定期通过 QGA 从云主机内部读取 IP 地址。仅在扁平网络且无 IP range 时,会将读取到的 IP 分配给云主机;其他网络类型不受影响。 |
| 69 | + |
| 70 | +在其他情况下,如果 QGA 读取到的 IP 与云主机当前 IP 冲突,系统会产生告警。 |
| 71 | + |
| 72 | +== 配置虚拟机 Guest OS 的 IP 地址 |
| 73 | + |
| 74 | +配置虚拟机 Guest OS 的 IP 地址有三种方式: |
| 75 | + |
| 76 | +. DHCP:通过 DHCP 服务器动态分配 IP 地址。 |
| 77 | +. Cloud-init:在云主机创建时通过 Cloud-init 预配置 IP 地址。 |
| 78 | +. QGA:通过 QEMU Guest Agent 配置云主机内部网络参数。 |
| 79 | + |
| 80 | +=== DHCP |
| 81 | + |
| 82 | +ZStack 会在每个物理机启动分布式 DHCP Server。云主机启动后通过 `dhclient` 获取 IP 地址、DNS 等参数。 |
| 83 | + |
| 84 | +=== Cloud-init |
| 85 | + |
| 86 | +ZStack 会在每个物理机启动分布式 Userdata Server。云主机启动后通过 Cloud-init 获取 IP 地址、DNS 等参数。 |
| 87 | + |
| 88 | +=== QGA |
| 89 | + |
| 90 | +云主机安装 ZStack Guest Agent 后,系统在检测到 Guest Agent 首次启动时,会通过 QGA 配置云主机的 IP、DNS 等参数。 |
| 91 | + |
| 92 | +当用户在 UI 手动修改 IP(`APISetVmStaticIpMsg`, `APIChangeVmNicNetworkMsg`)后,后端 API 会触发一次 Guest OS 网络参数下发流程。 |
| 93 | + |
| 94 | +QGA 下发的参数包括: |
| 95 | + |
| 96 | +* IP 地址 |
| 97 | +* 掩码或前缀长度 |
| 98 | +* 网关 |
| 99 | +* DNS 服务器地址 |
| 100 | +* MTU |
| 101 | +* Hostname |
| 102 | + |
| 103 | +用户可通过全局配置 `GuestToolsGlobalProperty.GUESTTOOLS_VM_PORT_CONFIGFIELDS` 限制下发字段。 |
| 104 | + |
| 105 | +== 网络服务 |
| 106 | + |
| 107 | +当网卡地址不在 L3 IP range 内时,可分为“在 L3 CIDR 内”和“在 L3 CIDR 外”两种情况。 |
| 108 | + |
| 109 | +=== 在 L3 CIDR 内 |
| 110 | + |
| 111 | +该情况与“IP 在 L3 IP range 内”一致,网络服务不受影响。 |
| 112 | + |
| 113 | +=== 在 L3 CIDR 外 |
| 114 | + |
| 115 | +==== 安全组 |
| 116 | + |
| 117 | +安全组规则本身不依赖网卡 IP 是否位于 L3 CIDR 内,但需要用户谨慎设计规则,避免不符合预期。 |
| 118 | + |
| 119 | +==== DHCP |
| 120 | + |
| 121 | +如果网卡所属网络无 IP range,则不提供 DHCP 服务。 |
| 122 | + |
| 123 | +如果网卡所属网络有 IP range,ZStack 会启动 DHCP 服务,且 `dnsmasq` 配置要求指定一个 IP CIDR。 |
| 124 | + |
| 125 | +当网卡 IP 不在 DHCP 服务对应的 IP CIDR 内时,DHCP 模块下发配置时会过滤掉 CIDR 外地址。 |
| 126 | + |
| 127 | +==== EIP |
| 128 | + |
| 129 | +对于扁平网络,EIP 功能不受影响,可继续创建。 |
| 130 | + |
| 131 | +对于 VPC 网络,若 EIP 绑定的私网地址不在 L3 CIDR 内,VPC 路由器无法路由,网络不通。 |
| 132 | + |
| 133 | +为保证一致性,EIP 不能绑定 IP 不在 L3 CIDR 内的网卡;`APIGetEipAttachableVmNicsMsg` 也不会返回该类网卡。 |
| 134 | + |
| 135 | +==== Port Forwarding |
| 136 | + |
| 137 | +Port Forwarding 仅用于 VPC 网络。与 EIP 类似,若网卡 IP 不在 L3 CIDR 内,VPC 路由器无法路由,网络不通。 |
| 138 | + |
| 139 | +Port Forwarding 不能绑定 IP 不在 L3 CIDR 内的网卡;`APIGetPortForwardingAttachableVmNicsMsg` 也不会返回该类网卡。 |
| 140 | + |
| 141 | +==== Load Balancer |
| 142 | + |
| 143 | +与 EIP 类似,若网卡 IP 不在 L3 CIDR 内,网络不通。 |
| 144 | + |
| 145 | +`APIAddVmNicToLoadBalancerMsg`、`APIAddBackendServerToServerGroupMsg` 不能绑定 IP 不在 L3 CIDR 内的网卡。 |
| 146 | + |
| 147 | +`APIGetCandidateVmNicsForLoadBalancerServerGroupMsg`、`APIGetCandidateVmNicsForLoadBalancerMsg` 也不会返回该类网卡。 |
| 148 | + |
| 149 | +== 代码细节 |
| 150 | + |
| 151 | +=== APISetVmStaticIpMsg |
| 152 | + |
| 153 | +该 API 通过成员字段配置云主机 IP、掩码、网关等参数,并进行完整性校验: |
| 154 | + |
| 155 | +* 用户输入掩码与网关:以用户输入为准。 |
| 156 | +* 用户仅输入网关:若 IP 与网关均在 L3 CIDR 内,使用 L3 CIDR 掩码;否则报错。 |
| 157 | +* 用户仅输入掩码:若与 L3 CIDR 掩码一致,使用 L3 CIDR 网关;否则若网卡为默认网卡或唯一网卡,报错;否则使用输入掩码,网关置空。 |
| 158 | +* 用户未输入掩码和网关,且 IP 在 L3 CIDR 内:使用 L3 CIDR 的掩码与网关。 |
| 159 | +* 用户未输入掩码和网关,且 IP 在 L3 CIDR 外:报错。 |
| 160 | +* IPv6 与 IPv4 的逻辑一致。 |
| 161 | +* 对 DNS 参数:若 UI 传递 `NULL`,后端保持旧 DNS 参数不变。 |
| 162 | +* 对 DNS 参数:若 UI 传递 `""` 或 `[]`,后端删除旧 DNS。 |
| 163 | +* 其他情况仅允许传递合法 DNS 列表,后端会先删除旧 DNS,再配置新 DNS。 |
| 164 | + |
| 165 | +=== APIChangeVmNicNetworkMsg |
| 166 | + |
| 167 | +该 API 通过 System Tags 配置云主机 IP、掩码、网关等参数,并进行完整性校验: |
| 168 | + |
| 169 | +* 用户输入掩码与网关:以用户输入为准。 |
| 170 | +* 用户仅输入网关:若 IP 与网关均在 L3 CIDR 内,使用 L3 CIDR 掩码;否则报错。 |
| 171 | +* 用户仅输入掩码:若与 L3 CIDR 掩码一致,使用 L3 CIDR 网关;否则若网卡为默认网卡或唯一网卡,报错;否则使用输入掩码,网关置空。 |
| 172 | +* 用户未输入掩码和网关:若网卡存在相同 IP 版本地址,且输入 IP 在旧 IP 的掩码与网关组成 CIDR 内,则复用旧掩码与网关;否则若 IP 在 L3 CIDR 内,使用 L3 CIDR 掩码与网关;否则报错。 |
| 173 | +* IPv6 与 IPv4 的逻辑一致。 |
| 174 | +* 对 DNS 参数:若 UI 传递 `NULL`,后端保持旧 DNS 参数不变。 |
| 175 | +* 对 DNS 参数:若 UI 传递 `""` 或 `[]`,后端删除旧 DNS。 |
| 176 | +* 其他情况仅允许传递合法 DNS 列表,后端会先删除旧 DNS,再配置新 DNS。 |
| 177 | + |
| 178 | +=== APICreateVmInstanceMsg |
| 179 | + |
| 180 | +逻辑与 `APIChangeVmNicNetworkMsg` 相同。 |
| 181 | + |
| 182 | +=== APIGetL3NetworkIpStatisticMsg |
| 183 | + |
| 184 | +不统计位于 IP range 之外的 IP 地址。 |
| 185 | + |
| 186 | +=== APIAddIpRangeMsg |
| 187 | + |
| 188 | +系统允许给云主机设置不在 IP range 内的 IP,因此添加 IP range 时可能覆盖已分配 IP。此时会将这些已分配地址归属到新加入的 IP range。 |
| 189 | + |
| 190 | +=== APIAddReservedIpRangeMsg |
| 191 | + |
| 192 | +该 API 不仅会添加 `ReservedIpRangeVO`,还会将 `ReservedIpRangeVO` 与 IP range 重叠的地址写入 `UsedIpVO`。 |
| 193 | + |
| 194 | +[source,java] |
| 195 | +---- |
| 196 | +vo.setUsedFor(IpAllocatedReason.Reserved.toString()); |
| 197 | +---- |
| 198 | + |
| 199 | +=== APICheckIpAvailabilityMsg |
| 200 | + |
| 201 | +在 5.5.12 之前,该 API 在扁平网络未启用 DHCP 的情况下会跳过 IP range 检查;该行为保持不变。 |
| 202 | + |
0 commit comments