DEV Community

David Tio
David Tio

Posted on • Originally published at blog.dtio.app

Build a KVM-Ready Container Image from Scratch

Build a KVM-Ready Container Image from Scratch

Quick one-liner: Learn how to build a custom Podman container image with KVM/QEMU installed — the first step to running hardware-accelerated virtual machines inside containers.


Why This Matters

You've probably heard that containers and virtual machines are different things. Containers share the host kernel. VMs have their own kernel. They're opposites, right?

Well, here's the thing: sometimes you need both.

Maybe you need to test software on a different architecture. Or run a legacy OS that won't work in a container. Or isolate something even more securely than containers provide.

That's where KVM and QEMU come in. QEMU is a free, open-source emulator that can run virtual machines. KVM (Kernel-based Virtual Machine) is the Linux kernel feature that gives QEMU direct access to your CPU's hardware virtualization extensions (Intel VT-x or AMD-V). And yes — you can run them inside a container.

But here's the catch: The official QEMU images are built for specific use cases. If you want full control over what's installed and how it's configured, you need to build your own.

This guide walks you through building a custom Podman container image with QEMU and KVM support installed from scratch. No black boxes. No mystery dependencies. Just you, a Containerfile, and a working KVM setup.

By the end, you'll have:

  • A custom Containerfile tailored for KVM/QEMU
  • A working Podman image with QEMU installed
  • Understanding of what each layer does
  • A foundation to build on in future posts (next: enable KVM acceleration!)

