Add Fedora 44 GNOME virtual machine

This commit is contained in:
Guofang committed 2026-08-31 12:16:59 +08:00
1 parent 58a0a2d1ff
commit a0cd640ffe
10 files changed
+267 -2

No files matched your search

+24
View File
@@ -5,6 +5,7 @@ Start the required operating system with its distribution-specific launcher:
```bash ```bash
./run-debian13.sh ./run-debian13.sh
./run-almalinux10.sh ./run-almalinux10.sh
./run-fedora44.sh
./run-windows11.sh ./run-windows11.sh
``` ```
@@ -71,6 +72,29 @@ stored alongside the VM disk at `.vm/almalinux10/seed.iso`. If it already
exists after editing its source files, rebuild it explicitly with exists after editing its source files, rebuild it explicitly with
`./seediso/almalinux10/build-seed.sh .vm/almalinux10/seed.iso`. `./seediso/almalinux10/build-seed.sh .vm/almalinux10/seed.iso`.
## Fedora 44
Start a Fedora 44 Cloud Base VM with:
```bash
./run-fedora44.sh
```
The launcher downloads the `fedora44` image through the shared helper when it
is missing, creates `.vm/fedora44/disk.qcow2`, and builds its NoCloud seed from
`seediso/fedora44/`. SSH is forwarded to host port `2224` by default:
```bash
ssh -p 2224 guofang@localhost
```
On the first boot, cloud-init updates package metadata and installs Fedora's
GNOME package group through its native package module, then reboots the guest.
Keep the VM running until this initial installation and reboot have completed.
Fedora settings use the `FEDORA_VM_` prefix. Run `./run-fedora44.sh --help`
for the complete list of overrides.
## Windows 11 23H2 ## Windows 11 23H2
On first boot, the Windows 11 launcher creates a writable system-disk overlay On first boot, the Windows 11 launcher creates a writable system-disk overlay
+153
View File
@@ -0,0 +1,153 @@
#!/usr/bin/env bash
set -euo pipefail
script_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
if [[ -n "${VM_IMAGE_HELPER:-}" ]]; then
image_downloader="$VM_IMAGE_HELPER"
elif [[ -x "${script_dir}/vm-images/download-images.sh" ]]; then
image_downloader="${script_dir}/vm-images/download-images.sh"
else
image_downloader="${script_dir}/../vm-images/download-images.sh"
fi
uses_shared_base_image=false
if [[ -n "${FEDORA_VM_BASE_IMAGE:-}" ]]; then
base_image="$FEDORA_VM_BASE_IMAGE"
else
[[ -x "$image_downloader" ]] || { printf 'Error: shared image helper is unavailable: %s\n' "$image_downloader" >&2; exit 1; }
base_image="$("$image_downloader" --print-path fedora44)"
uses_shared_base_image=true
fi
state_dir="${FEDORA_VM_STATE_DIR:-${script_dir}/.vm/fedora44}"
disk_image="${FEDORA_VM_DISK_IMAGE:-${state_dir}/disk.qcow2}"
seed_image="${FEDORA_VM_SEED_IMAGE:-$(dirname -- "$disk_image")/seed.iso}"
disk_size="${FEDORA_VM_DISK_SIZE:-20G}"
memory="${FEDORA_VM_MEMORY:-8G}"
cpus="${FEDORA_VM_CPUS:-8}"
ssh_port="${FEDORA_VM_SSH_PORT:-2224}"
uefi_code="${FEDORA_VM_UEFI_CODE:-/usr/share/OVMF/OVMF_CODE_4M.fd}"
uefi_vars_template="${FEDORA_VM_UEFI_VARS:-/usr/share/OVMF/OVMF_VARS_4M.fd}"
uefi_vars="${state_dir}/OVMF_VARS_4M.fd"
pid_file="${state_dir}/qemu.pid"
log_file="${state_dir}/console.log"
daemonize=false
extra_args=()
usage() {
cat <<EOF
Usage: $(basename "$0") [--daemon] [-- QEMU_ARGUMENT ...]
Start a Fedora 44 Cloud Base virtual machine. The launcher obtains a missing
base image through the shared image helper and creates a writable overlay
under .vm/fedora44/, leaving the base image unchanged.
Options:
--daemon Run in the background while keeping the graphical window
-h, --help Show this help
Environment variables:
FEDORA_VM_MEMORY Guest memory (default: 8G)
FEDORA_VM_CPUS Virtual CPU count (default: 8)
FEDORA_VM_SSH_PORT Host port forwarded to guest SSH (default: 2224)
FEDORA_VM_BASE_IMAGE Base qcow2 image path (default: resolved by shared image helper)
FEDORA_VM_SEED_IMAGE cloud-init seed ISO path (default: alongside the VM disk)
FEDORA_VM_STATE_DIR Runtime state directory (default: .vm/fedora44)
FEDORA_VM_DISK_IMAGE Writable overlay path
FEDORA_VM_DISK_SIZE New overlay virtual capacity (default: 20G)
FEDORA_VM_UEFI_CODE OVMF read-only firmware path
FEDORA_VM_UEFI_VARS OVMF variable-store template path
EOF
}
while (($#)); do
case "$1" in
--daemon) daemonize=true; shift ;;
-h|--help) usage; exit 0 ;;
--) shift; extra_args+=("$@"); break ;;
*) printf 'Error: unknown option: %s\n' "$1" >&2; usage >&2; exit 2 ;;
esac
done
for command_name in qemu-system-x86_64 qemu-img; do
if ! command -v "$command_name" >/dev/null 2>&1; then
printf 'Error: %s is not installed.\n' "$command_name" >&2
exit 1
fi
done
if [[ ! -f "$base_image" ]]; then
if [[ "$uses_shared_base_image" == true ]]; then
"$image_downloader" fedora44
else
printf 'Error: Fedora base image was not found: %s\n' "$base_image" >&2
exit 1
fi
fi
[[ -f "$base_image" ]] || { printf 'Error: downloader did not create: %s\n' "$base_image" >&2; exit 1; }
for firmware_file in "$uefi_code" "$uefi_vars_template"; do
[[ -f "$firmware_file" ]] || { printf 'Error: required UEFI firmware was not found: %s\n' "$firmware_file" >&2; exit 1; }
done
if [[ ! -f "$seed_image" ]]; then
seed_builder="${script_dir}/seediso/fedora44/build-seed.sh"
if [[ ! -x "$seed_builder" ]]; then
printf 'Error: seed image is missing and builder is unavailable: %s\n' "$seed_builder" >&2
exit 1
fi
printf 'Seed image not found; building %s...\n' "$seed_image"
"$seed_builder" "$seed_image"
fi
mkdir -p "$state_dir"
[[ -f "$uefi_vars" ]] || cp -- "$uefi_vars_template" "$uefi_vars"
if [[ -f "$pid_file" ]]; then
old_pid="$(<"$pid_file")"
if [[ "$old_pid" =~ ^[0-9]+$ ]] && kill -0 "$old_pid" 2>/dev/null; then
printf 'Error: the Fedora virtual machine is already running (PID %s).\n' "$old_pid" >&2
exit 1
fi
rm -f "$pid_file"
fi
if [[ ! -f "$disk_image" ]]; then
qemu-img create -q -f qcow2 -F qcow2 -b "$base_image" "$disk_image" "$disk_size"
printf 'Created writable disk overlay: %s\n' "$disk_image"
fi
qemu_args=(
-name fedora44
-machine q35
-display gtk
-m "$memory"
-smp "$cpus"
-drive "if=pflash,format=raw,readonly=on,file=${uefi_code}"
-drive "if=pflash,format=raw,file=${uefi_vars}"
-drive "file=${disk_image},if=virtio,format=qcow2"
-drive "file=${seed_image},media=cdrom,readonly=on"
-nic "user,model=virtio-net-pci,hostfwd=tcp::${ssh_port}-:22"
)
if [[ -r /dev/kvm && -w /dev/kvm ]]; then
qemu_args+=(-enable-kvm -cpu host)
accelerator=KVM
else
qemu_args+=(-accel tcg -cpu max)
accelerator=TCG
fi
printf 'Starting Fedora 44 with %s acceleration; SSH is forwarded to localhost:%s.\n' \
"$accelerator" "$ssh_port"
if [[ "$daemonize" == true ]]; then
: >"$log_file"
qemu_args+=(
-serial "file:${log_file}"
-monitor none
-daemonize
-pidfile "$pid_file"
)
qemu-system-x86_64 "${qemu_args[@]}" "${extra_args[@]}"
printf 'VM started (PID %s); console log: %s\n' "$(<"$pid_file")" "$log_file"
else
exec qemu-system-x86_64 "${qemu_args[@]}" "${extra_args[@]}"
fi
+2 -1
View File
@@ -6,7 +6,8 @@ Each operating system has an independent NoCloud configuration and generated
```text ```text
seediso/ seediso/
├── debian13/ ├── debian13/
└── almalinux10/ ├── almalinux10/
└── fedora44/
``` ```
Keeping per-OS metadata separate allows each VM to use a distinct hostname and Keeping per-OS metadata separate allows each VM to use a distinct hostname and
+2
View File
@@ -0,0 +1,2 @@
seed.iso
*.iso
+14
View File
@@ -0,0 +1,14 @@
# Fedora 44 seed.iso
This directory contains the cloud-init NoCloud configuration used by
`run-fedora44.sh`. On first boot, cloud-init's package module installs Fedora's
GNOME package group and reboots the guest.
After changing `user-data`, `meta-data`, or `network-config`, remove the old
`seed.iso` and rebuild it:
```bash
./seediso/fedora44/build-seed.sh
```
Use a unique `instance-id` when cloning this configuration for another VM.
+28
View File
@@ -0,0 +1,28 @@
#!/usr/bin/env bash
set -euo pipefail
script_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
output="${1:-${script_dir}/seed.iso}"
files=(user-data meta-data)
mkdir -p "$(dirname -- "$output")"
if [[ -f "${script_dir}/network-config" ]]; then
files+=(network-config)
fi
if command -v cloud-localds >/dev/null 2>&1; then
args=()
[[ -f "${script_dir}/network-config" ]] && args+=(--network-config="${script_dir}/network-config")
cloud-localds "${args[@]}" "$output" "${script_dir}/user-data" "${script_dir}/meta-data"
elif command -v xorriso >/dev/null 2>&1; then
xorriso -as mkisofs -quiet -volid cidata -joliet -rock -output "$output" "${files[@]/#/${script_dir}/}"
elif command -v genisoimage >/dev/null 2>&1; then
genisoimage -quiet -output "$output" -volid cidata -joliet -rock "${files[@]/#/${script_dir}/}"
elif command -v mkisofs >/dev/null 2>&1; then
mkisofs -quiet -output "$output" -volid cidata -joliet -rock "${files[@]/#/${script_dir}/}"
else
printf 'Error: install cloud-image-utils, xorriso, genisoimage, or mkisofs.\n' >&2
exit 1
fi
printf 'Created %s\n' "$output"
+2
View File
@@ -0,0 +1,2 @@
instance-id: fedora44-host-001
local-hostname: fedora44-host
+10
View File
@@ -0,0 +1,10 @@
version: 2
ethernets:
all-en:
match:
name: "en*"
dhcp4: true
all-eth:
match:
name: "eth*"
dhcp4: true
+31
View File
@@ -0,0 +1,31 @@
#cloud-config
preserve_hostname: false
manage_etc_hosts: true
ssh_pwauth: true
users:
- name: guofang
gecos: Guofang
groups: [wheel]
shell: /bin/bash
sudo: "ALL=(ALL) NOPASSWD: ALL"
lock_passwd: false
hashed_passwd: $6$0NtCERV3eO12t9oJ$nlFE2sSc66nFfuD5X0xMnOla1cuzOnHfeGNRY5X7dCDHg.WzWVmuRe7M17Puj44.eCWLnJAWt4WNjd9vP9X0D0
chpasswd:
expire: false
package_update: true
packages:
- "@gnome-desktop"
runcmd:
- [systemctl, set-default, graphical.target]
# - [systemctl, enable, gdm.service]
power_state:
delay: now
mode: reboot
message: "GNOME installation completed; rebooting into graphical mode."
condition: true