Linux (Cloud-Image)
Cloud-Images are lightweight (usually under 700Mb) snapshots of a configured OS created by a publisher for use with public and private clouds. These images provide a way to repeatably create identical copies of a machine across platforms. Cloud-Image based systems are best used for ephemeral or immutable workloads and then discarded after each run. We will use Cloud-Init to customize the cloud-image immediately upon booting, prior to user-space initialization.
Download a Cloud-Image
Choose a cloud-image to use as the base OS:
Debian:
12: 'https://laotzu.ftp.acc.umu.se/images/cloud/bookworm/latest/debian-12-generic-amd64.qcow2'
Ubuntu:
jammy: 'https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64.img'Download the image with
wget
export CLOUD_IMAGE_URL="https://laotzu.ftp.acc.umu.se/images/cloud/bookworm/latest/debian-12-generic-amd64.qcow2"
export CLOUD_IMAGE_NAME=$(basename -- "$CLOUD_IMAGE_URL")
wget -c -O "$CLOUD_IMAGE_NAME" "$CLOUD_IMAGE_URL" -q --show-progress
VM Setup
Configure VM options
# The name of the Virtual Machine
export VM_NAME="gameci"
# The name of the user to create
export VM_USER="vmadmin"
# Number of physical CPU cores to allocate to the VM
export PHYSICAL_CORES="2"
# Number of threads per core.
# Set this to `1` for CPUs that do not support hyper-threading
export THREADS="1"
export SMP=$(( $PHYSICAL_CORES * $THREADS ))
# Amount of Disk Space to allocate to the VM.
# Cannot exceed available on host.
export DISK_SIZE="32G"
# Amount of RAM to allocate to the VM.
# Cannot exceed available RAM on host.
export MEMORY="8G"
# IP address where host may be reached. Do not use `localhost`.
export HOST_ADDRESS="SOME IP HERE"
# Port used by SSH on the host
export HOST_SSH_PORT="22"
# Port to use when forwarding SSH to the VM
export VM_SSH_PORT="1234"
# Port number to expose on the host for VNC
export VNC_PORT="0"
Credentials
Create an SSH Key
yes |ssh-keygen -C "$VM_USER" \
-f runner \
-N '' \
-t rsaCreate a password
# Install the mkpasswd utility
sudo apt install -y whois
read PW_STRING
export PASSWORD=$(mkpasswd -m sha-512 --rounds=4096 "$PW_STRING" -s "saltsaltlettuce")
Cloud-init Config
Create a Cloud-Init file
See the Cloud-Init official docs for more information about Cloud-Init. More advanced templates are available in the Host Provisioning directory.
VM_KEY=$(cat runner.pub)
/bin/cat << EOF > cloud-init.yaml
#cloud-config
hostname: runner
disable_root: false
network:
config: disabled
users:
- name: ${VM_USER}
groups: users, admin, sudo
sudo: ALL=(ALL) NOPASSWD:ALL
shell: /bin/bash
lock_passwd: false
passwd: ${PASSWORD}
ssh_authorized_keys:
- ${VM_KEY}
EOF
Disks
Create a Cloud-Init disk
cloud-localds seed.img cloud-init.yaml
Create a virtual disk using the cloud-image as a read-only backing file.
qemu-img create -b ${CLOUD_IMAGE_NAME} -f qcow2 \
-F qcow2 disk.qcow2 \
"$DISK_SIZE" 1> /dev/null
Create the VM
New guest
sudo qemu-system-x86_64 \
-machine accel=kvm,type=q35 \
-cpu host \
-smp $SMP,sockets=1,cores="$PHYSICAL_CORES",threads="$THREADS",maxcpus=$SMP \
-m "$MEMORY" \
-serial stdio -vga virtio -parallel none \
-device virtio-net-pci,netdev=network \
-netdev user,id=network,hostfwd=tcp::"${VM_SSH_PORT}"-:"${HOST_SSH_PORT}" \
-object iothread,id=io \
-device virtio-blk-pci,drive=disk,iothread=io \
-drive if=none,id=disk,cache=none,format=qcow2,aio=threads,file=disk.qcow2 \
-drive if=virtio,format=raw,file=seed.img,index=0,media=disk \
-bios /usr/share/ovmf/OVMF.fd \
-usbdevice tablet \
-vnc "$HOST_ADDRESS":"$VNC_PORT"Boot existing guest
sudo qemu-system-x86_64 \
-machine accel=kvm,type=q35 \
-cpu host \
-smp $SMP,sockets=1,cores="$PHYSICAL_CORES",threads="$THREADS",maxcpus=$SMP \
-m "$MEMORY" \
-serial stdio -vga virtio -parallel none \
-device virtio-net-pci,netdev=network \
-netdev user,id=network,hostfwd=tcp::"${VM_SSH_PORT}"-:"${HOST_SSH_PORT}" \
-object iothread,id=io \
-device virtio-blk-pci,drive=disk,iothread=io \
-drive if=none,id=disk,cache=none,format=qcow2,aio=threads,file=disk.qcow2 \
-bios /usr/share/ovmf/OVMF.fd \
-usbdevice tablet \
-vnc "$HOST_ADDRESS":"$VNC_PORT"
Connect to the VM
Connect over SSH
Copy the ssh private key
runner
to the machine you wish to connect to the VM with.Connect to the VM using the format
ssh -i runner $VM_USER@$HOST_ADDRESS -p$VM_SSH_PORT
Connect using VNC
In your VNC software use the address format
$HOST_ADDRESS:$VNC_PORT
to connect to the VM.