Skip to content
MarcelloMorettoniPublic

About

A pipeline that creates an image and uses QEMU for lab and studies

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

qemu-lab

End-to-end QEMU foundation for prep. Builds a customized Ubuntu cloud image with Packer + Ansible, then boots it under QEMU with a cloud-init seed ISO for per-boot configuration.

What the pipeline looks like

Ubuntu cloud qcow2 (upstream)
        │
        ▼
   Packer (qemu builder, disk_image=true)
        │   ┌─ boots upstream image with a transient
        │   │  cloud-init seed (packer/cidata/) that
        │   │  creates an SSH user
        │   └─ Packer SSHes in and runs:
        ▼
   Ansible playbook (ansible/playbook.yml)
        │   pkgs, sysctl, MOTD, users, marker file
        ▼
   ubuntu-custom.qcow2  ◄── the "golden image"
        │
        ▼
   QEMU launch with:
     • a qcow2 overlay over the golden image
     • a runtime cloud-init seed.iso (cloud-init/)
        │
        ▼
   sre-lab-vm   (SSH on host :2222)

Two cloud-init configs, two different jobs:

  • packer/cidata/ — used during the build only, to give Packer an SSH user.
  • cloud-init/ — used at runtime, every time the final image boots.

Repository layout

qemu-lab/
├── packer/
│   ├── ubuntu.pkr.hcl        # Packer template (qemu builder, disk_image=true)
│   └── cidata/               # Cloud-init seed used during Packer build only
│       ├── user-data         #   creates the `packer` SSH user
│       └── meta-data
├── ansible/
│   └── playbook.yml          # Provisions the golden image (pkgs, sysctl, users)
├── cloud-init/               # Runtime seed: reconfigures the VM on every boot
│   ├── user-data             #   ← put your SSH pubkey here
│   └── meta-data
└── scripts/
    ├── build.sh              # Run Packer → packer/output/ubuntu-custom.qcow2
    ├── make-seed.sh          # Build seed.iso from cloud-init/
    ├── run.sh                # Create qcow2 overlay + launch QEMU
    └── cleanup.sh            # Remove generated artifacts

Prereqs

sudo apt install -y qemu-system-x86 qemu-utils cloud-image-utils ansible packer
# Confirm KVM:
ls -l /dev/kvm  # you must be in the kvm group (or root)

If you're running this lab inside another VM, enable nested virtualization on the host or kvm-ok will fail.

Usage

# 1. Build the custom image (downloads upstream cloud image on first run)
bash scripts/build.sh

# 2. Edit cloud-init/user-data and paste your ssh pubkey
vim cloud-init/user-data

# 3. Build the runtime seed ISO
bash scripts/make-seed.sh

# 4. Boot
bash scripts/run.sh

# In another terminal, once cloud-init finishes:
ssh -p 2222 sre@localhost

Quit the QEMU serial console with Ctrl-A then X.

run.sh creates a fresh run.qcow2 overlay every time it starts, so the golden image is never modified. Any changes made inside the VM are discarded when you re-run run.sh.

Cleanup

# Remove per-run ephemeral files (run.qcow2, seed.iso)
bash scripts/cleanup.sh

# Remove everything including the golden image and packer download cache
bash scripts/cleanup.sh --all

After --all, the next build.sh will re-download the upstream cloud image.

Things to keep in mind for your studies

  • disk_image=true skips full ISO installation — Packer treats the source as the starting disk. Standard pattern for cloud images.
  • NoCloud datasource: cloud-init looks for a filesystem labeled cidata containing user-data and meta-data. A CD-ROM with that label is the simplest way to deliver it; that's what both seed ISOs are.
  • The runtime overlay (qemu-img create -f qcow2 -F qcow2 -b GOLDEN) keeps the golden image immutable. Throw away the overlay to reset.
  • virtio everywhere (disk, net) is paravirtualization — the guest knows it's a VM and uses a thin driver, vs. emulating real hardware.
  • -cpu host exposes the physical CPU's feature set to the guest. Critical for confidential computing (SEV/TDX) where the guest needs to see those flags.
  • user networking (SLIRP) is convenient but slow and NAT-only. For real workloads you switch to a tap device on a Linux bridge.

About

A pipeline that creates an image and uses QEMU for lab and studies

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages