Tools: Report: Build a KVM-Ready Container Image from Scratch

Tools: Report: Build a KVM-Ready Container Image from Scratch

Build a KVM-Ready Container Image from Scratch

Why This Matters

Prerequisites

Step 1: Create Your Project Directory

Step 2: Write the Containerfile

Step 3: Build the Image

Step 4: Test the Image

Step 5: Check Image Size

Step 6: Tag and Organize

What You've Built

What's Next?

Want More? 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. 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: First, let's set up a clean workspace. You're going to build everything in this directory. When you're done, you can delete it or keep it for reference. Create a file named Containerfile (no extension) in your project directory: Here's what goes in it: Let me break down what each section does: 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. You should see output like: 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. Let's verify QEMU is actually installed and working: You should see QEMU's version information: Success! QEMU is installed and working inside the container. But wait — that's just the version check. Let's actually run QEMU interactively: You're now inside the container. Try running QEMU directly: Same version output. Good. Now let's try something more interesting — boot a tiny test VM: This lists all CPU models QEMU can emulate. You should see a long list including qemu64, host, Nehalem, Haswell, and many more. Let's see how big this image is: You should see something like: 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. Let's give this image a better tag for future use: Now you can refer to it as qemu:base instead of qemu-base. You should see both tags pointing to the same image ID: 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. 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. 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 Published: 23 Mar 2026Author: David TioTags: KVM, QEMU, Podman, Virtualization, Containers, Linux, TutorialSeries: KVM Virtual Machines on Podman

Word Count: ~800 Templates let you quickly answer FAQs or store snippets for re-use. Hide child comments as well For further actions, you may consider blocking this person and/or reporting abuse

Command

Copy

$ mkdir -p ~/qemu-container $ cd ~/qemu-container $ mkdir -p ~/qemu-container $ cd ~/qemu-container $ mkdir -p ~/qemu-container $ cd ~/qemu-container $ nano Containerfile $ nano Containerfile $ nano Containerfile # 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 <[email protected]>" 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 -weight: 500;">install QEMU RUN -weight: 500;">apt-get -weight: 500;">update && \ -weight: 500;">apt-get -weight: 500;">install -y --no--weight: 500;">install-recommends \ qemu-system-x86 \ qemu-utils \ qemu-system-common \ libvirt-daemon-system \ libvirt-clients \ bridge-utils \ virt-manager \ && -weight: 500;">apt-get clean \ && rm -rf /var/lib/-weight: 500;">apt/lists/* # Set working directory for VM files WORKDIR /vms # Default command — show QEMU version CMD ["qemu-system-x86_64", "--version"] # 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 <[email protected]>" 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 -weight: 500;">install QEMU RUN -weight: 500;">apt-get -weight: 500;">update && \ -weight: 500;">apt-get -weight: 500;">install -y --no--weight: 500;">install-recommends \ qemu-system-x86 \ qemu-utils \ qemu-system-common \ libvirt-daemon-system \ libvirt-clients \ bridge-utils \ virt-manager \ && -weight: 500;">apt-get clean \ && rm -rf /var/lib/-weight: 500;">apt/lists/* # Set working directory for VM files WORKDIR /vms # Default command — show QEMU version CMD ["qemu-system-x86_64", "--version"] # 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 <[email protected]>" 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 -weight: 500;">install QEMU RUN -weight: 500;">apt-get -weight: 500;">update && \ -weight: 500;">apt-get -weight: 500;">install -y --no--weight: 500;">install-recommends \ qemu-system-x86 \ qemu-utils \ qemu-system-common \ libvirt-daemon-system \ libvirt-clients \ bridge-utils \ virt-manager \ && -weight: 500;">apt-get clean \ && rm -rf /var/lib/-weight: 500;">apt/lists/* # Set working directory for VM files WORKDIR /vms # Default command — show QEMU version CMD ["qemu-system-x86_64", "--version"] $ podman build -t qemu-base . $ podman build -t qemu-base . $ podman build -t qemu-base . STEP 1/10: FROM ubuntu:24.04 STEP 2/10: LABEL maintainer="Your Name <[email protected]>" ... STEP 10/10: CMD ["qemu-system-x86_64", "--version"] COMMIT qemu-base --> a1b2c3d4e5f6 Successfully built qemu-base STEP 1/10: FROM ubuntu:24.04 STEP 2/10: LABEL maintainer="Your Name <[email protected]>" ... STEP 10/10: CMD ["qemu-system-x86_64", "--version"] COMMIT qemu-base --> a1b2c3d4e5f6 Successfully built qemu-base STEP 1/10: FROM ubuntu:24.04 STEP 2/10: LABEL maintainer="Your Name <[email protected]>" ... STEP 10/10: CMD ["qemu-system-x86_64", "--version"] COMMIT qemu-base --> a1b2c3d4e5f6 Successfully built qemu-base $ podman run --rm qemu-base $ podman run --rm qemu-base $ podman run --rm qemu-base 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 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 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 $ podman run --rm -it qemu-base /bin/bash $ podman run --rm -it qemu-base /bin/bash $ podman run --rm -it qemu-base /bin/bash root@container-id:/vms# qemu-system-x86_64 --version root@container-id:/vms# qemu-system-x86_64 --version root@container-id:/vms# qemu-system-x86_64 --version root@container-id:/vms# qemu-system-x86_64 -cpu help root@container-id:/vms# qemu-system-x86_64 -cpu help root@container-id:/vms# qemu-system-x86_64 -cpu help root@container-id:/vms# exit root@container-id:/vms# exit root@container-id:/vms# exit $ podman images qemu-base $ podman images qemu-base $ podman images qemu-base REPOSITORY TAG IMAGE ID CREATED SIZE localhost/qemu-base latest 568a6950c2ea 5 minutes ago 439 MB REPOSITORY TAG IMAGE ID CREATED SIZE localhost/qemu-base latest 568a6950c2ea 5 minutes ago 439 MB REPOSITORY TAG IMAGE ID CREATED SIZE localhost/qemu-base latest 568a6950c2ea 5 minutes ago 439 MB $ podman tag qemu-base qemu:base $ podman tag qemu-base qemu:base $ podman tag qemu-base qemu:base $ podman images qemu $ podman images qemu $ podman images qemu 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 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 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 - 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: -weight: 500;">enable KVM acceleration!) - 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) - LinkedIn: Share with your network - Twitter: Tweet about it - Questions? Drop a comment below or reach out on LinkedIn - 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