Go up

lxc

2022/06/17

Knowledge


Example

user@host ~> cat /proc/self/cgroup                                                                                                                                              1
0::/user.slice/user-1000.slice/session-1.scope

user@host ~> systemd-run --user --scope --collect --shell                                                                                                                       1
Running scope as unit: run-r7f23525aef1e46c0aa667f4b2b2a5705.scope

user@host ~> cat /proc/self/cgroup
0::/user.slice/user-1000.slice/user@1000.service/app.slice/run-r7f23525aef1e46c0aa667f4b2b2a5705.scope

user@host ~> lxc-create -t download -n penguin -- --dist debian --release bullseye --arch amd64
Using image from local cache
Unpacking the rootfs

---
You just created a Debian bullseye amd64 (20220603_05:24) container.

To enable SSH, run: apt install openssh-server
No default root or user password are set by LXC.

user@host ~> lxc-ls --fancy
NAME    STATE   AUTOSTART GROUPS IPV4 IPV6 UNPRIVILEGED
firefox STOPPED 0         -      -    -    true
spyder  STOPPED 0         -      -    -    true
penguin STOPPED 0         -      -    -    true

user@host ~> lxc-start penguin

user@host ~> lxc-attach penguin --clear-env

root@penguin:/# cat /etc/os-release
PRETTY_NAME="Debian GNU/Linux 11 (bullseye)"
[...]

user@host ~> lxc-ls --fancy
NAME    STATE   AUTOSTART GROUPS IPV4 IPV6 UNPRIVILEGED
firefox STOPPED 0         -      -    -    true
spyder  STOPPED 0         -      -    -    true
penguin RUNNING 0         -      -    -    true

user@host ~> lxc-stop penguin

user@host ~> lxc-destroy penguin

user@host ~> lxc-ls --fancy
NAME    STATE   AUTOSTART GROUPS IPV4 IPV6 UNPRIVILEGED
firefox STOPPED 0         -      -    -    true
spyder  STOPPED 0         -      -    -    true

If you do not execute systemd-run you will get an error like the following:

user@host ~> lxc-start firefox -F
Failed to mount cgroup at /sys/fs/cgroup/systemd: Operation not permitted
[!!!!!!] Failed to mount API filesystems.
Exiting PID 1...

Basic commands

lxc

Common options

lxc-ls

lxc-ls [-1] [--active] [--frozen] [--running] [--stopped] [--defined] [-f] [-F format] [-g groups] [--nesting=NUM] [--filter=regex]
lxc-ls --fancy
---
NAME    STATE   AUTOSTART GROUPS IPV4 IPV6 UNPRIVILEGED
firefox STOPPED 0         -      -    -    true
gui     STOPPED 0         -      -    -    true

lxc-start

lxc-start {-n name} [-f config_file] [-c console_device] [-L console_logfile] [-d] [-F] [-p pid_file] [-s KEY=VAL] [-C]
          [--share-[net|ipc|uts] name|pid] [command]
lxc-start --foreground --name firefox --logfile=/tmp/test/log --logpriority=DEBUG

lxc-attach

lxc-attach {-n, --name name} [-f, --rcfile config_file] [-a, --arch arch] [-e, --elevated-privileges privileges]
           [-s, --namespaces namespaces] [-R, --remount-sys-proc] [--keep-env] [--clear-env]
           [-v, --set-var variable] [--keep-var variable] [-u, --uid uid] [-g, --gid gid] [-- command]
lxc-attach -n firefox --clear-env
lxc-attach -n firefox --clear-env --uid 1000 -- firefox

lxc-create

lxc-create {-n name} [-f config_file] {-t template} [-B backingstore] [-- template-options]
lxc-create penguin -t download
lxc-create -t download -n firefox -- --dist debian --release bullseye --arch amd64

lxc-console

lxc-console {-n name} [-e escape character] [-t ttynum]
lxc-console -n test

Ctrl+a q to exit.

lxc-info

lxc-info {-n name} [-c KEY] [-s] [-p] [-i] [-S] [-H]
lxc-info firefox

lxc-stop

lxc-stop {-n name} [-W] [-r] [-t timeout] [-k] [--nokill] [--nolock]
lxc-stop firefox

lxc-destroy

lxc-destroy {-n name} [-f] [-s]
lxc-destroy -n test

lxc-checkconfig

lxc-checkconfig

Check the current kernel for lxc support

This indicates there is not support for cgroups v1.

[...]
Cgroup v1 systemd controller: missing
Cgroup v1 freezer controller: missing
Cgroup ns_cgroup: required
[...]

lxc-checkpoint

lxc-checkpoint {-n name} {-D PATH} [-r] [-s] [-v] [-d] [-F]

systemd

systemd-run

systemd-run --user --scope --collect --shell
systemd-run --user --scope --collect lxc-start container
systemd-run --unit=myshell --user --scope -p "Delegate=yes" lxc-start --name penguin --foreground
systemd-run --unit=myshell1 --user --property=AllowedCPUs=0,1 -p TasksMax=100 -p Delegate=yes lxc-start -n penguin

For more info check man systemd-run and man systemd.resource-control.

Show current systemd scope.

cat /proc/self/cgroup
---
0::/user.slice/user-1000.slice/user@1000.service/app.slice/run-r463d33efe17540179ac04d01f657faaa.scope

lxc config

Defaults

~/.config/lxc/defaults.conf
---

Network

/etc/lxc/lxc-usernet
---

Enable cpu, cpuset and io delegation

