Skip to content

Instantly share code, notes, and snippets.

@Informatic
Last active April 9, 2024 07:09
Show Gist options
  • Star 61 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save Informatic/0b6b24374b54d09c77b9d25595cdbd47 to your computer and use it in GitHub Desktop.
Save Informatic/0b6b24374b54d09c77b9d25595cdbd47 to your computer and use it in GitHub Desktop.
cloud-init "nocloud" networking setup

cloud-init is absolute cancer. Its code is horrible. It has no documentation at all.

It took me 5 fucking hours to figure out how to properly configure networking on recent cloud-init (Ubuntu 16.04 cloud image) with local datasource.

It's not mentioned anywhere you need to provide dsmode: local. (but only if you need network-config, besides that everything is fine; someone below noted that -m flag does the same thing, good to know) Of course nobody needs documentation for network-config format either. (cloudinit/net/__init__.py is a protip, enjoy the feces dive)

Oh, and by the way - no, it's not possible to provide network-config to uvt-kvm without patching shit.

Use -N flag for cloud-localds for network-config.

dsmode: local
# ↑ THIS. SHIT.
---
version: 1
config:
- type: physical
name: ens3
subnets:
- control: auto
type: static
address: |
192.168.21.37
pre-up echo xD > /tmp/yesitsthereyo # quality configuration injection, real thing
#cloud-config
chpasswd:
list: |
root:password
expire: False
write_files:
- content: |
You don't really need that, just a bloody test.
path: /root/test.txt
@jsaenz1000
Copy link

I also was stumped by this but if you delete the /etc/cloud/cloud.cfg.d/99-fake-cloud.cfg (I may have the name wrong slightly) file, Cloud-Init will then respect your user-data network configuration. I came about the solution from following @wintermute000's advice (Neuromancer is my favorite book BTW!) about deleting and re-installing cloud-config and noticed that file is missing when you do that.

@chris-mccoy
Copy link

Thank you everyone for your help with this! It definitely pointed me in the right direction. I was chasing my tail with Proxmox VE with a custom version 2 (Netplan using the systemd-networkd renderer) network-config on an Ubuntu 22.04 VM. Everything pointed to cloud-init being the problem, but despite modifying the PVE code to add the dsmode: local setting to the meta-data-generating source code, it just did not work. What I learned was cloud-init would tell netplan to render the networkd configuration to /run/systemd/network but it wouldn't actually start the network. It depended on systemd to do that.

I found out my network-config was just bad. I was trying to use set-name: eth0 without matching on a MAC address. Which strangely wouldn't work on bootup, but would work by running netplan apply manually.

If you find your network just isn't coming up, check out what networkctl is telling you and see if the interface is managed or not. Check your configuration and the system journal and make sure systemd-networkd is happy.

@StudioLE
Copy link

StudioLE commented Apr 1, 2023

@chris-mccoy I'm running into a similar issues to what you were experiencing.

I found out my network-config was just bad. I was trying to use set-name: eth0 without matching on a MAC address. Which strangely wouldn't work on bootup, but would work by running netplan apply manually.

One thing I've found is instead of matching on mac address it's simpler to match by name

#cloud-config

network:
  version: 2
  ethernets:
    eth0:
      set-name: eth0
      match:     
        name: en*

@StudioLE
Copy link

StudioLE commented Apr 1, 2023

@chris-mccoy

Thank you everyone for your help with this! It definitely pointed me in the right direction. I was chasing my tail with Proxmox VE with a custom version 2 (Netplan using the systemd-networkd renderer) network-config on an Ubuntu 22.04 VM. Everything pointed to cloud-init being the problem, but despite modifying the PVE code to add the dsmode: local setting to the meta-data-generating source code, it just did not work. What I learned was cloud-init would tell netplan to render the networkd configuration to /run/systemd/network but it wouldn't actually start the network. It depended on systemd to do that.

