Skip to content

Custom OS Images

PiVirt supports custom virtual machine images with seamless cloud-init integration, enabling administrators to build standardized, security-hardened templates for rapid deployment.

Pre-built cloud images from distributions:

Terminal window
# List available cloud images
pvcli image list
# Download Ubuntu cloud image
pvcli image pull ubuntu-24.04

Your own customized images:

Terminal window
# Import custom image
pvcli image import \
--name custom-ubuntu \
--file /path/to/image.qcow2 \
--os ubuntu \
--version 24.04
Terminal window
# 1. Create base VM
pvcli vm create --name base-image \
--image ubuntu-24.04 \
--cpu 2 \
--memory 4Gi \
--disk 20Gi
# 2. Start VM and configure
pvcli vm start base-image
pvcli vm console base-image
# 3. Install packages, configure system
# (inside VM console)
sudo apt-get update
sudo apt-get install -y nginx docker.io
sudo systemctl enable nginx docker
# 4. Clean up
sudo apt-get clean
sudo rm -rf /var/lib/apt/lists/*
sudo shred -u /etc/ssh/*_key*
sudo rm -f /var/log/*.log
# 5. Shutdown VM
pvcli vm stop base-image
# 6. Create image from VM disk
pvcli vm snapshot create base-image --name "base-image-v1"
pvcli storage volume clone \
--source base-image-root \
--name custom-ubuntu-base \
--pool default
Terminal window
# Install libguestfs-tools
sudo apt-get install -y libguestfs-tools
# Download base image
wget https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img
# Customize image
virt-customize -a noble-server-cloudimg-amd64.img \
--install nginx,docker.io \
--run-command 'systemctl enable nginx docker' \
--delete '/var/lib/apt/lists/*' \
--delete '/var/log/*.log' \
--hostname-template 'vm-%INDEX%' \
--root-password password:changeme
# Import customized image
pvcli image import \
--name custom-ubuntu \
--file noble-server-cloudimg-amd64.img \
--os ubuntu \
--version 24.04
ubuntu-custom.pkr.hcl
packer {
required_plugins {
qemu = {
version = ">= 1.0.0"
source = "github.com/hashicorp/qemu"
}
}
}
source "qemu" "ubuntu" {
iso_url = "https://releases.ubuntu.com/24.04/ubuntu-24.04-live-server-amd64.iso"
iso_checksum = "sha256:..."
output_directory = "output"
shutdown_command = "sudo shutdown -P now"
ssh_username = "ubuntu"
ssh_password = "ubuntu"
ssh_timeout = "30m"
vm_name = "ubuntu-custom"
disk_size = "20G"
format = "qcow2"
accelerator = "kvm"
boot_command = [
"<enter>",
"<wait5s>",
"ubuntu<enter>",
"ubuntu<enter>",
"sudo apt-get update<enter>",
"sudo apt-get install -y openssh-server<enter>",
"sudo systemctl enable ssh<enter>"
]
}
build {
sources = ["source.qemu.ubuntu"]
provisioner "shell" {
inline = [
"sudo apt-get update",
"sudo apt-get install -y nginx docker.io",
"sudo systemctl enable nginx docker",
"sudo apt-get clean",
"sudo rm -rf /var/lib/apt/lists/*"
]
}
post-processor "shell-local" {
inline = [
"pvcli image import --name custom-ubuntu --file output/ubuntu-custom.qcow2 --os ubuntu --version 24.04"
]
}
}
Terminal window
# Build image
packer build ubuntu-custom.pkr.hcl
user-data.yaml
#cloud-config
hostname: ${INSTANCE_NAME}
fqdn: ${INSTANCE_NAME}.pilab.hu
users:
- name: pivirt
groups: [sudo, docker]
sudo: ALL=(ALL) NOPASSWD:ALL
shell: /bin/bash
ssh_authorized_keys:
- ${SSH_PUBLIC_KEY}
packages:
- nginx
- docker.io
runcmd:
- systemctl enable --now nginx
- systemctl enable --now docker
write_files:
- path: /etc/motd
content: |
Welcome to ${INSTANCE_NAME}
Managed by PiVirt
final_message: "Cloud-init completed"
network-config.yaml
version: 2
ethernets:
eth0:
dhcp4: true
match:
macaddress: ${MAC_ADDRESS}
vendor-data.yaml
#cloud-config
manage_etc_hosts: true
timezone: Europe/Budapest
ntp:
pools:
- time.pilab.hu
Terminal window
# Create VM using custom image
pvcli vm create --name web-01 \
--image custom-ubuntu \
--cpu 2 \
--memory 4Gi \
--disk 20Gi \
--cloud-init user-data.yaml
Terminal window
# Create VM with full cloud-init config
pvcli vm create --name web-01 \
--image custom-ubuntu \
--cpu 2 \
--memory 4Gi \
--disk 20Gi \
--cloud-init-user-data user-data.yaml \
--cloud-init-network-config network-config.yaml \
--cloud-init-vendor-data vendor-data.yaml
Terminal window
# List all images
pvcli image list
# Filter by OS
pvcli image list --os ubuntu
# Filter by version
pvcli image list --os ubuntu --version 24.04
Terminal window
# Get image details
pvcli image info custom-ubuntu
# Output:
# Name: custom-ubuntu
# OS: Ubuntu
# Version: 24.04
# Architecture: amd64
# Format: qcow2
# Size: 2.3 GB
# Cloud-init: Supported
# Created: 2024-01-15 10:30:00
Terminal window
# Delete image
pvcli image delete custom-ubuntu
# Force delete (even if in use)
pvcli image delete custom-ubuntu --force
/etc/osinfodb/config.yaml
sources:
- name: "private-registry"
type: "http"
url: "https://images.pilab.hu"
enabled: true
auth:
username_ref: "vault:secret/data/registry#username"
password_ref: "vault:secret/data/registry#password"
image-metadata.yaml
name: "custom-ubuntu"
os:
id: "ubuntu"
name: "Ubuntu"
version: "24.04"
codename: "Noble Numbat"
architecture: "amd64"
format: "qcow2"
size_bytes: 2469606144
cloud_init:
supported: true
datasource: "NoCloud"
default_user: "pivirt"
packages:
- nginx
- docker.io
maintainer: "platform-team@pilab.hu"
description: "Custom Ubuntu image with nginx and Docker pre-installed"
  • Install only required packages
  • Remove unnecessary files
  • Minimize image size
  • Leverage cloud-init for configuration
  • Avoid hardcoding hostnames, IPs
  • Use templates for dynamic values
  • Use semantic versioning
  • Tag images with version
  • Keep changelog
  • Test image creation process
  • Test cloud-init configuration
  • Test VM deployment
  • Use Packer for reproducible builds
  • Integrate with CI/CD
  • Automate image updates