PolarSPARC

Hands-on Firecracker MicroVM


Bhaskar S 01/31/2026


Overview


Ever wondered what type of virtualization Amazon AWS uses when spinning up services with their Lambda serverless or their ECS Fargate instances ???

Well - Amazon AWS leverages Firecracker microVM under-the-hood !!!

Before getting started, one needs to first understand some important concepts in Linux.

In virtualization, container(s) share the same host kernel, but achieve isolation via namespaces and cgroups at a process level. On the other hand, microVM(s) are lightweight virtual machines with their own minimal kernel, that are isolated from the host kernel.

A network tap is a virtual network interface in Linux that operates at Layer 2 (Data Link layer) of the OSI network model. It has a MAC address, handles Ethernet, and is used for full Ethernet emulation in virtual machines.

A bridge in Linux network operates at Layer 2 ( Data Link layer) of the OSI network model and acts like a virtual network switch, which enables two or more virtual interfaces communicate with one other as a single network segment.


Hands-on Firecracker MicroVM


All the commands will be executed on a Ubuntu 24.04 LTS based Linux desktop.

Firecracker relies on the kvm virtualization stack. To check if kvm is enabled, execute the following command in a terminal window:


$ lsmod | grep "^kvm"


The following would be a typical output:


Output.1

kvm_intel             487424  0
kvm                  1409024  1 kvm_intel

If one does *NOT* see any output, execute the following command in the terminal window:


$ sudo modprobe kvm


To fetch the architecture of the host system, execute the following command in the terminal window:


$ uname -m


The following would be a typical output:


Output.2

x86_64

Let us refer to this value as ARCH.

To check the current stable version of Firecracker, execute the following command in the terminal window:


$ URL="https://github.com/firecracker-microvm/firecracker/releases"; VERSION=$(basename $(curl -fsSLI -o /dev/null -w %{url_effective} ${URL}/latest)); echo ${VERSION}


At the time of this article, the following would be a typical output:


Output.2

v1.14.1

Let us refer to this value as VERSION.

To download and install the Firecracker executable called firecracker, execute the following commands in the terminal window:


$ cd /tmp

$ curl -LOJ https://github.com/firecracker-microvm/firecracker/releases/download/${VERSION}/firecracker-${VERSION}-${ARCH}.tgz

$ tar -xvzf firecracker-${VERSION}-${ARCH}.tgz

$ sudo mv release-${VERSION}-${ARCH}/firecracker-${VERSION}-${ARCH} /usr/local/bin/firecracker


To ensure the Firecracker executable was properly installed, execute the following command in the terminal window:


$ firecracker --version


The following would be a typical output:


Output.3

Firecracker v1.14.1

2026-01-30T22:25:21.478790809 [anonymous-instance:main] Firecracker exiting successfully. exit_code=0

To ensure the logged in user has appropriate system privileges, execute the following commands in the terminal window:


$ sudo usermod -aG kvm ${USER}

$ sudo shutdown -r now


Once the host system reboots, log back in !

One needs a kernel image and a root filesystem (root fs) for the Firecracker MicroVM to boot and startup.

For the hands-on demonstration, we will download a pre-built kernel image and an ubuntu root fs.

To fetch the current stable base version of Firecracker, execute the following command in the terminal window:


$ CI_VERSION=${VERSION%.*}; echo ${CI_VERSION}


At the time of this article, the following would be a typical output:


Output.4

v1.14

Let us refer to this value as CI_VERSION.

To fetch the current kernel image key for Firecracker, execute the following command in the terminal window:


$ KERNEL_KEY=$(curl -s "http://spec.ccfc.min.s3.amazonaws.com/?prefix=firecracker-ci/${CI_VERSION}/${ARCH}/vmlinux-&list-type=2" | grep -oP "(?<=<Key>)(firecracker-ci/${CI_VERSION}/${ARCH}/vmlinux-[0-9]+\.[0-9]+\.[0-9]{1,3})(?=)" | sort -V | tail -1); echo ${KERNEL_KEY}


At the time of this article, the following would be a typical output:


Output.5

firecracker-ci/v1.14/x86_64/vmlinux-6.1.155

Let us refer to this value as KERNEL_KEY.

To download the kernel image for Firecracker to boot off, execute the following commands in the terminal window:


cd /tmp

$ wget "https://s3.amazonaws.com/spec.ccfc.min/${KERNEL_KEY}"


The following would be a typical output:


Output.6

--2026-01-30 22:28:15--  https://s3.amazonaws.com/spec.ccfc.min/firecracker-ci/v1.14/x86_64/vmlinux-6.1.155
Resolving s3.amazonaws.com (s3.amazonaws.com)... 16.182.104.104, 16.15.223.14, 16.15.179.49, ...
Connecting to s3.amazonaws.com (s3.amazonaws.com)|16.182.104.104|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 44278288 (42M) [binary/octet-stream]
Saving to: 'vmlinux-6.1.155'

