Cloud-init in LXD 4.21

I’m struggling new key of cloud-in “cloud-init.network-config” which was supported in 4.21.
I was just going through cloud-init - LXD documentation to setup static IP address by cloud-init, but still no luck.
What is I’m wrong or missing here?

Here is LXD version and default profile, described what I did step by step.

# lxd --version 
4.21
# lxc profile show default
config: {}
description: Default LXD profile
devices:
  eth0:
    name: eth0
    network: lxdbr0
    type: nic
  eth1:
    name: eth1
    nictype: bridged
    parent: br0
    type: nic
  root:
    path: /
    pool: default
    type: disk
name: default
used_by: []

Create new container with ubuntu20.04 image and apply custom network configuration with cloud-init.

# lxc init ubuntu:20.04 c0
# cat c0-network.yaml
version: 1
config:
  - type: physical
    name: eth0
    subnets:
      - type: static
        ipv4: true
        address: 192.168.244.20/24
        netmask: 255.255.255.0
        gateway: 192.168.244.1
        control: auto
  - type: nameserver
    address: 10.128.8.22
# cat c0-network.yaml | lxc config set c0 cloud-init.network-config -

Applied configuration seems to be OK below.

# lxc config show c0
architecture: x86_64
config:
  cloud-init.network-config: |
    version: 1
    config:
      - type: physical
        name: eth0
        subnets:
          - type: static
            ipv4: true
            address: 192.168.244.20/24
            netmask: 255.255.255.0
            gateway: 192.168.244.1
            control: auto
      - type: nameserver
        address: 10.128.8.22
  image.architecture: amd64
  image.description: ubuntu 20.04 LTS amd64 (release) (20211129)
  image.label: release
  image.os: ubuntu
  image.release: focal
  image.serial: "20211129"
  image.type: squashfs
  image.version: "20.04"
  volatile.apply_template: create
  volatile.base_image: a8402324842148ccfcbacbc69bf251baa9703916593089f0609e8d45e3185bff
  volatile.eth0.hwaddr: 00:16:3e:43:d2:94
  volatile.eth1.hwaddr: 00:16:3e:f0:4c:06
  volatile.idmap.base: "0"
  volatile.idmap.next: '[{"Isuid":true,"Isgid":false,"Hostid":1000000,"Nsid":0,"Maprange":1000000000},{"Isuid":false,"Isgid":true,"Hostid":1000000,"Nsid":0,"Maprange":1000000000}]'
  volatile.last_state.idmap: '[]'
  volatile.uuid: 13505685-2c2d-4571-9116-aab53f8bfaf5
devices: {}
ephemeral: false
profiles:
- default
stateful: false
description: ""

Then start container, however cloud-init I set was not applied.

# lxc start c0
# lxc list         
+------+---------+------------------------+------+-----------+-----------+
| NAME |  STATE  |          IPV4          | IPV6 |   TYPE    | SNAPSHOTS |
+------+---------+------------------------+------+-----------+-----------+
| c0   | RUNNING | 192.168.244.202 (eth0) |      | CONTAINER | 0         |
+------+---------+------------------------+------+-----------+-----------+

# lxc exec c0 cat /etc/netplan/50-cloud-init.yaml 
# This file is generated from information provided by the datasource.  Changes
# to it will not persist across an instance reboot.  To disable cloud-init's
# network configuration capabilities, write a file
# /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg with the following:
# network: {config: disabled}
network:
    version: 2
    ethernets:
        eth0:
            dhcp4: true

Anything missing and wrong?

BTW, although it was same configuration file, but worked with “user.network-config” instead of "cloud-init.network-config below.

# lxc init ubuntu:20.04 c0
# cat c0-network.yaml         
version: 1
config:
  - type: physical
    name: eth0
    subnets:
      - type: static
        ipv4: true
        address: 192.168.244.20/24
        netmask: 255.255.255.0
        gateway: 192.168.244.1
        control: auto
  - type: nameserver
    address: 10.128.8.22
# cat c0-network.yaml | lxc config set c0 user.network-config -
# lxc start c0
# lxc list
+------+---------+-----------------------+------+-----------+-----------+
| NAME |  STATE  |         IPV4          | IPV6 |   TYPE    | SNAPSHOTS |
+------+---------+-----------------------+------+-----------+-----------+
| c0   | RUNNING | 192.168.244.20 (eth0) |      | CONTAINER | 0         |
+------+---------+-----------------------+------+-----------+-----------+
root@mds08:~# lxc exec c0 cat /etc/netplan/50-cloud-init.yaml 
# This file is generated from information provided by the datasource.  Changes
# to it will not persist across an instance reboot.  To disable cloud-init's
# network configuration capabilities, write a file
# /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg with the following:
# network: {config: disabled}
network:
    version: 2
    ethernets:
        eth0:
            addresses:
            - 192.168.244.20/24
            gateway4: 192.168.244.1
            nameservers:
                addresses:
                - 10.128.8.22
                search: []

