VMware guest customization can write /etc/netplan/99-netcfg-vmware.yaml. If the template already has another active netplan file, the host can end up with multiple network authorities.

That can break routing, DNS, bootstrap scripts, Kubernetes node communication, and storage initialization.

Symptoms

Common signs:

Error: Conflicting default route declarations for IPv4
first declared in nic0 but also in ens192

or:

Destination Host Unreachable

or DNS search drift like:

resolv_conf_search = .
netplan_search = []

Inspect Netplan Ownership

ls -l /etc/netplan
sudo grep -R "routes:\|gateway\|search:" /etc/netplan -n

If both a template file and VMware file are present, decide which one owns networking.

Example conflict:

/etc/netplan/01-template-static.yaml
/etc/netplan/99-netcfg-vmware.yaml

Verify Active Routing

ip -br addr
ip route
networkctl status ens192 --no-pager

If the default route is missing, test the expected route manually:

sudo ip route replace default via 192.0.2.1 dev ens192
ping -c 3 192.0.2.1

If ARP fails, compare the vSphere port group against a working VM:

govc device.ls -vm /DC-Site-A/vm/K8s-Cluster/NonProd/cluster-a-worker-01
govc device.ls -vm /DC-Site-A/vm/K8s-Cluster/NonProd/cluster-a-worker-02

Normalize To One Netplan File

If VMware customization is the current network authority, keep only the VMware-generated file:

if [ -f /etc/netplan/99-netcfg-vmware.yaml ]; then
  for f in /etc/netplan/*.yaml /etc/netplan/*.yml; do
    [ -f "$f" ] || continue
    case "$f" in
      /etc/netplan/99-netcfg-vmware.yaml)
        echo "keeping $f"
        ;;
      *)
        echo "removing $f"
        rm -f "$f"
        ;;
    esac
  done
fi

Then validate and apply:

sudo netplan generate
sudo netplan apply
ip route
resolvectl status

Important Shell Detail

If this is run through Ansible shell, remember that /bin/sh may execute the script. Bash-only syntax such as [[ ... ]] can fail:

/bin/sh: 47: [[: not found

Use POSIX [ ... ] syntax or explicitly run the script with Bash.

Operating Model

Pick one owner:

  • VMware customization owns primary NIC, hostname, gateway, and DNS.
  • Bootstrap owns additional storage NICs and iSCSI-specific netplan.
  • Cloud-init userdata runs bootstrap and avoids competing with network ownership.

The failure pattern is usually not one bad command. It is multiple systems trying to own the same network configuration.

If VMware customization owns DNS, make sure Terraform separates the VM identity domain from resolver search suffixes. See Terraform vSphere DNS Search Suffix Ownership.