Testing OpenWrt x86 builds, in Docker using RunCVM

Hi. I love OpenWrt and have used it for >10 years. I'd like to draw developers' attention to a tool called RunCVM, that I hope could be useful to those developing and testing OpenWrt builds on x86, as it makes it as easy to launch a VM running OpenWRT as launching any Docker container.

Some background

RunCVM is an open-source Docker container runtime for launching VMs from Docker images. You can read all about it on GitHub. It runs on any Linux x86 host with KVM, including inside GitHub Codespaces (so anyone can try this using the free tier).

As mentioned, RunCVM makes it as easy to launch a VM running OpenWRT as launching any Docker container - avoiding many of the complexities of creating a VM in VirtualBox, VMware or LibVirt.

Example

The following example is tested on Github Codespaces, so feel free to try it yourself there (or watch the Asciinema screen recording).

Start by installing RunCVM with this one-liner:

curl -s -o - https://raw.githubusercontent.com/newsnowlabs/runcvm/main/runcvm-scripts/runcvm-install-runtime.sh | sudo sh

Next, import an openwrt rootfs to create a Docker image:

docker import --change='ENTRYPOINT ["/sbin/init"]' https://archive.openwrt.org/releases/23.05.2/targets/x86/generic/openwrt-23.05.2-x86-generic-rootfs.tar.gz openwrt-23.05.2

Create a docker network, simply so we have a known IP range:

docker network create --subnet 172.128.0.0/24 runcvm-openwrt

Create a pre-configured /etc/config/network file at /tmp/runcvm-openwrt-network:

echo -e "config interface 'loopback'\n\toption device 'lo'\n\toption proto 'static'\n\toption ipaddr '127.0.0.1'\n\toption netmask '255.0.0.0'\n\nconfig device\n\toption name 'br-lan'\n\toption type 'bridge'\n\tlist ports 'eth0'\n\nconfig interface 'lan'\n\toption device 'br-lan'\n\toption proto 'static'\n\toption ipaddr '172.128.0.5'\n\toption netmask '255.255.255.0'\n\toption gateway '172.128.0.1'\n" >/tmp/runcvm-openwrt-network

Finally, launch an OpenWrt VM on that network with IP 172.128.0.5, with the network config bound in, and with port 8080 forwarded to the VM's port 80:

docker run -it --rm --runtime=runcvm --name=openwrt --network=runcvm-openwrt --ip=172.128.0.5 -v /tmp/runcvm-openwrt-network:/etc/config/network -p 8080:80 openwrt-23.05.2

You should get a terminal and see the message "Please press Enter to activate this console." Go on and hit Enter. Type anything you like into the shell, like ifconfig or an opkg install command.

In VS Code, the port forward should have been automatically created and you can now navigate to the Ports tab and click the globe (Open in Browser) icon to access the LuCi login screen, and log in.

Here is an Asciinema screen recording showing this in action.

Please let me know if you find this useful or would like more information.

Hey, that looks interesting, but I don't understand how it is less complex than using KVM? A kvm virtual machine can be created with one command line from the openwrt rootfs?

Thank you for commenting. It's a fair point and I really don't want to overplay my suggestion that using Docker+RunCVM is less complex than using KVM. It might be for some people/use cases, but not for others. If you already know KVM and have a good one-liner or launch script you may already be just fine. But if you already know Docker and not KVM then RunCVM may be an interesting choice as many relevant KVM command-line options are effectively hidden behind Docker command-line options.

In my experience setting up KVM networking to bridge with, or route via, a host can be a fiddle (requiring wrapper scripts esp.in the bridging case). Docker+RunCVM preconfigures networking for you (which to be fair also imposes limitations, as Docker requires container interfaces to have IP addresses so running OpenWrt configurations simulating certain networking scenarios may not be possible with Docker+RunCVM; it's true KVM command-line offers much more flexibility).

Another difference: Docker+RunCVM uses virtiofs to mount the root filesystem, and supports Docker volume and bind-mounts. Hence it's possible to bind-mount config or other files/data directly into the OpenWrt VM (as in above example), to use docker cp to copy files in/out, and to use docker commit to create an image of the running VM root fs.