Prerequisites

  • Podman installed (rootless mode is the default — see your distro's Podman package)
  • 5-10 minutes to build the image
  • Terminal access to your Podman host
  • Basic Containerfile knowledge (FROM, RUN, CMD instructions)

Step 1: Create Your Project Directory

First, let's set up a clean workspace.

$ mkdir -p ~/qemu-container
$ cd ~/qemu-container
Enter fullscreen mode Exit fullscreen mode

You're going to build everything in this directory. When you're done, you can delete it or keep it for reference.


Step 2: Write the Containerfile

Create a file named Containerfile (no extension) in your project directory:

$ nano Containerfile
Enter fullscreen mode Exit fullscreen mode

Here's what goes in it:

# QEMU Container Image — Base Setup
# Build: podman build -t qemu-base .
# Run:   podman run --rm -it qemu-base

FROM ubuntu:24.04

LABEL maintainer="Your Name <your.email@example.com>"
LABEL description="QEMU emulator in a Podman container"
LABEL version="1.0"

# Prevent interactive prompts during package installation
ENV DEBIAN_FRONTEND=noninteractive

# Update package lists and install QEMU
RUN apt-get update && \
    apt-get install -y --no-install-recommends \
        qemu-system-x86 \
        qemu-utils \
        qemu-system-common \
        libvirt-daemon-system \
        libvirt-clients \
        bridge-utils \
        virt-manager \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/*

# Set working directory for VM files
WORKDIR /vms

# Default command — show QEMU version
CMD ["qemu-system-x86_64", "--version"]
Enter fullscreen mode Exit fullscreen mode

Let me break down what each section does:

Line What It Does
FROM ubuntu:24.04 Start from Ubuntu 24.04 LTS — stable, well-documented, good QEMU support
ENV DEBIAN_FRONTEND=noninteractive Prevents package installation from hanging on configuration prompts
RUN apt-get update && apt-get install -y Updates package lists and installs QEMU packages
--no-install-recommends Skips optional packages — keeps the image smaller
qemu-system-x86 The main QEMU emulator for x86_64 machines
qemu-utils Utilities like qemu-img for managing disk images
qemu-system-common Common files shared by QEMU system emulators
libvirt-daemon-system Libvirt daemon for managing virtualization
libvirt-clients Client tools like virsh to interact with libvirt
bridge-utils Network bridge utilities for VM networking
virt-manager Virtual Machine Manager GUI (optional, useful for testing)
apt-get clean && rm -rf /var/lib/apt/lists/* Cleans up package cache — reduces image size
WORKDIR /vms Sets default working directory for VM files
CMD ["qemu-system-x86_64", "--version"] Shows QEMU version when container starts (useful for testing)

Why Ubuntu? You could use Alpine, Debian, or Fedora. But Ubuntu has the best documentation, largest community, and most stable QEMU packages. For a learning setup, it's the right choice.

Save the file and exit.


Step 3: Build the Image

Now build the image:

$ podman build -t qemu-base .
Enter fullscreen mode Exit fullscreen mode

You should see output like:

STEP 1/10: FROM ubuntu:24.04
STEP 2/10: LABEL maintainer="Your Name <your.email@example.com>"
...
STEP 10/10: CMD ["qemu-system-x86_64", "--version"]
COMMIT qemu-base
--> a1b2c3d4e5f6
Successfully built qemu-base
Enter fullscreen mode Exit fullscreen mode

The build downloads the base Ubuntu image, installs QEMU and all dependencies, then commits the result as qemu-base.

First build tip: The first time you build, it'll take a few minutes to download packages. Subsequent builds are faster because Podman caches layers.


Step 4: Test the Image

Let's verify QEMU is actually installed and working:

$ podman run --rm qemu-base
Enter fullscreen mode Exit fullscreen mode

You should see QEMU's version information:

QEMU emulator version 8.2.2 (Debian 1:8.2.2+ds-0ubuntu1.13)
Copyright (c) 2003-2023 Fabrice Bellard and the QEMU Project developers
Enter fullscreen mode Exit fullscreen mode

Success! QEMU is installed and working inside the container.

But wait — that's just the version check. Let's actually run QEMU interactively:

$ podman run --rm -it qemu-base /bin/bash
Enter fullscreen mode Exit fullscreen mode

You're now inside the container. Try running QEMU directly:

root@container-id:/vms# qemu-system-x86_64 --version
Enter fullscreen mode Exit fullscreen mode

Same version output. Good.

Now let's try something more interesting — boot a tiny test VM:

root@container-id:/vms# qemu-system-x86_64 -cpu help
Enter fullscreen mode Exit fullscreen mode

This lists all CPU models QEMU can emulate. You should see a long list including qemu64, host, Nehalem, Haswell, and many more.

Exit the container:

root@container-id:/vms# exit
Enter fullscreen mode Exit fullscreen mode

Step 5: Check Image Size

Let's see how big this image is:

$ podman images qemu-base
Enter fullscreen mode Exit fullscreen mode

You should see something like:

REPOSITORY           TAG         IMAGE ID      CREATED        SIZE
localhost/qemu-base  latest      568a6950c2ea  5 minutes ago  439 MB
Enter fullscreen mode Exit fullscreen mode

439 MB — pretty reasonable for a full QEMU setup with GUI tools.

Want it smaller? Remove virt-manager and libvirt packages if you only need command-line QEMU. That shaves off ~100 MB. But for learning, the full setup is worth it.


Step 6: Tag and Organize

Let's give this image a better tag for future use:

$ podman tag qemu-base qemu:base
Enter fullscreen mode Exit fullscreen mode

Now you can refer to it as qemu:base instead of qemu-base.

List your images:

$ podman images qemu
Enter fullscreen mode Exit fullscreen mode

You should see both tags pointing to the same image ID:

REPOSITORY   TAG       IMAGE ID       CREATED         SIZE
qemu         base      a1b2c3d4e5f6   3 minutes ago   1.2 GB
qemu-base    latest    a1b2c3d4e5f6   3 minutes ago   1.2 GB
Enter fullscreen mode Exit fullscreen mode

What You've Built

You now have a working QEMU container image with:

✅ QEMU system emulator (x86_64)
✅ Disk image utilities (qemu-img)
✅ Libvirt management tools
✅ Network bridge support
✅ Clean, documented Containerfile

But here's the thing: Right now, this is just an image. You can run QEMU commands, but you can't actually boot a VM yet.

Why? Because you don't have a disk image to boot.


What's Next?

You've got QEMU installed in a container. But if you try to boot a VM right now, it'll be painfully slow — like, 10 minutes to boot an OS that normally boots in 30 seconds.

Why? Because you're using pure software emulation. Every CPU instruction is translated by QEMU instead of running directly on your hardware.

Next time: We'll enable KVM acceleration — Intel VT-x or AMD-V hardware virtualization — and speed up VM boot times by 10-20x.

But there's a catch: KVM requires special device access from inside the container. And that's where things get interesting with Podman.


Want More?

This guide is Part 1 of the KVM Virtual Machines on Podman series. Each post builds on the last, adding one capability at a time.

Coming up in Part 2: Enable KVM Acceleration: 10x Faster VMs in Rootless Podman

📚 Prefer the full book? Check out "Levelling Up with Docker" on Amazon for 14 chapters of practical Docker guides.

📖 Missed a post? Start from the beginning: Run Your First Docker Container


Found this helpful?


Published: 23 Mar 2026
Author: David Tio
Tags: KVM, QEMU, Podman, Virtualization, Containers, Linux, Tutorial
Series: KVM Virtual Machines on Podman
Word Count: ~800


SEO Metadata:

  • Title: Build a KVM-Ready Container Image from Scratch (2026 Guide)
  • Meta Description: Learn how to build a custom Podman container image with KVM/QEMU support. Step-by-step guide to creating a Containerfile, building the image, and preparing for hardware-accelerated virtualization.
  • Target Keywords: kvm podman container, build qemu image, podman build kvm, qemu-system-x86_64 container, rootless kvm, virtualization in containers, hardware acceleration podman
  • Series: KVM Virtual Machines on Podman

Top comments (0)