vmlinux-6.1.155                  100%[==========================================================>]  42.23M  11.1MB/s    in 5.3s    

2026-01-30 22:28:20 (8.03 MB/s) - 'vmlinux-6.1.155' saved [44278288/44278288]

To fetch the current ubuntu root fs key for Firecracker, execute the following command:


$ UBUNTU_KEY=$(curl -s "http://spec.ccfc.min.s3.amazonaws.com/?prefix=firecracker-ci/${CI_VERSION}/${ARCH}/ubuntu-&list-type=2" | grep -oP "(?<=<Key>)(firecracker-ci/${CI_VERSION}/${ARCH}/ubuntu-[0-9]+\.[0-9]+\.squashfs)(?=)" | sort -V | tail -1); echo ${UBUNTU_KEY}


At the time of this article, the following would be a typical output:


Output.7

firecracker-ci/v1.14/x86_64/ubuntu-24.04.squashfs

Let us refer to this value as UBUNTU_KEY.

To download the ubuntu root fs for Firecracker to use, execute the following commands in the terminal window:


$ cd /tmp

$ wget -O ubuntu-${UBUNTU_KEY}.squashfs.upstream "https://s3.amazonaws.com/spec.ccfc.min/firecracker-ci/${CI_VERSION}/${ARCH}/ubuntu-${UBUNTU_KEY}.squashfs"


The following would be a typical output:


Output.8

Resolving s3.amazonaws.com (s3.amazonaws.com)... 16.15.183.181, 52.217.170.128, 16.15.187.208, ...
Connecting to s3.amazonaws.com (s3.amazonaws.com)|16.15.183.181|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 107810816 (103M) [binary/octet-stream]
Saving to: 'ubuntu-24.04.squashfs.upstream'

ubuntu-24.04.squashfs.upstream   100%[==========================================================>] 102.82M  74.4MB/s    in 1.4s    

2026-01-30 22:32:16 (74.4 MB/s) - 'ubuntu-24.04.squashfs.upstream' saved [107810816/107810816]

The downloaded ubuntu root fs does not have any ssh key embedded and has to be patched with one. To patch the ubuntu root fs with an ssh key and create a custom ubuntu root fs, execute the following commands in a terminal window:


$ cd /tmp

$ unsquashfs ubuntu-24.04.squashfs.upstream

$ ssh-keygen -f id_rsa -N ""

$ cp -v id_rsa.pub squashfs-root/root/.ssh/authorized_keys

$ mv -v id_rsa ./ubuntu-24.04.id_rsa

$ sudo chown -R root:root squashfs-root

$ truncate -s 1G ubuntu-24.04.ext4

$ sudo mkfs.ext4 -d squashfs-root -F ubuntu-24.04.ext4


With this we will have the ubuntu root fs as ubuntu-24.04.ext4.

To list all the network interfaces in the host, execute the following command in the terminal window:


$ ip -br link show


The following would be a typical output:


Output.9

lo               UNKNOWN        00:00:00:00:00:00 <LOOPBACK,UP,LOWER_UP> 
enp1s0           UP             aa:1d:aa:2e:aa:08 <BROADCAST,MULTICAST,UP,LOWER_UP> 
wlp2s0           DOWN           bb:75:bb:66:bb:2f <NO-CARRIER,BROADCAST,MULTICAST,UP>

To create a virtual network tap interface called tap0, execute the following command in the terminal window:


$ sudo ip tuntap add dev tap0 mode tap


There will be no output.

To create a network bridge called br0, execute the following command in the terminal window:


$ sudo ip link add name br0 type bridge


There will be no output.

Once again, to list all the network interfaces on the host, execute the following command in the terminal window:


$ ip -br link show


The following would be a typical output:


Output.10

lo               UNKNOWN        00:00:00:00:00:00 <LOOPBACK,UP,LOWER_UP> 
enp1s0           UP             aa:1d:aa:2e:aa:08 <BROADCAST,MULTICAST,UP,LOWER_UP> 
wlp2s0           DOWN           bb:75:bb:66:bb:2f <NO-CARRIER,BROADCAST,MULTICAST,UP> 
tap0             DOWN           ba:2d:f4:54:2e:24 <BROADCAST,MULTICAST> 
br0              DOWN           ea:10:9c:12:36:e1 <BROADCAST,MULTICAST>

To disable IPv6 on the host, execute the following command in the terminal window:


$ sudo sysctl -w net.ipv6.conf.tap0.disable_ipv6=1


