Incus
Incus can be used to manage system containers, application containers, and virtual machines.
1. Get a volume
The disk space on our VPS is almost full, so we need to get a volume from Hetzner, that we can use for Incus. A volume is like a virtual disk, that can be attached to our VPS.
Let's say that the size of the disk is 50 GB. Later we can resize it
and make it larger, if needed. Set the name of the volume to "incus"
and click on the mount option: Manually
. Then click on the button
"Create & Buy Now".
On the VPS, we can use this command to check the presence of the disk:
lsblk
Unformatting the disk
If we chose by mistake the mount option "Automatic", the new disk will be formated and mounted inside the VPS. We don't want this -- for Incus we need an unmounted and unformatted disk. To correct this we can delete the disk and create a new one. But we can also unmount and unformat it manually, like this:
lsblk
umount /dev/sdb
lsblk
dd if=/dev/zero of=/dev/sdb count=1 bs=1M
We also have to edit /etc/fstab
and comment out (or delete) the line
that mounts the disk.
2. Install Incus
We can install it from the Zabbly package repository:
-
Get the key of the repository:
mkdir -p /etc/apt/keyrings/
curl -fsSL https://pkgs.zabbly.com/key.asc \
-o /etc/apt/keyrings/zabbly.asc -
Add the package repository to the list of sources:
cat <<EOF > /etc/apt/sources.list.d/zabbly-incus.sources
Enabled: yes
Types: deb
URIs: https://pkgs.zabbly.com/incus/stable
Suites: bookworm
Components: main
Architectures: amd64
Signed-By: /etc/apt/keyrings/zabbly.asc
EOF
cat /etc/apt/sources.list.d/zabbly-incus.sources -
Install the package
incus
:apt update
apt install incus
incus --version
incus ls -
Make sure that
btrfs-progs
is also installed, since we are going to use a Btrfs storage backend with incus:apt install btrfs-progs
3. Initialize Incus
Before we can create containers, we need to initialize Incus:
incus admin init
We use the default answers for almost all the questions. The important questions are these:
-
--> Name of the storage backend to use:
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. Besides, deduplication features of Btrfs make it possible to use less disk space (or to use the disk space more efficiently).
-
--> Would you like to use an existing empty block device?
yes
We are using the second disk as a storage for the Incus containers.
-
--> Path to the existing block device:
/dev/sdb
-
--> What IPv6 address should be used?
none
We are disabling IPv6 for the containers; we don't need it.
4. Networking
The connection of the Incus containers to the Internet goes through
the host. The bridge network incusbr0
can be thought as a switch,
which provides DHCP service for the containers that are connected to
it. It also works as a gateway for them and provides NAT.
4.1 Fix the Firewall
In firewalld
(that is installed on the server), any interface that
is not explicitly added to a zone, is handled by the default zone,
which is the zone public
. This zone is meant for the interfaces that
are facing the public internet, so it has restrictions.
The bridge interface of Incus (incusbr0
) is also handled by default
by the restricted public
zone. As a result, DHCP requests are
blocked, and the containers cannot get an IP.
-
Test networking in a container.
If we create a test container, we will notice that the network in the container is not working:
incus launch images:ubuntu/24.04 u24
incus ls
incus exec u24 -- ip addrThe container did not get an IP, as it normally should.
-
However, if we stop
firewalld
and restart the container, everything works fine:systemctl status firewalld
systemctl stop firewalld
incus restart u24
incus ls
incus exec u24 -- ip addr
incus exec u24 -- ping 8.8.8.8
systemctl start firewalld
systemctl status firewalldSo the problem is that the firewall is not configured properly.
Make sure that IP forwarding is enabled
By the way, IP forwarding should already be enabled in the kernel of the host:
sysctl net.ipv4.ip_forward
cat /proc/sys/net/ipv4/ip_forwardIf it is not, enable it like this:
echo 'net.ipv4.ip_forward = 1' >> /etc/sysctl.conf
sysctl -p -
Let's fix this problem by adding the bridge interface 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 -
Check that it is working:
incus restart u24
incus ls
incus exec u24 -- ip addr
incus exec u24 -- ping 8.8.8.8noteIf the ping is still not working, usually the problem is that forwarding is blocked. Try this command:
iptables-save | grep FORWARD
If you see something like this:
:FORWARD DROP [4:2508]
, it means that the policy for the FORWARD chain is DROP (maybe it is set by Docker).We can make the default policy ACCEPT, like this:
iptables -P FORWARD ACCEPT
However, the next time that the server is rebooted, or firewalld restarted, we may loose this configuration.
-
Let's 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 -
Let's test again that networking works, and then clean up the test container:
incus exec u24 -- ping 8.8.8.8
incus stop u24
incus rm u24
incus ls
4.2 Limit DHCP range
Incus containers usually get an automatic IP from the DHCP that is
provided by incusbr0
. Sometimes we need to set a fixed IP to some
containers. To avoid any possible IP conflicts between the fixed IP
and the automatic IPs issued by DHCP, we should limit the range of the
DHCP IPs, and make sure that the fixed IPs are outside the DHCP range.
Let's modify the DHCP range on the configuration of incusbr0
:
incus network show incusbr0
incus network get incusbr0 ipv4.address
incus network set incusbr0 \
ipv4.dhcp.ranges 10.148.0.2-10.148.0.200
incus network get incusbr0 ipv4.dhcp.ranges
incus network show incusbr0