Thanks for your interest in using containerd and Firecracker together! This project is currently in a very early state, and things are not yet as plug-and-play as we'd like. This guide contains general instructions for getting started, but is more descriptive than a concrete set of step-by-step instructions.
If you prefer to follow a script, you can use the quickstart guide instead.
You need to have the following things in order to use firecracker-containerd:
-
A computer with a recent-enough version of Linux (4.14+), an Intel x86_64 processor (AMD and Arm are on the roadmap, but not yet supported), and KVM enabled. An i3.metal running Amazon Linux 2 is a good candidate.
Click here to see a bash script that will check if your system meets the basic requirements to run Firecracker.
#!/bin/bash err=""; \ [ "$(uname) $(uname -m)" = "Linux x86_64" ] \ || err="ERROR: your system is not Linux x86_64."; \ [ -r /dev/kvm ] && [ -w /dev/kvm ] \ || err="$err\nERROR: /dev/kvm is inaccessible."; \ (( $(uname -r | cut -d. -f1)*1000 + $(uname -r | cut -d. -f2) >= 4014 )) \ || err="$err\nERROR: your kernel version ($(uname -r)) is too old."; \ dmesg | grep -i "hypervisor detected" \ && echo "WARNING: you are running in a virtual machine. Firecracker is not well tested under nested virtualization."; \ [ -z "$err" ] && echo "Your system looks ready for Firecracker!" || echo -e "$err"
-
git
-
gcc, required by the Firecracker agent for building
-
A recent installation of Docker CE.
-
Go 1.23 or later, which you can download from here.
You can use the following kernel:
curl -fsSL -o hello-vmlinux.bin https://s3.amazonaws.com/spec.ccfc.min/img/quickstart_guide/x86_64/kernels/vmlinux.binYou can install Docker CE from the upstream binaries or from your Linux distribution.
Clone this repository to your computer in a directory of your choice.
We recommend choosing a directory outside of $GOPATH or ~/go.
git clone --recurse-submodules https://github.com/firecracker-microvm/firecracker-containerd
make allIf you clone repository inside the $GOPATH and golang version is 1.11.x, should explicitly set GO111MODULE=on before build.
GO111MODULE=on make allOnce you have built the runtime, be sure to place the following binaries on your
$PATH:
runtime/containerd-shim-aws-firecrackerfirecracker-control/cmd/containerd/firecracker-containerdfirecracker-control/cmd/containerd/firecracker-ctr
You can use the make install target to install the files to /usr/local/bin,
or specify a different INSTALLROOT if you prefer another location.
From the repository cloned in the previous step, run
make firecrackerOnce you have built firecracker, be sure to place the following binaries on your
$PATH:
_submodules/firecracker/target/x86_64-unknown-linux-musl/release/firecracker_submodules/firecracker/target/x86_64-unknown-linux-musl/release/jailer
You can use the make install-firecracker target to install the files to /usr/local/bin,
or specify a different INSTALLROOT if you prefer another location.
The firecracker-containerd repository includes an image builder component that constructs a Debian-based root filesystem for the VM. This root filesystem bundles the necessary firecracker-containerd components and is configured to be safely shared among multiple VMs by overlaying a read-write filesystem layer on top of a read-only image.
The image builder uses Docker, and expects you to be a member of the docker
group (or otherwise have access to the Docker API socket).
You can build an image like this:
make image
sudo mkdir -p /var/lib/firecracker-containerd/runtime
sudo cp tools/image-builder/rootfs.img /var/lib/firecracker-containerd/runtime/default-rootfs.imgThe firecracker-containerd binary is a containerd binary that includes an
additional plugin. Configure it with a separate config file and have it use a
separate location for on-disk state. Make sure to include configuration for the
snapshotter you intend to use.
We recommend a configuration like the following:
version = 2
disabled_plugins = ["io.containerd.grpc.v1.cri"]
root = "/var/lib/firecracker-containerd/containerd"
state = "/run/firecracker-containerd"
[grpc]
address = "/run/firecracker-containerd/containerd.sock"
[plugins]
[plugins."io.containerd.snapshotter.v1.devmapper"]
pool_name = "fc-dev-thinpool"
base_image_size = "10GB"
root_path = "/var/lib/firecracker-containerd/snapshotter/devmapper"
[debug]
level = "debug"Also note the firecracker-ctr binary installed alongside the firecracker-containerd
binary. ctr is containerd's standard cli client; firecracker-ctr is a build of ctr
from the same version of containerd as firecracker-containerd, which ensures the two
binaries are in sync with one another. While other builds of ctr may work with
firecracker-containerd, use of firecracker-ctr will ensure compatibility.
The devmapper snapshotter requires a thinpool to exist. Below is a script to create a thinpool device.
Note: The configuration with loopback devices is slow and not intended for use in production.
Script to setup thinpool with dmsetup.
#!/bin/bash
# Sets up a devicemapper thin pool with loop devices in
# /var/lib/firecracker-containerd/snapshotter/devmapper
set -ex
DIR=/var/lib/firecracker-containerd/snapshotter/devmapper
POOL=fc-dev-thinpool
if [[ ! -f "${DIR}/data" ]]; then
touch "${DIR}/data"
truncate -s 100G "${DIR}/data"
fi
if [[ ! -f "${DIR}/metadata" ]]; then
touch "${DIR}/metadata"
truncate -s 2G "${DIR}/metadata"
fi
DATADEV="$(losetup --output NAME --noheadings --associated ${DIR}/data)"
if [[ -z "${DATADEV}" ]]; then
DATADEV="$(losetup --find --show ${DIR}/data)"
fi
METADEV="$(losetup --output NAME --noheadings --associated ${DIR}/metadata)"
if [[ -z "${METADEV}" ]]; then
METADEV="$(losetup --find --show ${DIR}/metadata)"
fi
SECTORSIZE=512
DATASIZE="$(blockdev --getsize64 -q ${DATADEV})"
LENGTH_SECTORS=$(bc <<< "${DATASIZE}/${SECTORSIZE}")
DATA_BLOCK_SIZE=128 # see https://www.kernel.org/doc/Documentation/device-mapper/thin-provisioning.txt
LOW_WATER_MARK=32768 # picked arbitrarily
THINP_TABLE="0 ${LENGTH_SECTORS} thin-pool ${METADEV} ${DATADEV} ${DATA_BLOCK_SIZE} ${LOW_WATER_MARK} 1 skip_block_zeroing"
echo "${THINP_TABLE}"
if ! $(dmsetup reload "${POOL}" --table "${THINP_TABLE}"); then
dmsetup create "${POOL}" --table "${THINP_TABLE}"
fiThe runtime expects a JSON-formatted configuration file to be located either in
/etc/containerd/firecracker-runtime.json or in a location defined by the
FIRECRACKER_CONTAINERD_RUNTIME_CONFIG_PATH environment variable. The
configuration file has the following fields:
firecracker_binary_path(optional) - A path to locate thefirecrackerexecutable. If left undefined, the runtime looks for an executable namedfirecrackerlocated in its working directory. A fully-qualified path to thefirecrackerbinary is recommended, as the working directory typically changes every execution when run by containerd.kernel_image_path(optional) - A path where the kernel image file is located. A fully-qualified path is recommended. If left undefined, the runtime looks for a file named/var/lib/firecracker-containerd/runtime/default-vmlinux.bin.kernel_args(optional) - Arguments for the kernel command line. If left undefined, the runtime specifies "console=ttyS0 noapic reboot=k panic=1 pci=off nomodules rw".root_drive(optional) - A path where the root drive image file is located. A fully-qualified path is recommended. If left undefined, the runtime looks for a file named/var/lib/firecracker-containerd/runtime/default-rootfs.img.cpu_template(required) - The Firecracker CPU emulation template. Supported values are "C3" and "T2".additional_drives(unused)log_fifo(optional) - Named pipe where Firecracker logs should be delivered.log_levels(optional) - Log level for the Firecracker logs.metrics_fifo(optional) - Named pipe where Firecracker metrics should be delivered.ht_enabled(unused) - Reserved for future use.debug(optional) - Enable debug-level logging from the runtime.default_network_interfaces(optional) - a list of network interfaces to configure a VM with if no list of network interfaces is provided with a CreateVM call. Defaults to an empty list. The structure of the items in the list is the same as the Go API FirecrackerNetworkInterface defined in protobuf here.shim_base_dir- (optional) Set the path to which Firecracker will run the shim from. Defaults to /var/lib/firecracker-containerd/shim-base
A reasonable example configuration
{
"firecracker_binary_path": "/usr/local/bin/firecracker",
"kernel_image_path": "/var/lib/firecracker-containerd/runtime/hello-vmlinux.bin",
"kernel_args": "console=ttyS0 noapic reboot=k panic=1 pci=off nomodules ro systemd.unified_cgroup_hierarchy=0 systemd.journald.forward_to_console systemd.unit=firecracker.target init=/sbin/overlay-init",
"root_drive": "/var/lib/firecracker-containerd/runtime/default-rootfs.img",
"cpu_template": "T2",
"log_fifo": "fc-logs.fifo",
"log_levels": ["debug"],
"metrics_fifo": "fc-metrics.fifo"
}Ensure that /var/lib/firecracker-containerd exists as the default shim base directory used is /var/lib/firecracker-containerd/shim-base
mkdir -p /var/lib/firecracker-containerdStart containerd
$ sudo PATH=$PATH /usr/local/bin/firecracker-containerd \
--config /etc/firecracker-containerd/config.tomlPull an image
$ sudo firecracker-ctr --address /run/firecracker-containerd/containerd.sock images \
pull --snapshotter devmapper \
docker.io/library/busybox:latestAnd start a container!
$ sudo firecracker-ctr --address /run/firecracker-containerd/containerd.sock \
run \
--snapshotter devmapper \
--runtime aws.firecracker \
--rm --tty --net-host \
docker.io/library/busybox:latest busybox-testAlternatively you can specify --runtime and --snapshotter just once when
creating a new namespace using containerd's default labels:
$ sudo firecracker-ctr --address /run/firecracker-containerd/containerd.sock \
namespaces create fc
$ sudo firecracker-ctr --address /run/firecracker-containerd/containerd.sock \
namespaces label fc \
containerd.io/defaults/runtime=aws.firecracker \
containerd.io/defaults/snapshotter=devmapper
$ sudo firecracker-ctr --address /run/firecracker-containerd/containerd.sock \
-n fc \
run --rm --tty --net-host \
docker.io/library/busybox:latest busybox-testFirecracker-containerd supports the same networking options as provided by the Firecracker Go SDK, documented here. This includes support for configuring VM network interfaces both with pre-created tap devices and with tap devices created automatically by CNI plugins.
CNI-configured networks offer the quickest way to get VMs up and running with connectivity between MicroVMs and to external networks. Setting one up requires a few extra steps in addition to the above Setup steps.
Production deployments should be sure to choose a network configuration suitable to the specifics of the environment and workloads being hosting, with particular attention being given to network isolation between tasks.
To install the required CNI dependencies, run the following make target from the previously cloned firecracker-containerd repository:
$ sudo make demo-networkYou can check the Makefile to see exactly what is installed and where, but for a quick summary:
bridgeCNI plugin- Creates a veth pair with one end in a private network namespace and the other end attached to a bridge device in the host's network namespace.
ptpCNI plugin- Creates a veth pair with one end in a private network namespace and the other end in the host's network namespace.
host-localCNI plugin- Manages IP allocations of network devices present on the local machine by vending them from a statically defined subnet.
firewallCNI plugin- Sets up firewall rules on the host that allows traffic to/from VMs via the host network.
tc-redirect-tapCNI plugin- A CNI plugin that adapts other CNI plugins to be usable by Firecracker VMs.
See this doc for more details. It is used here to adapt veth
devices created by the
ptpplugin to tap devices provided to VMs.
- A CNI plugin that adapts other CNI plugins to be usable by Firecracker VMs.
See this doc for more details. It is used here to adapt veth
devices created by the
fcnet.conflist- A sample CNI configuration file that defines afcnetnetwork created via theptp,host-localandtc-redirect-tapplugins- Note that, by default, the nameserver configuration within your host's
/etc/resolv.confwill be parsed and provided to VMs as their nameserver configuration. This can cause problems if your host is using a systemd resolver or other resolver that operates on localhost (which results in the VM using its own localhost as the nameserver instead of your host's). This situation may require manual tweaking of the default CNI configuration, such as specifying static DNS configuration as part of theptpplugin.
- Note that, by default, the nameserver configuration within your host's
After those dependencies are installed, an update to the firecracker-containerd
configuration file is required for VMs to use the fcnet CNI-configuration as
their default way of generating network interfaces. Just include the following
default_network_interfaces key in your runtime configuration file (by default
at /etc/containerd/firecracker-runtime.json):
"default_network_interfaces": [
{
"CNIConfig": {
"NetworkName": "fcnet",
"InterfaceName": "veth0"
}
}
]After that, start up a container (as described in the above Usage section) and try pinging any IP available on your host. If your host has internet access, you should also be able to access the internet from the container too.