By default, a non-root user can only get memory controller and pids controller to be delegated.

See the currently allowed delegations.

cat /sys/fs/cgroup/user.slice/user-$(id -u).slice/user@$(id -u).service/cgroup.controllers
---
memory pids

To allow delegation of other controllers such as cpu, cpuset, and io, run the following commands:

sudo mkdir -p /etc/systemd/system/user@.service.d
cat <<EOF | sudo tee /etc/systemd/system/user@.service.d/delegate.conf
[Service]
Delegate=cpu cpuset io memory pids
EOF
sudo systemctl daemon-reload

Delegating cpuset is recommended as well as cpu. Delegating cpuset requires systemd 244 or later.

After changing the systemd configuration, you need to re-login or reboot the host. Rebooting the host is recommended.


Privileged containers as root (default)

UID 0 inside the container is UID 0 outside the container.


GUI without mapping the user

Configure subuid & subgid

Authorize your UIDs to map ranges of UIDs from its namespace into child namespaces.

You can write only user:100000:100000 but I wanted to do it differently as I have a different setup.

/etc/subuid
---
root:1000000:65536
lxd:1065536:65536
user:1131072:65536
/etc/subgid
---
root:1000000:65536
lxd:1065536:65536
user:1131072:65536

user:1131072:65536 means that user users can map 65536 UIDs from 1131072, so from 1131072 to 1196608.

You need to reboot to apply the changes.

Some people only map 65530 but that will brake the system as user nobody uses 65534 and it is needed.

Allow the user to map network devices

Allow user user to create up to 30 veth (virtual ethernet) devices connected to the virbr2 network bridge.

/etc/lxc/lxc-usernet
---
yu veth virbr2 30

Change the default configuration for the containers

~/.config/lxc/default.conf
---
lxc.net.0.type = veth
lxc.net.0.link = virbr2
lxc.net.0.flags = up
lxc.net.0.hwaddr = 00:16:3e:xx:xx:xx
lxc.idmap = u 0 1131072 65536
lxc.idmap = g 0 1131072 65536

Configure the host

pulseaudio

Configure pulseaudio to create a socket at /run/user/1000/pulse-socket

/etc/pulse/default.pa
    load-module module-native-protocol-unix auth-anonymous=1 socket=/run/user/1000/pulse-socket

Restart pulseaudio.

rm -rf /tmp/pulse* /run/user/1000/pulse* ~/.pulse* ~/.config/pulse
pulseaudio -k
pulseaudio --start

Wayland

Nothing, it already creates the socket at /run/user/1000/wayland-1.

GPU

Get the character

ls -la /dev/dri/                                                                                                                                                   1
---
drwxr-xr-x   3 root root        100 Jun 17 11:21 .
drwxr-xr-x  20 root root       4460 Jun 17 15:37 ..
drwxr-xr-x   2 root root         80 Jun 17 11:21 by-path
crw-rw----+  1 root video  226,   0 Jun 17 11:21 card0
crw-rw-rw-   1 root render 226, 128 Jun 17 11:21 renderD128

card0 and rederD128 only do 3D acceleration, they do not output video. card1 does output video but I do not have it.

ACLs

Allow the UID 1131072 (0 inside the container) access to mount (--x) /run/user/1000 and UID 1132072 (1000 inside the container) to write (rwx) to wayland and pulseaudio.

setfacl -m u:1131072:--x /run/user/1000
setfacl -m u:1132072:rwx /run/user/1000/wayland-1
setfacl -m u:1132072:rwx /run/user/1000/pulse-socket

Create and configure the container

Create the container

lxc-create -t download -n firefox -- --dist debian --release bullseye --arch amd64

Map the required sockets into the container. The last three lines are only needed for 3D rendering.

~/.local/share/lxc/firefox/config
---
lxc.mount.entry = /run/user/1000/pulse-socket home/user/1000/pulse-socket none bind,create=file,rw 0 0
lxc.mount.entry = /run/user/1000/wayland-1 home/user/1000/wayland-1 none bind,create=file,rw 0 0
lxc.mount.entry = /dev/dri/renderD128 dev/dri/renderD128 none bind,create=file,rw 0 0
lxc.cgroup2.devices.allow = c 226:128 rwm
lxc.cgroup2.devices.allow = c 226:0 rwm

Start the container and attach

lxc-start firefox
lxc-attach firefox --clear-env

Set up the container

Fix the terminal.

export TERM=xterm-256color

Install dependencies.

apt update
apt install -y xwayland weston x11-apps mesa-utils pulseaudio firefox-esr

Configure pulseaudio.

/etc/pulse/client.conf
---
default-server = unix:/home/user/1000/pulse-socket

Create new user.

useradd -u 1000 -m user
echo "user:user" | chpasswd
passwd -u user

As the folder /home/user already exists no new files are created so copy the skel directory into the user’s home.

cp /etc/skel/.bash_logout /home/user/.bash_logout
cp /etc/skel/.bashrc /home/user/.bashrc
cp /etc/skel/.profile /home/user/.profile

Configure required environment variables.

/home/user/.bashrc
---
export TERM=xterm-256color
export XDG_RUNTIME_DIR=/home/user/1000
export WAYLAND_DISPLAY=wayland-1
export QT_QPA_PLATFORM=wayland
export DISPLAY=:0
export MOZ_ENABLE_WAYLAND=1

Make sure all files are owned by the user.

chown user:user /home/user
chmod 0750 /home/user
chown user:user /home/user/1000

Start the GUI app.

su user -l -c firefox

Sources


🡹 Go to top