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.
Image Types
Section titled “Image Types”Cloud Images
Section titled “Cloud Images”Pre-built cloud images from distributions:
# List available cloud imagespvcli image list
# Download Ubuntu cloud imagepvcli image pull ubuntu-24.04Custom Images
Section titled “Custom Images”Your own customized images:
# Import custom imagepvcli image import \ --name custom-ubuntu \ --file /path/to/image.qcow2 \ --os ubuntu \ --version 24.04Creating Custom Images
Section titled “Creating Custom Images”Method 1: From Existing VM
Section titled “Method 1: From Existing VM”# 1. Create base VMpvcli vm create --name base-image \ --image ubuntu-24.04 \ --cpu 2 \ --memory 4Gi \ --disk 20Gi
# 2. Start VM and configurepvcli vm start base-imagepvcli vm console base-image
# 3. Install packages, configure system# (inside VM console)sudo apt-get updatesudo apt-get install -y nginx docker.iosudo systemctl enable nginx docker
# 4. Clean upsudo apt-get cleansudo rm -rf /var/lib/apt/lists/*sudo shred -u /etc/ssh/*_key*sudo rm -f /var/log/*.log
# 5. Shutdown VMpvcli vm stop base-image
# 6. Create image from VM diskpvcli vm snapshot create base-image --name "base-image-v1"pvcli storage volume clone \ --source base-image-root \ --name custom-ubuntu-base \ --pool defaultMethod 2: Using virt-customize
Section titled “Method 2: Using virt-customize”# Install libguestfs-toolssudo apt-get install -y libguestfs-tools
# Download base imagewget https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img
# Customize imagevirt-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 imagepvcli image import \ --name custom-ubuntu \ --file noble-server-cloudimg-amd64.img \ --os ubuntu \ --version 24.04Method 3: Using Packer
Section titled “Method 3: Using Packer”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" ] }}# Build imagepacker build ubuntu-custom.pkr.hclCloud-Init Integration
Section titled “Cloud-Init Integration”User Data
Section titled “User Data”#cloud-confighostname: ${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
Section titled “Network Config”version: 2ethernets: eth0: dhcp4: true match: macaddress: ${MAC_ADDRESS}Vendor Data
Section titled “Vendor Data”#cloud-configmanage_etc_hosts: truetimezone: Europe/Budapestntp: pools: - time.pilab.huUsing Custom Images
Section titled “Using Custom Images”Create VM with Custom Image
Section titled “Create VM with Custom Image”# Create VM using custom imagepvcli vm create --name web-01 \ --image custom-ubuntu \ --cpu 2 \ --memory 4Gi \ --disk 20Gi \ --cloud-init user-data.yamlCreate VM with Cloud-Init
Section titled “Create VM with Cloud-Init”# Create VM with full cloud-init configpvcli 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.yamlImage Management
Section titled “Image Management”List Images
Section titled “List Images”# List all imagespvcli image list
# Filter by OSpvcli image list --os ubuntu
# Filter by versionpvcli image list --os ubuntu --version 24.04Image Details
Section titled “Image Details”# Get image detailspvcli 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:00Delete Image
Section titled “Delete Image”# Delete imagepvcli image delete custom-ubuntu
# Force delete (even if in use)pvcli image delete custom-ubuntu --forceImage Repository
Section titled “Image Repository”Private Registry
Section titled “Private Registry”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
Section titled “Image Metadata”name: "custom-ubuntu"os: id: "ubuntu" name: "Ubuntu" version: "24.04" codename: "Noble Numbat"architecture: "amd64"format: "qcow2"size_bytes: 2469606144cloud_init: supported: true datasource: "NoCloud" default_user: "pivirt"packages: - nginx - docker.iomaintainer: "platform-team@pilab.hu"description: "Custom Ubuntu image with nginx and Docker pre-installed"Best Practices
Section titled “Best Practices”1. Keep Images Minimal
Section titled “1. Keep Images Minimal”- Install only required packages
- Remove unnecessary files
- Minimize image size
2. Use Cloud-Init
Section titled “2. Use Cloud-Init”- Leverage cloud-init for configuration
- Avoid hardcoding hostnames, IPs
- Use templates for dynamic values
3. Version Images
Section titled “3. Version Images”- Use semantic versioning
- Tag images with version
- Keep changelog
4. Test Images
Section titled “4. Test Images”- Test image creation process
- Test cloud-init configuration
- Test VM deployment
5. Automate Image Building
Section titled “5. Automate Image Building”- Use Packer for reproducible builds
- Integrate with CI/CD
- Automate image updates