According to the proxmox docs (see --citype) the nocloud datasource is used for linux which doesn't support the dsmode setting. Only the configdrive datasource supports dsmode: local as far as I can tell.

My workaround has been to conditionally call netplan apply from the bootcmd which is called early in the (source) cloud-init execution order. That way the package sources are updated on first boot and packages can be installed as standard.

#cloud-config

bootcmd:
  - if [ ! -f /root/first-run-complete ]; then netplan apply; fi

runcmd:
  - touch /root/first-run-complete

apt:
  preserve_sources_list: true
package_update: true
package_upgrade: true
package_reboot_if_required: true
packages:
  - git

@chris-mccoy
Copy link

@StudioLE nice, thank you! 🙏

@mcbenjemaa
Copy link

mcbenjemaa commented Aug 8, 2023

@StudioLE
I want to set a static ip address with nocloud but that doesn't work, on proxmox.
I'm mounting the cloud-init data using an ISO cd drive.
Do you have a workaround?

I have put this in metadata and user data, but that doesn't work.

network:
    version: 2
    ethernets:
        eth0:
            match:     
              name: en*
            set-name: eth0
            addresses: [10.10.10.84/32]
            gateway4: 10.10.10.1
            nameservers:
              addresses:
                - 8.8.8.8
                - 8.8.4.4

@StudioLE
Copy link

StudioLE commented Aug 8, 2023

@mcbenjemaa

Instead of relying on cloud-init's network configuration I've opted to write the netplan configuration from the user-config.ymlusing write_files and it's applied from a per-instance script.

Full disclosure though I have ditched Proxmox in favour of Multipass but the cloud-init logic will be the same.

Here are the relevant lines:

#cloud-config

write_files:
- path: /etc/netplan/10-custom.yaml
  content: |
    network:
      version: 2
      ethernets:
        extra0:
          dhcp4: no
          match:
            macaddress: C8:36:54:11:11:11
          addresses:
          - 10.0.1.2/24
          - fc00::0:1:2/112
          routes:
          - to: default
            via: 10.0.1.1
            metric: 50
          - to: default
            via: fc00::0:1:1
            metric: 50
- path: /var/lib/cloud/scripts/per-instance/30-network-configure
  permissions: 0o500
  content: |
    #!/bin/bash
    set -uo pipefail

    echo-success () {
      echo -e "\e[32m ✔  $1\e[0m" >&2
    }

    echo-information () {
      echo -e "\e[34m ⓘ  $1\e[0m" >&2
    }

    echo-error () {
      echo -e "\e[31m !  $1\e[0m" >&2
    }

    echo-warning () {
      echo -e "\e[33m ⚠  $1\e[0m" >&2
    }

    echo-subsidiary () {
      echo -e "\e[37m    $1\e[0m" >&2
    }

    echo-step () {
      echo -e "\e[0m »  $1\e[0m" >&2
    }

    echo-step "Applying Netplan configuration"
    if netplan apply
    then
      echo-success "Applied Netplan configuration"
    else
      echo-error "Failed to apply netplan configuration"
    fi

@StudioLE
Copy link

StudioLE commented Aug 8, 2023

@StudioLE I want to set a static ip address with nocloud but that doesn't work, on proxmox. I'm mounting the cloud-init data using an ISO cd drive. Do you have a workaround?

I have put this in metadata and user data, but that doesn't work.

network:
    version: 2
    ethernets:
        eth0:
            match:     
              name: en*
            set-name: eth0
            addresses: [10.10.10.84/32]
            gateway4: 10.10.10.1
            nameservers:
              addresses:
                - 8.8.8.8
                - 8.8.4.4

The indentation isn't consistent in your example, I'm not sure if that may be causing issues? In some places you're using 4 spaces and others 2 spaces.

Also worth noting that gateway4: is deprecated you should use default routes instead.

Rewriting your example would look something like this:

