cloud-init Network Configuration v2: Static IPs and Bonds - 夜莺博客

cloud-init Network Configuration v2: Static IPs and Bonds

Provisioning a VM with DHCP works until the day you need a fixed address, a bond, or a management interface in a specific VLAN — and then a boot-time network mistake means a machine you cannot reach to fix. cloud-init's network configuration handles all of this before user-space services start, and, crucially, the configuration survives reboots. This guide covers the version 2 format, matching interfaces reliably, and debugging the first boot when the machine never appears on the network.

Version 1 vs version 2

cloud-init supports two network config formats. Version 1 is the original list-based format; version 2 mirrors netplan's YAML syntax and is the preferred choice on Ubuntu 18.04+ (and on any distro where cloud-init renders netplan output). If you are writing new configuration, write version 2 — it supports ethernets, bonds, bridges and vlans as first-class device types.

Minimal static configuration

# /etc/cloud/cloud.cfg.d/99-custom-network.cfg
network:
  version: 2
  renderer: networkd
  ethernets:
    ens3:
      dhcp4: false
      dhcp6: false
      addresses:
        - 10.0.0.10/24
      routes:
        - to: default
          via: 10.0.0.1
          metric: 100
      nameservers:
        addresses: [10.0.0.53, 8.8.8.8]
        search: [internal.example.com]

Note the modern route form (to: default plus via:) rather than the deprecated gateway4 key — on current netplan, gateway4 produces a warning and will eventually be removed.

Matching interfaces reliably

Interface names are not stable across hypervisors and hardware: ens3 on one host is enp1s0 on the next. In a VM template this is the single most common cause of a boot that comes up with no address. Match on MAC and rename:

network:
  version: 2
  ethernets:
    primary-nic:
      match:
        macaddress: "52:54:00:1a:2b:3c"
      set-name: eth0
      dhcp4: false
      addresses: [10.0.1.50/24]
      routes:
        - to: default
          via: 10.0.1.1
      nameservers:
        addresses: [10.0.1.1]

Multiple NICs, a bond and a VLAN

network:
  version: 2
  ethernets:
    mgmt:
      match: {macaddress: "52:54:00:aa:01:01"}
      set-name: eth0
      dhcp4: true
    stor-a:
      match: {macaddress: "52:54:00:aa:01:02"}
      set-name: eth1
    stor-b:
      match: {macaddress: "52:54:00:aa:01:03"}
      set-name: eth2
  bonds:
    bond0:
      interfaces: [eth1, eth2]
      addresses: [10.20.0.30/24]
      parameters:
        mode: 802.3ad
        lacp-rate: fast
        mii-monitor-interval: 100
        transmit-hash-policy: layer3+4
      mtu: 9000
  vlans:
    vlan100:
      id: 100
      link: bond0
      addresses: [192.168.100.20/24]

Matching on MAC plus explicit set-name keeps storage interfaces stable even if the hypervisor reorders PCI slots — and a storage bond that silently pairs the wrong two NICs is a performance incident waiting to happen.

Where to put it: cloud-config vs networkData

#cloud-config
hostname: web-server-01
users:
  - name: ubuntu
    sudo: ALL=(ALL) NOPASSWD:ALL
    ssh_authorized_keys:
      - ssh-ed25519 AAAA... admin@host
packages: [qemu-guest-agent, nginx]
runcmd:
  - systemctl enable --now qemu-guest-agent
  • NoCloud datasource — put the network YAML in a separate network-config file next to user-data on the seed ISO or in the VM's cloud-init drive.
  • Kubernetes / KubeVirt / Harvester — the same YAML goes in the networkData field of a cloudInitNoCloud volume or secret.
  • Proxmox VE — use the cloud-init drive and provide the custom network configuration in the UI's cloud-init network editor, which writes exactly this format.

Debugging a first boot that never appears on the network

# From the hypervisor console
cloud-init status --long
cloud-init query --all | head
cat /var/log/cloud-init.log
cat /var/log/cloud-init-output.log
journalctl -u cloud-init --no-pager | tail -50
cloud-init schema --config-file /etc/cloud/cloud.cfg.d/99-custom-network.cfg --annotate

cloud-init schema catches the most common class of failure — a typo'd key that YAML parses happily and netplan then ignores. Two further rules save time:

  1. Keep custom files in /etc/cloud/cloud.cfg.d/ with a numeric prefix; changing an existing vendor file gets overwritten on package upgrade.
  2. If a datasource supplies network config, it takes precedence over your file. Check /run/cloud-init/ for the rendered copy actually applied on this boot.

Validate the YAML on a throwaway VM before templating it. Five minutes of cloud-init schema beats twenty minutes of console recovery on a production host.

Related Reading on This Site

原文链接:https://oneuptime.com/blog/post/2026-03-02-how-to-configure-network-settings-with-cloud-init-on-ubuntu/view (OneUptime - Configure network settings with cloud-init on Ubuntu)