Any ideas @monstermunchkin ?

@sihara I see you are using the ubuntu:20.04 image. Does the same happen if you use images:ubuntu/20.04/cloud?

1 Like

@monstermunchkin Yeah, I did dobule-check with images:ubuntu/20.04/cloud, but it’s still same problem.
In fact, I started to see that issue with images:centos/7/cloud image, then went back ubuntu:20.04 to confirm if it worked, but didn’t work neither.
It looks like cloud-init.user-data seems to be working below though.

root@mds08:~# cat c0-write_files.yaml 
#cloud-config
write_files:
    - content: |
          This is test.
      path: /tmp/testfile

root@mds08:~# lxc init images:ubuntu/20.04/cloud c0
root@mds08:~# cat c0-write_files.yaml | lxc config set c0 cloud-init.user-data -
root@mds08:~# lxc config show c0 
architecture: x86_64
config:
  cloud-init.user-data: |
    #cloud-config
    write_files:
        - content: |
              This is test.
          path: /tmp/testfile

< - snip ->

root@mds08:~# lxc start c0
root@mds08:~# lxc exec c0 cat /tmp/testfile
This is test.

In fact, content of /var/lib/cloud/seed/nocloud-net/user-data in the image was updated in this case properly.

root@mds08:~# lxc exec c0 cat /var/lib/cloud/seed/nocloud-net/user-data
#cloud-config
write_files:
    - content: |
          This is test.
      path: /tmp/testfile

However, what I’m seeing problem with cloud-init.network-config that /var/lib/cloud/seed/nocloud-net/network-config in the image was never updated in any cases.

@sihara I can reproduce the issue you have. It’s caused by a bug in distrobuilder. Once this PR is merged, and new images have been built, the problem will go away.

@monstermunchkin cool, that’s great to hear what you found a root cause. thanks for prompt fix.
btw, according to doc cloud-init - LXD documentation, cloud-init is enabled by default in ubuntu and ubuntu-daily images. that’s correct, right? at least, I can confirm.

root@mds08:~# lxc init ubuntu:20.04 c0
root@mds08:~# lxc start c0
root@mds08:~# lxc exec c0 cloud-init status
status: done

@monstermunchkin this seems to be another related issue.
The regardless whether if cloud-init triggered, cloud-init.user-data can’t be populated into ubuntu:20.04 image somehow. It can be populated on image images:ubuntu/20.04/cloud though.
See below.

root@mds08:~# lxc init ubuntu:20.04 c0
root@mds08:~# lxc init images:ubuntu/20.04/cloud c1
root@mds08:~# cat cloud-init-write_files.yaml 
#cloud-config
write_files:
    - content: |
          This is test.
      path: /tmp/testfile

root@mds08:~# cat cloud-init-write_files.yaml | lxc config set c0 cloud-init.user-data -
root@mds08:~# cat cloud-init-write_files.yaml | lxc config set c1 cloud-init.user-data -

root@mds08:~# lxc config show c0 
architecture: x86_64
config:
  cloud-init.user-data: |
    #cloud-config
    write_files:
        - content: |
              This is test.
          path: /tmp/testfile

root@mds08:~# lxc config show c1
architecture: x86_64
config:
  cloud-init.user-data: |
    #cloud-config
    write_files:
        - content: |
              This is test.
          path: /tmp/testfile


root@mds08:~# lxc start c0
root@mds08:~# lxc start c1
root@mds08:~# lxc exec c0 cat /var/lib/cloud/seed/nocloud-net/user-data
#cloud-config
{}

root@mds08:~# lxc exec c1 cat /var/lib/cloud/seed/nocloud-net/user-data
#cloud-config
write_files:
    - content: |
          This is test.
      path: /tmp/testfile

The ubuntu: images require cloud-init to support the cloud-init.* config keys. Although the code has been merged upstream, there hasn’t been a release since then. If you need to use the ubuntu: images, you should use the old user.*config keys for now.

Just found this as I was confused as well and seeing mixed information between ubuntu: vs images:

Is there a recommendation to use one over the other?

According to @monstermunchkin answer, my understanding is that if you want to use cloud-init.* config keys with images, you still need to pick image from images:<distro>/<version>/cloud, otherwise ubuntu: image is fine. But, you have to keep user.* config keys for those ubuntu: images until cloud-init.* config keys supported images will be released.