本文适用场景:vSphere 实验室 / NSX 试验环境 / vSphere with Kubernetes / VCF 演示
涉及版本:物理 ESXi 7.0/8.0/9.0,嵌套 ESXi 6.7/7.0/8.0
阅读时长:约 7 分钟
一、排错日记:今天又踩了一遍这个坑
今天下午在搭 vSphere with Kubernetes 实验环境,在物理 ESXi 8.0 上装了一台嵌套 ESXi 8.0,里面再装 vCenter + Supervisor Cluster。
配好 vSphere Distributed Switch、开了 NSX,部署 Tanzu 时报 "TKG cluster waiting for node IP"。
第一反应:DHCP 配错了?去看 NSX Segment 的 DHCP 配置,没问题;去看 DHCP 服务器日志,完全没有请求记录。
第二反应:VM 网卡没接上?进嵌套 ESXi 看 VM 状态,网络适配器显示已连接,但 VM 里跑ip addr看不到任何 IP。
第三反应:打开嵌套 ESXi 的 vSphere Client → 选中那台 VM → Edit Settings → VM Options → Advanced → 看网卡 MAC,改成 static 试一下,居然通了。
——好家伙,问题不在 DHCP,在DHCP Discover 包根本没出去。然后翻了下 vSphere 文档,真相大白:
嵌套虚拟化的 VM 发出的广播包,默认会被物理 vSwitch 丢掉,除非你在 vSwitch 端口组上开启Promiscuous Mode(混杂模式)。
踩完坑顺便记一下,后面再有人问就直接甩链接。
二、原理:为什么嵌套 VM 拿不到 DHCP?
DHCP 工作流程是广播 Discover → Offer → Request → ACK,整个过程都是二层广播。
在嵌套虚拟化场景下,数据包路径是这样的:
[嵌套 VM] │ 发 DHCP Discover 广播(目的 MAC: ff:ff:ff:ff:ff:ff) ▼ [嵌套 ESXi 虚拟网卡(vmxnet3)] │ 广播包 ▼ [物理 ESXi 的 vSwitch 端口组] │ ⚠️ 这里被丢了! ▼ [物理网卡 vmnic] ▼ [上游交换机 → DHCP 服务器]vSwitch 默认会丢弃所有目标 MAC 不是该端口组已知 VM 的广播包(安全考虑,防 MAC flooding 攻击)。但 DHCP 是广播,目标 MAC 是 ff:ff:ff:ff:ff:ff,vSwitch 不认识这个 MAC,直接丢弃。
解决办法:让 vSwitch 端口组接受所有 MAC 地址的包——也就是混杂模式(Promiscuous Mode)。
三、3 种解决方式,从轻到重
方式 1:在 vSwitch 端口组开 Promiscuous Mode(推荐,90% 场景适用)
标准 vSwitch(7.0/8.0 通用):
# 临时生效(重启 ESXi 后失效) esxcli network vswitch standard portgroup set \ --portgroup-name "Nested-Network" \ --promiscuous-mode true # 验证 esxcli network vswitch standard portgroup list # 看 "Promiscuous Mode" 列是否为 truevSphere Distributed Switch(VC 管理):
# PowerShell + PowerCLI(批量改) Get-VDPortgroup "Nested-Network" | %{ $_.ExtParam = @{ "PromiscuousMode" = $true } $_.ApplyExtParam() } # 或者直接改安全策略(手动): # vSphere Client → Networking → Distributed Switch → 端口组 # → Edit Settings → Policies → Security → Promiscuous Mode → Accept⚠️ 安全提醒:混杂模式开启后,该端口组上的 VM 可以看到所有流过物理网卡的流量(含其他 VM 的)。实验环境无所谓,生产环境慎重。
方式 2:在嵌套 ESXi 上配 DHCP 中继(适合复杂网络)
如果你的嵌套环境有多个 VLAN、跨网段 DHCP,需要在嵌套 ESXi 上配 DHCP Relay:
# 进嵌套 ESXi 的 SSH,查看 VMkernel 端口 esxcli network ip interface list # 配置 DHCP Relay(需要在 NSX Edge 或物理路由器上配) # 不是 ESXi 直接配,而是要在 Tier-0/Tier-1 Gateway 上配 DHCP Relay这种方式在 VCF + NSX 环境里很常见,但配起来相对复杂,适合 POC 演示用。
方式 3:绕过 DHCP,用静态 IP(最快但只适合测试)
# 进 VM 操作系统手动配 IP # Linux: ip addr add 192.168.10.100/24 dev eth0 ip route add default via 192.168.10.1 # Windows: netsh interface ip set address "Ethernet" static 192.168.10.100 255.255.255.0 192.168.10.1 netsh interface ip set dns "Ethernet" static 192.168.10.1适合临时调试,不推荐生产用。
四、关键前置:嵌套 ESXi 虚拟硬件配置
除了开混杂模式,嵌套 ESXi 本身也要配对几个地方,否则连 VM 都起不来:
# 1. 物理 ESXi 上嵌套 ESXi 的 VM 配置: # - CPU: 启用 "Expose hardware assisted virtualization" # - CPU: 启用 "Expose IOMMU to guest OS" # - 内存: 至少 8GB,推荐 16GB+ # - 虚拟磁盘: 提供 100GB+ 给嵌套 ESXi # # 2. 嵌套 ESXi 内的 VM 配置: # - 虚拟网卡必须用 vmxnet3(不要用 e1000) # - 启用 "Mac Address Changes" 安全策略 = Accept # - 启用 "Forged Transmits" 安全策略 = AcceptPowerCLI 一键配置嵌套 ESXi 的 VM(在物理 ESXi 上跑):
# 把嵌套 ESXi 的 VM 配置成最佳实践 Get-VM "Nested-ESXi-01" | %{ $spec = New-Object VMware.Vim.VirtualMachineConfigSpec $spec.NestedHVEnabled = $true # CPU 配置 $cpuSpec = New-Object VMware.Vim.VirtualMachineConfigSpec $cpuSpec.CpuFeatureMask = @(@{ "level" = "0x4"; "featureName" = "hv-vapic" }, @{ "level" = "0x4"; "featureName" = "hv-mvp" }) # 网卡改成 vmxnet3 Get-NetworkAdapter -VM $_ | Set-NetworkAdapter -Type Vmxnet3 $_.ReconfigVM($spec) }五、验证:确认 DHCP 包能出去了
# 在物理 ESXi 上抓包(最直观) pktcap-uw --vmknic vmnic0 --dir 0 --stage 0 \ --filter "udp port 67 or 68" \ -o /tmp/dhcp.pcap # 把 pcap 拷出来用 Wireshark 打开 # 应该看到 DHCP Discover 包从嵌套 VM 的 MAC 地址发出如果能看到 Discover 包但收不到 Offer,问题在 DHCP 服务器;如果连 Discover 都看不到,问题在 vSwitch 混杂模式没开。
六、速查命令卡(可收藏转发)
# 1. 开混杂模式(标准 vSwitch) esxcli network vswitch standard portgroup set \ --portgroup-name "你的端口组名" \ --promiscuous-mode true # 2. 验证混杂模式 esxcli network vswitch standard portgroup list # 3. 抓 DHCP 包验证 pktcap-uw --vmknic vmnic0 --dir 0 \ --filter "udp port 67 or 68" \ -o /tmp/dhcp.pcap # 4. PowerCLI 配嵌套 ESXi 的 VM 硬件 Get-VM "Nested-ESXi-01" | %{ $spec = New-Object VMware.Vim.VirtualMachineConfigSpec $spec.NestedHVEnabled = $true Get-NetworkAdapter -VM $_ | Set-NetworkAdapter -Type Vmxnet3 $_.ReconfigVM($spec) } # 5. 兜底:用静态 IP(临时调试) ip addr add 192.168.10.100/24 dev eth0