Vagrant and MicroK8s: A Tested Linux Development VM

Posted on July 14, 2020

Updated

Vagrant and MicroK8s can provide a repeatable Linux development VM when the host, provider and guest are compatible. This walkthrough was tested on an amd64 Ubuntu 24.04 host with KVM/libvirt, Vagrant 2.4.9 and vagrant-libvirt 0.12.2. It replaces the original Ubuntu 20.04/VirtualBox assumptions.

Prepare a compatible Linux host

Install Vagrant from HashiCorp’s supported distribution, KVM/libvirt and the provider’s build dependencies. Confirm that hardware virtualization is available and libvirt works. The test used a disposable EC2 host with nested virtualization; a normal Linux workstation with KVM can provide the same provider boundary. macOS, Windows and VirtualBox were not validated by this run.

vagrant --version
vagrant plugin list
test -c /dev/kvm
virsh -c qemu:///system list --all
# Install the tested provider when it is not already present:
vagrant plugin install vagrant-libvirt --plugin-version 0.12.2

Pin the guest and MicroK8s channel

Save this as Vagrantfile in an empty working directory. The Bento image is a third-party Ubuntu box, not a Canonical-published Vagrant image. Verify its publisher, provider, architecture and checksum through your normal image review. The tested box version contains a libvirt amd64 provider; a newer version may expose a different provider set.

Vagrant.configure("2") do |config|
  config.vm.box = "bento/ubuntu-24.04"
  config.vm.box_version = "202508.03.0"
  config.vm.synced_folder ".", "/vagrant", disabled: true
  config.vm.provider :libvirt do |vm|
    vm.memory = 4096
    vm.cpus = 2
    vm.cpu_mode = "host-passthrough"
  end
  config.vm.provision "shell", inline: <<-SHELL
    set -eux
    systemctl start snapd
    snap wait system seed.loaded
    for attempt in 1 2 3; do
      snap install microk8s --classic --channel=1.36/stable && break
      sleep 10
    done
    snap list microk8s
    timeout 600 microk8s status --wait-ready
    microk8s kubectl get nodes
    microk8s kubectl get namespaces
  SHELL
end

The live run resolved the channel to MicroK8s v1.36.2. Do not assume upstream Kubernetes and MicroK8s tracks publish simultaneously: the proposed 1.37 stable track was unavailable. On the first boot Snap also needed initialization/retry handling. Review the actual Snap channels before an upgrade.

Boot and verify an actual workload

vagrant validate
vagrant up --provider=libvirt
vagrant ssh -c 'sudo microk8s kubectl create deployment sample --image=nginx:1.30-alpine'
vagrant ssh -c 'sudo microk8s kubectl rollout status deployment/sample --timeout=180s'
vagrant ssh -c 'sudo microk8s kubectl get nodes -o wide'

Use explicit MicroK8s commands rather than assuming interactive aliases exist. The workload rollout passed in the tested guest. A single VM remains a development environment; it does not establish production availability, storage recovery or parity with a managed Kubernetes service.

Destroy the guest and verify removal

vagrant destroy -f
vagrant status
virsh -c qemu:///system list --all

Confirm the VM is absent. Remove the project-specific box/cache if it was created only for the test. The live run destroyed the guest, then deleted its enclosing AWS host and disk. For a container-based local alternative, see the kind topology-spread lab.

Sources