network:
  version: 2
  ethernets:
    eth0:
      match:     
        name: en*
      set-name: eth0
      addresses: 
      - 10.10.10.84/32
      routes:
      - to: default
        via: 10.10.10.1
      nameservers:
        addresses:
          - 8.8.8.8
          - 8.8.4.4

@StudioLE
Copy link

StudioLE commented Aug 8, 2023

@mcbenjemaa

I think the CIDR you're using for your address is incorrect too. 10.10.10.84/32 should be 10.10.10.84/24 It should match the network range of the gateway whereas /32 is restricted to just a single IP.

Netplan example:
https://github.com/canonical/netplan/blob/main/examples/static.yaml#L7
Docs:
https://netplan.readthedocs.io/en/stable/netplan-tutorial/#using-static-ip-addresses

@mcbenjemaa
Copy link

mcbenjemaa commented Aug 9, 2023

should i put this in the network-config file?

The network-config is not working, I only see the default cloud-init dhcp config.

the script you provided adds the 10-custom.yaml but there's still 50-cloud-init.yaml by default.

it doesn't change the IP, should I disable it?

@mcbenjemaa
Copy link

@StudioLE , thanks for your suggestion.

I have this working now. 💯

#cloud-config
hostname: proxmox-test-control-plane
manage_etc_hosts: true
user: ionos
chpasswd:
  expire: false
users:
  - default
package_upgrade: true

write_files:
  - path: /etc/cloud/cloud.cfg.d/99-custom-networking.cfg
    permissions: '0644'
    content: |
      network: {config: disabled}

  - path: /etc/netplan/99-custom.yaml
    content: |
      network:
        version: 2
        renderer: networkd
        ethernets:
          eth0:
            dhcp4: no
            addresses:
            - 10.10.10.66/24
            routes:
            - to: default
              via: 10.10.10.1
            nameservers:
              addresses: [8.8.8.8, 8.8.4.4]

  - path: /var/lib/cloud/scripts/per-instance/30-network-configure
    permissions: 0o500
    content: |
        #!/bin/bash
        set -uo pipefail
        
        echo-success () {
          echo -e "\e[32m ✔  $1\e[0m" >&2
        }
        
        echo-information () {
          echo -e "\e[34m ⓘ  $1\e[0m" >&2
        }
        
        echo-error () {
          echo -e "\e[31m !  $1\e[0m" >&2
        }
        
        echo-warning () {
          echo -e "\e[33m ⚠  $1\e[0m" >&2
        }
        
        echo-subsidiary () {
          echo -e "\e[37m    $1\e[0m" >&2
        }
        
        echo-step () {
          echo -e "\e[0m »  $1\e[0m" >&2
        }
        
        echo-step "Applying Netplan configuration"
        if netplan apply
        then
          echo-success "Applied Netplan configuration"
        else
          echo-error "Failed to apply netplan configuration"
        fi

@pentiumoverdrive
Copy link

@StudioLE I want to set a static ip address with nocloud but that doesn't work, on proxmox. I'm mounting the cloud-init data using an ISO cd drive. Do you have a workaround?
I have put this in metadata and user data, but that doesn't work.

network:
    version: 2
    ethernets:
        eth0:
            match:     
              name: en*
            set-name: eth0
            addresses: [10.10.10.84/32]
            gateway4: 10.10.10.1
            nameservers:
              addresses:
                - 8.8.8.8
                - 8.8.4.4

The indentation isn't consistent in your example, I'm not sure if that may be causing issues? In some places you're using 4 spaces and others 2 spaces.

Also worth noting that gateway4: is deprecated you should use default routes instead.

Rewriting your example would look something like this:

network:
  version: 2
  ethernets:
    eth0:
      match:     
        name: en*
      set-name: eth0
      addresses: 
      - 10.10.10.84/32
      routes:
      - to: default
        via: 10.10.10.1
      nameservers:
        addresses:
          - 8.8.8.8
          - 8.8.4.4

Thank you!
Saved me hours of hair pulling trying to build images without dhcpd.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment