Container with LXC/LXD (2)

Date: 2023/11/12 (initial publish), 2024/03/15 (last update)

Source: en/note-00053.md

Previous Post Top Next Post

TOC

Here is a series of memos of me trying to use LXC/LXD on Debian 12 (bookworm).

Default LXD Debian image issues

Let me simply use the default LXD Debian image to launch d0 instance with:

 $ lxd launch images:debian/12/cloud d0

Then, the resulting d0 image has a few glitches to my taste:

Here are my efforts to get a sane instance generated.

./lxcinit: local fixed-up image generation command

I first created local image with primary user name set to osamu and without netdev in groups-list as deb-12-image:

 $ lxc init images:debian/12/cloud d0
 $ lxc file edit d0/etc/cloud/cloud.cfg
 $ lxc publish d0 --alias deb-12

Please note that the “write_files:” part in “user.user-data:” portion of YAML data is implemented by cloud-config in rather later part of its process. So trick to use this functionality to update /etc/cloud/cloud.cfg doesn’t work.

Later, in order to automate this, I created a script to fix its image: lxcinit. This removes netdev group and optionally changes the primary user to osamu for cloud-init.

$ lxcinit -h

=============================================================================
NAME:
  lxcinit -- download lxd Debian cloud image and make local fixed image
             "deb-<name>"

SYNOPSIS:
  lxcinit [-b|-d|-h|-p|-u|--] [<name>]

DESCRIPTION:
  lxcinit creates a local un-previlidged LXD image "deb-<name>" just like
  the following but with some fix-ups on /etc/cloud/cloud.cfg:

  $ lxc init images:debian/<name>/cloud deb-<name>
  $ lxc publish deb-<name> --alias=deb-<name>

  The default <name> is "sid".  The <name> consists of the codename or the
  release version:
    - "sid", "trixie", "bookworm", "bullseye", "buster", 12, 11, 10

  You can't have an existing instance name such as deb-<name> for this
  command to function.

OPTIONS: (only the first character matters)
  -base BASE  set base name as BASE ("deb-")
  -delete     delete unmodified instance deb-<name>
  -help       print this help message and exit
  -primary    match primary user name in container with the current user
  -update     update the local image deb-<name> after removing it first.

=============================================================================

This was an interesting practice for me to get familiar with lxc publish .... But TBH, this is a bit cumbersome to use. So I don’t use this much.

Configuration of LXD instance

Instead of fixing the image itself, I tried to generate properly configured instance with the existing configuration to minimize overhead.

We can launch a LXD instance in 2 ways using YAML data user.yaml.

The latter style using profile provides me with an organized working environment.

Overriding default_user of cloud-init with profile

The root cause of issue is default_user data provided as the default cloud-init setting and cloud-init automatically creates normal group if it finds missing group name in groups list. These can be seen in /etc/cloud/cloud.cfg as:

...
   default_user:
     name: debian
     lock_passwd: True
     gecos: Debian
     groups: [adm, audio, cdrom, dialout, dip, floppy, netdev, plugdev, sudo, video]
     sudo: ["ALL=(ALL) NOPASSWD:ALL"]
     shell: /bin/bash

I found out this feature is the intended feature, I needed to find an easy way to override this default setting.

I eventually found “Users and Groups” on cloud-init reference document. The “Summary” explanation was confusing for me. So I tried “Examples” to see how thisfeature can be used.

Test script users.sh

I created a simple shell script users.sh to test configuration.

#!/bin/sh -e
lxc stop d0 >/dev/null 2>&1 || true
lxc delete d0 >/dev/null 2>&1 || true
lxc ls -f compact | grep d0 || true
echo "I: ===== YAML data $1 ==========="
cat $1
echo "I: ===== launch d0 =============="
lxc launch images:debian/12/cloud d0 <$1
echo "I: ===== wait 3 sec ==="
sleep 3
echo "I: ===== check home directory ==="
lxc exec d0 -- ls -la /home
echo "I: ===== check /etc/passwd ======"
lxc exec d0 -- tail -n5 /etc/passwd
echo "I: ===== check /etc/group ======="
lxc exec d0 -- egrep -e "(adm|plugdev|netdev|osamu|debian)" /etc/group

NOTE: Instead of waiting for 3 seconds with sleep 3 and hoping for the start up process is finished, lxc exec d0 -- cloud-init status --wait may address this requirement better.

Override default_user settings (1)

The following simply sets users: to an empty list overrides default_user settings.

$ ./users.sh users0.yaml
I: ===== YAML data users0.yaml ===========
config:
  user.user-data: |
    #cloud-config
    users: []
I: ===== launch d0 ==============
Creating d0
Starting d0
I: ===== wait 3 sec ===
I: ===== check home directory ===
total 0
drwxr-xr-x 1 root root   0 Sep 29 20:04 .
drwxr-xr-x 1 root root 154 Nov 18 05:29 ..
I: ===== check /etc/passwd ======
_apt:x:42:65534::/nonexistent:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
messagebus:x:100:101::/nonexistent:/usr/sbin/nologin
systemd-network:x:998:998:systemd Network Management:/:/usr/sbin/nologin
systemd-resolve:x:997:997:systemd Resolver:/:/usr/sbin/nologin
I: ===== check /etc/group =======
adm:x:4:
plugdev:x:46:

This can avoid setting netdev to GID=1000 but can’t have the primary user.

Override default_user settings (2)

The following sets users: to a list with updated name: and groups: list overrides default_user settings.

$ ./users.sh users1.yaml
I: ===== YAML data users1.yaml ===========
config:
  user.user-data: |
    #cloud-config
    users:
    - name: osamu
      groups: [adm, mail]
I: ===== launch d0 ==============
Creating d0
Starting d0
I: ===== wait 3 sec ===
I: ===== check home directory ===
total 0
drwxr-xr-x 1 root  root   10 Nov 19 03:32 .
drwxr-xr-x 1 root  root  154 Nov 18 05:29 ..
drwxr-xr-x 1 osamu osamu  62 Nov 19 03:33 osamu
I: ===== check /etc/passwd ======
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
messagebus:x:100:101::/nonexistent:/usr/sbin/nologin
systemd-network:x:998:998:systemd Network Management:/:/usr/sbin/nologin
systemd-resolve:x:997:997:systemd Resolver:/:/usr/sbin/nologin
osamu:x:1000:1000::/home/osamu:/bin/sh
I: ===== check /etc/group =======
adm:x:4:osamu
mail:x:8:osamu
plugdev:x:46:
osamu:x:1000:

This can avoid setting netdev to GID=1000 and sets the primary user to osamu with reasonable UID/GID..

In order this to add “osamu” to all groups (excluding netdev) as the initial list, groups: [adm, audio, cdrom, dialout, dip, floppy, plugdev, sudo, video] should be used in user0.yaml instead.

Previous Post Top Next Post