Passa al contenuto principale

Create an Incus container

How to create and setup an Incus container.

Install Incus

Install it like this:

apt install --yes incus
apt install --yes btrfs-progs
incus --version
incus ls
note

We also make sure that btrfs-progs is installed, since we are going to use a Btrfs storage backend with incus.

Before we can create containers, we need to initialize Incus:

incus admin init
The output of this command looks like this:
Would you like to use clustering? (yes/no) [default=no]:
Do you want to configure a new storage pool? (yes/no) [default=yes]:
Name of the new storage pool [default=default]:
Name of the storage backend to use (btrfs, dir, lvm, zfs, ceph) [default=zfs]: *btrfs*
Create a new BTRFS pool? (yes/no) [default=yes]:
Would you like to use an existing empty block device (e.g. a disk or partition)? (yes/no) [default=no]:
Size in GB of the new loop device (1GB minimum) [default=30GB]: 70
Would you like to create a new local network bridge? (yes/no) [default=yes]:
What should the new bridge be called? [default=incusr0]:
What IPv4 address should be used? (CIDR subnet notation, “auto” or “none”) [default=auto]:
What IPv6 address should be used? (CIDR subnet notation, “auto” or “none”) [default=auto]: *none*
Would you like the server to be available over the network? (yes/no) [default=no]:
Would you like stale cached images to be updated automatically? (yes/no) [default=yes]
Would you like a YAML "init" preseed to be printed? (yes/no) [default=no]:
note

Almost all the answers here are the default ones. One of the answers that is different is this:

Name of the storage backend to use (btrfs, dir, lvm, zfs, ceph) [default=zfs]: *btrfs*

We are using btrfs for the storage backend, because we need to install Docker inside the container, and only this filesystem supports it efficiently.

Fix the firewall

If you use firewalld on the host, you need to fix it.

Any interface that is not explicitly added to a zone, is added to the default zone, which is the zone public. This zone is meant for the interfaces that are facing the public internet, so it is restricted. For example DHCP requests are blocked, and the containers cannot get an IP.

To fix this, we can add the bridge interface (incusbr0) to the trusted zone, where everything is allowed:

firewall-cmd --zone=trusted --list-all
firewall-cmd --zone=trusted \
--add-interface=incusbr0 --permanent
firewall-cmd --reload
firewall-cmd --zone=trusted --list-all

We should also make sure that forwarding is enabled:

firewall-cmd --permanent --direct --add-rule \
ipv4 filter FORWARD 0 -j ACCEPT
firewall-cmd --reload

firewall-cmd --direct --get-all-rules

To access Incus from a user other than root, add that user to the groups incus and incus-admin:

adduser myusername incus
adduser myusername incus-admin

Create a VM

Let's create an Ubuntu VM, named linux-cli:

incus launch images:ubuntu/noble linux-cli --vm

incus ls
incus info linux-cli
incus config show linux-cli
note

A virtual machine requires dedicated resources (RAM and CPU) from the host, while a container shares them with the host. So, a container is usually more efficient than a VM. However, a container sometimes has some limitations that a VM does not have. For the Linux course a container is OK, except for a couple of topics.

informazioni

By default, incus allocates to a VM only 1GB RAM and 1CPU, which should be fine for this course. If we want to assign more resources to it, we use config options like this:

incus launch images:ubuntu/noble linux-cli --vm \
-c limits.memory=4GB -c limits.cpu=2

The rest of the configuration for a VM is the same as the configuration for a container (see the following sections).

Create a container

Let’s create an Ubuntu container, named linux-cli:

incus launch images:ubuntu/noble linux-cli \
-c security.nesting=true \
-c security.syscalls.intercept.mknod=true \
-c security.syscalls.intercept.setxattr=true
incus list
incus list -c ns4t
incus info linux-cli
incus config show linux-cli
note

The configuration -c security.nesting=true is needed in order to run docker inside the container. However if the container is unprivileged, it does not really have any security implications.

Similarly, the other two configuration options are needed so that docker can handle images efficiently.

Setup the container

  1. Get a shell in the container:

    incus shell linux-cli
  2. Update/upgrade:

    apt update
    apt upgrade --yes
  3. Set a better prompt:

    sed -i ~/.bashrc \
    -e '/^#\?force_color_prompt=/ c force_color_prompt=yes' \
    -e '/bashrc_custom/d'

    echo 'source ~/.bashrc_custom' >> ~/.bashrc

    cat <<'EOF' > ~/.bashrc_custom
    # set a better prompt
    PS1='${debian_chroot:+($debian_chroot)}\[\033[01;31m\]\u\[\033[01;33m\]@\[\033[01;36m\]\h \[\033[01;33m\]\w \[\033[01;35m\]\$ \[\033[00m\]'
    EOF
  4. Enable bash-completion:

    apt install --yes bash-completion

    cat <<'EOF' >> ~/.bashrc_custom
    # enable programmable completion features
    if [ -f /etc/bash_completion ] && ! shopt -oq posix; then
    source /etc/bash_completion
    fi
    EOF
    source ~/.bashrc
  5. Make sure that vim is installed and enable its dark background setting:

    apt install --yes vim
    sed -i /etc/vim/vimrc \
    -e 's/^"set background=dark/set background=dark/'
  6. Create a user with username user1 and password pass1, and add it to group sudo:

    useradd -m -s /bin/bash -G sudo user1
    echo user1:pass1 | chpasswd

    Customize ~/.bashrc of user1:

    su - user1 -c \
    "sed -i ~/.bashrc -e '/^#force_color_prompt/ c force_color_prompt=yes'"
  7. Install some other packages:

    DEBIAN_FRONTEND=noninteractive
    apt install --yes \
    task-mate-desktop ubuntu-mate-core task-ssh-server

    apt install --yes \
    mandoc less info plocate bash-completion \
    wbritish highlight elinks ncal tree \
    nano jed vim emacs netcat-openbsd \
    iputils-ping traceroute iputils-tracepath \
    rsync aspell lynx highlight git tmux

Using the container

  • To enter the container as user user1 use this command:

    incus exec linux-cli -- bash -c "su - user1"
  • Try an alias like this in order to simplify the login:

    alias linux-cli='incus exec linux-cli -- bash -c "su - user1"'

    Now, whenever you type linux-cli you will get a shell inside the container.

    note

    Add this alias to ~/.bashrc to make it permanent.

suggerimento
  • Try sudo su to get root access inside the container.

  • If you need to recreate the container, you should stop and remove it first:

    incus stop linux-cli
    incus rm linux-cli