The following would be a typical output:


Output.11

net.ipv6.conf.tap0.disable_ipv6 = 1

To enable IP packet forwarding on the host, execute the following command in the terminal window:


$ sudo sysctl -w net.ipv4.ip_forward=1


The following would be a typical output:


Output.12

net.ipv4.ip_forward = 1

To connect the network tap interface to the bridge, execute the following command in the terminal window:


$ sudo ip link set tap0 master br0


There will be no output.

To bring up network tap interface, execute the following command in the terminal window:


$ sudo ip link set tap0 up


There will be no output.

To bring up the bridge, execute the following command in the terminal window:


$ sudo ip link set br0 up


There will be no output.

To set the ip address/mask of the bridge to 192.168.5.1/24, execute the following command in the terminal window:


$ sudo ip addr add 192.168.5.1/24 dev br0


There will be no output.

The following are the contents of the file /tmp/vm_config.json that will be used to configure the Firecracker MicroVM instance:


/tmp/vm_config.json
{
  "boot-source": {
    "kernel_image_path": "./vmlinux-6.1.155",
    "boot_args": "keep_bootcon console=ttyS0 reboot=k panic=1 systemd.hostname=fc-vm ip=192.168.5.3::192.168.5.1:255.255.255.0::eth0"
  },
  "drives": [
    {
      "drive_id": "rootfs",
      "path_on_host": "./ubuntu-24.04.ext4",
      "is_root_device": true,
      "is_read_only": false
    }
  ],
  "network-interfaces": [
      {
          "iface_id": "eth0",
          "guest_mac": "ba:2d:f4:54:2e:24",
          "host_dev_name": "tap0"
      }
  ],
  "machine-config": {
    "vcpu_count": 1,
    "mem_size_mib": 1024
  }
}

Notice that we are assigning a hostname of fc-vm and an the ip address/mask of 192.168.5.3/24 to the Firecracker MicroVM instance.

Now for the moment of truth - to start a Firecracker MicroVM instance, execute the following commands in the terminal window:


$ cd /tmp

$ firecracker --no-api --config-file ./vm_config.json


The Firecracker MicroVM starts up in under 3 seconds and the following would be a typical trimmed output:


Output.13

... [ TRIM ]...
         Starting systemd-update-utmp-runle…- Record Runlevel Change in UTMP...
[  OK  ] Finished systemd-update-utmp-runle…e - Record Runlevel Change in UTMP.
[  OK  ] Finished fcnet.service.

Ubuntu 24.04.3 LTS fc-vm ttyS0

fc-vm-1 login: root (automatic login)

Password: 
Login timed out 
Ubuntu 24.04.3 LTS fc-vm-1 ttyS0

fc-vm login: root (automatic login)

Password:

Enter the password root and we are logged in !!!

To check the ip adress on the Firecracker MicroVM instance, execute the following command in the terminal window:


# ip -br addr show


The following would be a typical output:


Output.14

lo               UNKNOWN        127.0.0.1/8 ::1/128 
eth0             UP             192.168.5.3/24 fe80::b82d:f4ff:fe54:2e24/64

To check if one can reach the ip address 192.168.5.1 (of the bridge) from Firecracker MicroVM instance, execute the following command in the terminal window:


# ping -c 3 192.168.5.1


The following would be a typical output:


Output.15

PING 192.168.5.1 (192.168.5.1) 56(84) bytes of data.
64 bytes from 192.168.5.1: icmp_seq=1 ttl=64 time=1.37 ms
64 bytes from 192.168.5.1: icmp_seq=2 ttl=64 time=0.659 ms
64 bytes from 192.168.5.1: icmp_seq=3 ttl=64 time=0.593 ms

--- 192.168.5.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
rtt min/avg/max/mdev = 0.593/0.873/1.367/0.350 ms

To check if one can reach the ip address 192.168.1.174 (of the host) from Firecracker MicroVM instance, execute the following command in the terminal window:


# ping -c 3 192.168.1.174


The following would be a typical output:


Output.16

PING 192.168.1.174 (192.168.1.174) 56(84) bytes of data.
64 bytes from 192.168.1.174: icmp_seq=1 ttl=64 time=1.69 ms
64 bytes from 192.168.1.174: icmp_seq=2 ttl=64 time=0.600 ms
64 bytes from 192.168.1.174: icmp_seq=3 ttl=64 time=0.838 ms

--- 192.168.1.174 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
rtt min/avg/max/mdev = 0.600/1.043/1.692/0.468 ms

BOOM - with this we conclude the hands-on demonstration of Firecracker MicroVM !!!


References

Firecracker

Getting Started with Firecracker



© PolarSPARC