Skip to content

Instantly share code, notes, and snippets.

@Informatic
Last active July 22, 2024 20:06
Show Gist options
  • 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
@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.

@vbisalahalli
Copy link

You are my savior!!

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