Why Aren't You Using Incus to Create Containers and Virtual Machines?

Incus

Virtual machines remain the main building block of pretty much all infrastructure. We tend to forget about the technology and just how entrenched it is in our daily technical lives. Ok, that’s a pretty heavy statement for a blog post, but I do think we forget about virtual machines and just how valuable and secure the technology is–most public cloud services are loss leaders for the VM part of their business.

Anyways, what I want to talk about is Incus, a way to easily create containers AND virtual machines.

NOTE: I use Incus to exclusively create virtual machines, and don’t use the container functionality that much. I would imagine that most people use the container functionality more. So while I’ll touch on the system container functionality, I use Incus for local VMs.

What is Incus?

When using Incus, you can manage your instances (containers and VMs) with a simple command line tool, directly through the REST API or by using third-party tools and integrations. Incus implements a single REST API for both local and remote access. The Incus project was created by Aleksa Sarai as a community driven alternative to Canonical’s LXD. Today, it’s led and maintained by many of the same people that once created LXD. - Incus Docs

With Incus, you can easily create virtual machines and containers.

I don’t know all the history of the project, where it comes from in terms of LXD/LXC, etc, but I do know that I need a way to easily create virtual machines on my local computer, and that I really enjoy using Incus. So easy.

Example of creating a virtual machine:

incus launch ubuntu:22.04 my-server --vm

It’s that easy. Especially on Ubuntu 24.04, where you can just install the incus package from the default repositories.

I also alias the incus command to this script because I always forget the incus command syntax, and I’m super lazy. So this would create a default sized VM with just vm launch my-vm.

#!/bin/bash

launch_vm() {
  if [ -z "$1" ]; then
    echo "Usage: $0 launch <vm-name>"
    echo "Example: $0 launch my-ubuntu-vm"
    exit 1
  fi

  local name="$1"
  local cpu=2
  local memory="4GiB"
  local disk="40GiB"

  incus launch images:ubuntu/24.04 "$name" --vm \
    --device root,size="$disk" \
    -c limits.cpu="$cpu" \
    -c limits.memory="$memory"
}

list_vms() {
  incus ls
}

show_help() {
  echo "Usage: $0 <command> [options]"
  echo
  echo "Commands:"
  echo "  launch <vm-name>  Launch a new VM"
  echo "  ls                List all VMs"
  echo "  help              Show this help message"
  echo
  echo "For other commands, this script will pass them directly to incus."
}

# Main command handler
case "$1" in
  launch)
    launch_vm "$2"
    ;;
  ls)
    list_vms
    ;;
  help)
    show_help
    ;;
  *)
    if [ -z "$1" ]; then
      show_help
    else
      # If the command isn't recognized, pass it to incus
      incus "$@"
    fi
    ;;
esac

Using Incus

As mentioned earlier, I almost exclusively use Incus to get a virtual machine.

E.g. with my script I just run:

vm launch a-vm

Or with the bare Incus command it’s just as easy:

incus launch images:ubuntu/24.04 a-vm --vm

Now I can shell into the VM very quickly.

$ incus shell a-vm # or with my script, vm shell a-vm
root@a-vm:~# 

And you are in a nice little virtual machine that you can install anything you want into.

Getting a Container

Writing this post was the first time I used the container functionality of Incus! Getting a container is the default mode of operation, and it’s super easy.

$ incus launch images:ubuntu/22.04 ubuntu-container
# Image is downloaded, and the container is created
Launching ubuntu-container
$ incus ls | grep ubuntu-container
| ubuntu-container | RUNNING | 10.57.7.201 (eth0)           | fd42:af1f:b7c8:a36c:216:3eff:fee9:32e4 (eth0)   | CONTAINER       | 0         |
$ vm shell ubuntu-container

That is lightning fast. But again, important to note: this is a “system container” and not a “application container”, or in simpler terms, it’s not a docker container. If you have ever used LXC, then you will be right at home.

Application containers (as provided by, for example, Docker) package a single process or application. System containers, on the other hand, simulate a full operating system similar to what you would be running on a host or in a virtual machine. You can run Docker in an Incus system container, but you would not run Incus in a Docker application container. - Incus Docs

You may also want to understand the differences between a virtual machine and a system container:

Virtual machines create a virtual version of a physical machine, using hardware features of the host system. The boundaries between the host system and virtual machines is enforced by those hardware features. System containers, on the other hand, use the already running OS kernel of the host system instead of launching their own kernel. If you run several system containers, they all share the same kernel, which makes them faster and more lightweight than virtual machines. - Incus Docs

Why Use Incus?

You can see a list of major features here but what I like about it might not be the same as what you like about it.

  1. It’s very fast - There is an agent in the image that makes getting a shell into the VM super fast. The images are also small and download like lightning, at least in my experience.
  2. It’s easy to manage - Incus has a simple syntax for launching VMs and containers
  3. Image based - Incus uses images, instead of futzing around with qemu backing files and such
  4. You use Linux as your workstation and need to easily get a VM, or a system container

You can also try it online: https://linuxcontainers.org/incus/try-it/

Why Wouldn’t You Use Incus?

  1. It’s not Docker - it’s a different style of containerization, which many people are not used to.
  2. It’s relatively new, and a lot of work is being done on it - But on Ubuntu 24.04 it’s easy to install and get started.
  3. I do have some trouble with outbound access from the VMs and have futzed around with Iptables to get it working, but it’s not as easy as one would think–I expect I’m missing something obvious from the docs.

That’s about all I can think of.

Pairing Incus with My Kubernetes Install Script

FYI - If you create an 8GB VM with 4 CPUS, my single node Kubernetes install script pairs nicely with Incus, and is often what I use it for.

Incus 6.6 Was Just Released

See here. There is also a video overview of the new features here

Install it, try it out. Have fun easily creating VMs and containers!