Tools: Breaking: Persistent VMs in Podman: Install Alpine to a qcow2 Disk Image

Tools: Breaking: Persistent VMs in Podman: Install Alpine to a qcow2 Disk Image

Persistent VMs in Podman: Install Alpine to a Disk Image

Why This Matters

Prerequisites

Step 1: Create the VM Directory and Disk Image

Step 2: Boot from ISO + Disk to Install

Step 3: Install Alpine

Step 4: Boot from Disk Only

Step 5: Why This Persists Across Container Restarts

New Flags at a Glance

What You've Built

What's Next? Quick one-liner: Create a qcow2 disk image with qemu-img, install Alpine Linux into it, and boot from disk — so your VM survives container restarts. Post #2 proved that KVM hardware acceleration is fast. But there's a catch: every time the container stops, the VM state vanishes. The Alpine ISO is read-only — any changes you make inside the VM exist only in RAM. Stop the container and they're gone. That's fine for a boot-speed demo, but it's not a real VM. A real VM has a disk that persists between runs. The disk lives on the host filesystem, the container is just the runtime, and the two are completely independent. Stop and restart the container as many times as you want — the disk doesn't care. This post adds that layer. You'll create a qcow2 disk image, boot from ISO + disk to run the Alpine installer, then boot from disk alone to confirm it survived. First, create a dedicated directory for your VM disk images: Then create the disk image: What's qcow2? It stands for QEMU Copy-On-Write version 2. The key property is thin provisioning: the file on your host starts tiny (a few hundred KB) and only grows as the VM actually writes data. Specifying 8G sets the maximum size the VM sees, not the space it consumes on disk immediately. Now boot with both the ISO and the disk attached. The -boot d flag tells QEMU to boot from the CD-ROM first: Alpine will boot from the ISO into a live environment. Log in as root — no password required. Once you're at the shell, run the Alpine installer: Work through the prompts. Most defaults are fine. The ones that matter: When the installer finishes, power off: The container exits. The alpine.qcow2 file on your host now contains a complete Alpine installation. Drop the ISO flags entirely. The disk knows how to boot now: Alpine boots from the installed disk. Log in with the username you created during setup. Now write a file to prove the disk persists: The container exits. Run the exact same boot command again: The file survived. The container was destroyed and recreated, but the disk image on your host never changed. That's persistence. The container is ephemeral — --rm means Podman deletes it the moment QEMU exits. But the disk image at ~/vm/alpine.qcow2 lives on your host filesystem, completely outside the container lifecycle. The bind mount (-v ~/vm:/vm:z) is just a path into the host. Writing to /vm/alpine.qcow2 inside the container is writing to ~/vm/alpine.qcow2 on the host. When the container is gone, the file remains. That install took a few minutes of interactive prompts. Every time you want a new Alpine VM, you'd repeat it from scratch. Post #4: We'll skip the installer entirely by using a cloud image — a pre-built disk image ready to boot in seconds. This guide is Part 3 of the KVM Virtual Machines on Podman series. Part 1: Build a KVM-Ready Container Image from Scratch

Part 2: KVM Acceleration in a Rootless Podman ContainerComing up in Part 4: Cloud Images — Skip the Installer, Boot in Seconds Published: 6 Apr 2026Author: David TioTags: KVM, QEMU, Podman, Virtualization, Containers, Alpine Linux, qcow2, Linux, TutorialSeries: KVM Virtual Machines on Podman

Word Count: ~750 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 ~/vm $ mkdir -p ~/vm $ mkdir -p ~/vm $ podman run --rm \ -v ~/vm:/vm:z \ qemu:base \ qemu-img create -f qcow2 /vm/alpine.qcow2 8G $ podman run --rm \ -v ~/vm:/vm:z \ qemu:base \ qemu-img create -f qcow2 /vm/alpine.qcow2 8G $ podman run --rm \ -v ~/vm:/vm:z \ qemu:base \ qemu-img create -f qcow2 /vm/alpine.qcow2 8G Formatting '/vm/alpine.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=8589934592 lazy_refcounts=off refcount_bits=16 Formatting '/vm/alpine.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=8589934592 lazy_refcounts=off refcount_bits=16 Formatting '/vm/alpine.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=8589934592 lazy_refcounts=off refcount_bits=16 $ podman run --rm -it \ --device /dev/kvm \ -v ~/vm:/vm:z \ -v ~/Downloads:/iso:z \ qemu:base \ qemu-system-x86_64 \ --weight: 500;">enable-kvm -cpu host \ -nographic \ -m 512 \ -cdrom /iso/alpine-standard-3.23.3-x86_64.iso \ -drive file=/vm/alpine.qcow2,format=qcow2 \ -boot d $ podman run --rm -it \ --device /dev/kvm \ -v ~/vm:/vm:z \ -v ~/Downloads:/iso:z \ qemu:base \ qemu-system-x86_64 \ --weight: 500;">enable-kvm -cpu host \ -nographic \ -m 512 \ -cdrom /iso/alpine-standard-3.23.3-x86_64.iso \ -drive file=/vm/alpine.qcow2,format=qcow2 \ -boot d $ podman run --rm -it \ --device /dev/kvm \ -v ~/vm:/vm:z \ -v ~/Downloads:/iso:z \ qemu:base \ qemu-system-x86_64 \ --weight: 500;">enable-kvm -cpu host \ -nographic \ -m 512 \ -cdrom /iso/alpine-standard-3.23.3-x86_64.iso \ -drive file=/vm/alpine.qcow2,format=qcow2 \ -boot d # setup-alpine # setup-alpine # setup-alpine $ podman run --rm -it \ --device /dev/kvm \ -v ~/vm:/vm:z \ qemu:base \ qemu-system-x86_64 \ --weight: 500;">enable-kvm -cpu host \ -nographic \ -m 512 \ -drive file=/vm/alpine.qcow2,format=qcow2 $ podman run --rm -it \ --device /dev/kvm \ -v ~/vm:/vm:z \ qemu:base \ qemu-system-x86_64 \ --weight: 500;">enable-kvm -cpu host \ -nographic \ -m 512 \ -drive file=/vm/alpine.qcow2,format=qcow2 $ podman run --rm -it \ --device /dev/kvm \ -v ~/vm:/vm:z \ qemu:base \ qemu-system-x86_64 \ --weight: 500;">enable-kvm -cpu host \ -nographic \ -m 512 \ -drive file=/vm/alpine.qcow2,format=qcow2 $ echo "hello from -weight: 500;">install" > ~/persistence-test.txt $ cat ~/persistence-test.txt hello from -weight: 500;">install $ su - # poweroff $ echo "hello from -weight: 500;">install" > ~/persistence-test.txt $ cat ~/persistence-test.txt hello from -weight: 500;">install $ su - # poweroff $ echo "hello from -weight: 500;">install" > ~/persistence-test.txt $ cat ~/persistence-test.txt hello from -weight: 500;">install $ su - # poweroff $ podman run --rm -it \ --device /dev/kvm \ -v ~/vm:/vm:z \ qemu:base \ qemu-system-x86_64 \ --weight: 500;">enable-kvm -cpu host \ -nographic \ -m 512 \ -drive file=/vm/alpine.qcow2,format=qcow2 $ podman run --rm -it \ --device /dev/kvm \ -v ~/vm:/vm:z \ qemu:base \ qemu-system-x86_64 \ --weight: 500;">enable-kvm -cpu host \ -nographic \ -m 512 \ -drive file=/vm/alpine.qcow2,format=qcow2 $ podman run --rm -it \ --device /dev/kvm \ -v ~/vm:/vm:z \ qemu:base \ qemu-system-x86_64 \ --weight: 500;">enable-kvm -cpu host \ -nographic \ -m 512 \ -drive file=/vm/alpine.qcow2,format=qcow2 $ cat ~/persistence-test.txt hello from -weight: 500;">install $ cat ~/persistence-test.txt hello from -weight: 500;">install $ cat ~/persistence-test.txt hello from -weight: 500;">install - qemu:base image from Post #1 - Alpine ISO from Post #2 at ~/Downloads/alpine-standard-3.23.3-x86_64.iso - ~/vm directory (you'll create it below) - Hostname: anything, e.g. alpine - Network: eth0, DHCP - Proxy: none - Root password: set something you'll remember - Timezone: your choice - Mirror: pick the fastest (or just press Enter for the default) - SSH server: openssh or none — your call - Setup a user: enter a username — don't skip this; logging in as root is bad practice - Full name: optional, press Enter to skip - User password: set one - SSH key or URL: none - Disk: sda — this is your qcow2 image - How to use it: sys — full system -weight: 500;">install to disk - Erase above disk and continue: y - ✅ qcow2 disk image created on the host - ✅ Alpine Linux installed to disk inside a KVM container - ✅ VM boots from disk and survives container restarts - ✅ Host filesystem as the persistence layer - LinkedIn: Share with your network - Twitter: Tweet about it - Questions? Drop a comment below or reach out on LinkedIn - Title: Persistent VMs in Podman: Install Alpine to a qcow2 Disk Image (2026) - Meta Description: Create a qcow2 disk image with qemu-img, -weight: 500;">install Alpine Linux inside a rootless Podman container, and boot from disk so your VM survives container restarts. - Target Keywords: qcow2 podman vm, persistent vm podman, qemu-img create qcow2, alpine linux -weight: 500;">install qemu, podman kvm persistent disk, vm disk image container - Series: KVM Virtual Machines on Podman