feat: Select operating systems (#204)

This commit is contained in:
Kroese 2025-03-15 14:00:44 +01:00 committed by GitHub
parent 120171e826
commit 1abc636ede
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 234 additions and 73 deletions

View file

@ -3,7 +3,7 @@ services:
container_name: qemu container_name: qemu
image: qemux/qemu-arm image: qemux/qemu-arm
environment: environment:
BOOT: "https://dl-cdn.alpinelinux.org/alpine/v3.19/releases/aarch64/alpine-virt-3.19.1-aarch64.iso" BOOT: "alpine"
devices: devices:
- /dev/kvm - /dev/kvm
- /dev/net/tun - /dev/net/tun

View file

@ -31,7 +31,7 @@ spec:
image: qemux/qemu-arm image: qemux/qemu-arm
env: env:
- name: BOOT - name: BOOT
value: "https://dl-cdn.alpinelinux.org/alpine/v3.19/releases/aarch64/alpine-virt-3.19.1-aarch64.iso" value: "alpine"
- name: DISK_SIZE - name: DISK_SIZE
value: "16G" value: "16G"
ports: ports:

120
readme.md
View file

@ -32,7 +32,7 @@ services:
container_name: qemu container_name: qemu
image: qemux/qemu-arm image: qemux/qemu-arm
environment: environment:
BOOT: "https://dl-cdn.alpinelinux.org/alpine/v3.19/releases/aarch64/alpine-virt-3.19.1-aarch64.iso" BOOT: "alpine"
devices: devices:
- /dev/kvm - /dev/kvm
- /dev/net/tun - /dev/net/tun
@ -49,7 +49,7 @@ services:
Via Docker CLI: Via Docker CLI:
```bash ```bash
docker run -it --rm --name qemu -e "BOOT=http://example.com/image.iso" -p 8006:8006 --device=/dev/kvm --device=/dev/net/tun --cap-add NET_ADMIN -v ${PWD:-.}/qemu:/storage --stop-timeout 120 qemux/qemu-arm docker run -it --rm --name qemu -e "BOOT=alpine" -p 8006:8006 --device=/dev/kvm --device=/dev/net/tun --cap-add NET_ADMIN -v ${PWD:-.}/qemu:/storage --stop-timeout 120 qemux/qemu-arm
``` ```
Via Kubernetes: Via Kubernetes:
@ -72,7 +72,7 @@ kubectl apply -f https://raw.githubusercontent.com/qemus/qemu-arm/refs/heads/mas
Very simple! These are the steps: Very simple! These are the steps:
- Set the `BOOT` environment variable to the URL of any [disk image](#what-image-formats-are-supported) you want to install. - Set the `BOOT` variable to the [operating system](#how-do-i-select-the-operating-system) you want to install.
- Start the container and connect to [port 8006](http://localhost:8006) using your web browser. - Start the container and connect to [port 8006](http://localhost:8006) using your web browser.
@ -80,24 +80,64 @@ kubectl apply -f https://raw.githubusercontent.com/qemus/qemu-arm/refs/heads/mas
Enjoy your brand new machine, and don't forget to star this repo! Enjoy your brand new machine, and don't forget to star this repo!
### What image formats are supported? ### How do I select the operating system?
You can use the `BOOT` environment variable in order to specify the operating system to be installed:
```yaml
environment:
BOOT: "alpine"
```
Select from the values below:
| **Value** | **Operating System** | **Size** |
|---|---|---|
| `alma` | Alma Linux | 1.7 GB |
| `alpine` | Alpine Linux | 60 MB |
| `centos` | CentOS Stream | 6.4 GB |
| `debian` | Debian | 3.7 GB |
| `fedora` | Fedora | 2.9 GB |
| `gentoo` | Gentoo | 1.3 GB |
| `kali` | Kali Linux | 3.4 GB |
| `nixos` | NixOS | 2.4 GB |
| `oracle` | Oracle Linux | 1.0 GB |
| `rocky` | Rocky Linux | 1.9 GB |
| `ubuntu` | Ubuntu Desktop | 3.3 GB |
| `ubuntus` | Ubuntu Server | 2.7 GB |
### How can I use my own image?
If you want to boot an operating system that is not in the list, you can set the `BOOT` variable to the URL of the image:
```yaml
environment:
BOOT: "https://dl-cdn.alpinelinux.org/alpine/v3.19/releases/aarch64/alpine-virt-3.19.1-aarch64.iso"
```
The `BOOT` URL accepts files in any of the following formats: The `BOOT` URL accepts files in any of the following formats:
| **Extension** | **Format** | | **Extension** | **Format** |
|---|---| |---|---|
| `.img` | Raw | | `.img` | Raw |
| `.raw` | Raw | | `.raw` | Raw |
| `.iso` | Optical | | `.iso` | Optical |
| `.qcow2` | QEMU | | `.qcow2` | QEMU |
| `.vmdk` | VMware | | `.vmdk` | VMware |
| `.vhd` | VirtualPC | | `.vhd` | VirtualPC |
| `.vhdx` | Hyper-V | | `.vhdx` | Hyper-V |
| `.vdi` | VirtualBox | | `.vdi` | VirtualBox |
> [!TIP] It will also accept `.img.gz`, `.qcow2.xz`, `.iso.zip` and many more, as it automaticly extracts compressed files.
> It will also accept `.img.gz`, `.qcow2.xz`, `.iso.zip` and many more, as it automaticly extracts compressed files.
You can also use a local image file directly, and skip the download altogether, by binding it in your compose file like this:
```yaml
volumes:
- ./example.iso:/boot.iso
```
This way you can supply a `/boot.iso`, `/boot.img` or a `/boot.qcow2` file. The value of `BOOT` will be ignored in this case.
### How do I change the storage location? ### How do I change the storage location?
To change the storage location, include the following bind mount in your compose file: To change the storage location, include the following bind mount in your compose file:
@ -121,6 +161,18 @@ kubectl apply -f https://raw.githubusercontent.com/qemus/qemu-arm/refs/heads/mas
> [!TIP] > [!TIP]
> This can also be used to resize the existing disk to a larger capacity without any data loss. > This can also be used to resize the existing disk to a larger capacity without any data loss.
### How do I change the amount of CPU or RAM?
By default, the container will be allowed to use a maximum of 1 CPU core and 1 GB of RAM.
If you want to adjust this, you can specify the desired amount using the following environment variables:
```yaml
environment:
RAM_SIZE: "4G"
CPU_CORES: "4"
```
### How do I increase the display resolution? ### How do I increase the display resolution?
For maximum compatibility, the display output will be a simple framebuffer by default. While this isn't the most optimal, it doesn't require any drivers. For maximum compatibility, the display output will be a simple framebuffer by default. While this isn't the most optimal, it doesn't require any drivers.
@ -137,50 +189,14 @@ kubectl apply -f https://raw.githubusercontent.com/qemus/qemu-arm/refs/heads/mas
> [!NOTE] > [!NOTE]
> Using this method your screen will stay black during the boot process, until the point where the driver is actually loaded. > Using this method your screen will stay black during the boot process, until the point where the driver is actually loaded.
### How do I boot a local image?
You can use a local image file directly, and skip the download altogether, by binding it in your compose file:
```yaml
volumes:
- ./example.iso:/boot.iso
```
You can supply a `boot.iso`, `boot.img` or `boot.qcow2` file by replacing the example path `./example.iso` with the filename of your desired image. The value of `BOOT` will be ignored in this case.
### How do I boot Windows? ### How do I boot Windows?
Use [dockur/windows-arm](https://github.com/dockur/windows-arm) instead, as it includes all the drivers required during installation, amongst many other features. Use [dockur/windows-arm](https://github.com/dockur/windows-arm) instead, as it includes all the drivers required during installation, amongst many other features.
### How do I boot a x86 image? ### How do I boot x86/x64 images?
You can use the [qemu](https://github.com/qemus/qemu/) container to run x86 and x64 images on ARM. You can use the [qemu](https://github.com/qemus/qemu/) container to run x86 and x64 images on ARM.
### How do I boot without SCSI drivers?
By default, the machine makes use of `virtio-scsi` drives for performance reasons, and even though most Linux kernels bundle the necessary driver for this device, that may not always be the case for other operating systems.
If your machine fails to detect the hard drive, you can modify your compose file to use `virtio-blk` instead:
```yaml
environment:
DISK_TYPE: "blk"
```
If it still fails to boot, you can set the value to `usb` to emulate a USB drive, which is slower but requires no drivers and is compatible with almost every system.
### How do I change the amount of CPU or RAM?
By default, the container will be allowed to use a maximum of 1 CPU core and 1 GB of RAM.
If you want to adjust this, you can specify the desired amount using the following environment variables:
```yaml
environment:
RAM_SIZE: "4G"
CPU_CORES: "4"
```
### How do I verify if my system supports KVM? ### How do I verify if my system supports KVM?
Only Linux and Windows 11 support KVM virtualization, macOS and Windows 10 do not unfortunately. Only Linux and Windows 11 support KVM virtualization, macOS and Windows 10 do not unfortunately.

97
src/define.sh Normal file
View file

@ -0,0 +1,97 @@
#!/usr/bin/env bash
set -Eeuo pipefail
getURL() {
local id="${1/ /}"
local ret="$2"
local url=""
local name=""
case "${id,,}" in
"alma" )
name="AlmaLinux"
url="https://repo.almalinux.org/almalinux/9/live/aarch64/AlmaLinux-9.5-aarch64-Live-GNOME.iso" ;;
"alpine" )
name="Alpine Linux"
url="https://dl-cdn.alpinelinux.org/alpine/v3.19/releases/aarch64/alpine-virt-3.19.1-aarch64.iso" ;;
"arch" )
name="Arch Linux"
error "No image for $name is available for ARM64 yet! " && return 1 ;;
"cachy" | "cachyos" )
name="CachyOS"
error "No image for $name is available for ARM64 yet! " && return 1 ;;
"centos" )
name="CentOS Stream"
url="https://mirrors.xtom.de/centos-stream/10-stream/BaseOS/aarch64/iso/CentOS-Stream-10-latest-aarch64-dvd1.iso" ;;
"debian" )
name="Debian"
url="https://cdimage.debian.org/debian-cd/current/arm64/iso-dvd/debian-12.9.0-arm64-DVD-1.iso" ;;
"endeavour" | "endeavouros" )
name="EndeavourOS"
error "No image for $name is available for ARM64 yet! " && return 1 ;;
"fedora" )
name="Fedora Linux"
url="https://eu.edge.kernel.org/fedora/releases/41/Workstation/aarch64/images/Fedora-Workstation-41-1.4.aarch64.raw.xz" ;;
"gentoo" )
name="Gentoo Linux"
url="https://distfiles.gentoo.org/releases/arm64/autobuilds/20250309T234826Z/di-arm64-cloudinit-20250309T234826Z.qcow2" ;;
"kali" )
name="Kali Linux"
url="https://cdimage.kali.org/kali-2024.4/kali-linux-2024.4-live-arm64.iso" ;;
"kubuntu" )
name="Kubuntu"
error "No image for $name is available for ARM64 yet! " && return 1 ;;
"macos" | "osx" )
name="macOS"
error "To install $name use: https://github.com/dockur/macos" && return 1 ;;
"mint" | "linuxmint" )
name="Linux Mint"
error "No image for $name is available for ARM64 yet! " && return 1 ;;
"manjaro" )
name="Manjaro"
error "No image for $name is available for ARM64 yet! " && return 1 ;;
"mx" )
name="MX Linux"
error "No image for $name is available for ARM64 yet! " && return 1 ;;
"nixos" )
name="NixOS"
url="https://channels.nixos.org/nixos-24.11/latest-nixos-gnome-aarch64-linux.iso" ;;
"opensuse" | "suse" )
name="OpenSUSE"
error "No image for $name is available for ARM64 yet! " && return 1 ;;
"oracle" )
name="Oracle Linux"
url="https://yum.oracle.com/ISOS/OracleLinux/OL9/u5/aarch64/OracleLinux-R9-U5-aarch64-boot-uek.iso" ;;
"rocky" )
name="Rocky Linux"
url="https://dl.rockylinux.org/pub/rocky/9/live/aarch64/Rocky-9-Workstation-aarch64-latest.iso" ;;
"slack" | "slackware" )
name="Slackware"
error "No image for $name is available for ARM64 yet! " && return 1 ;;
"tails" )
name="Tails"
error "No image for $name is available for ARM64 yet! " && return 1 ;;
"ubuntu" )
name="Ubuntu Desktop"
url="https://cdimage.ubuntu.com/ubuntu/releases/24.10/release/ubuntu-24.10-desktop-arm64.iso" ;;
"ubuntus" )
name="Ubuntu Server"
url="https://cdimage.ubuntu.com/releases/24.04/release/ubuntu-24.04.2-live-server-arm64.iso" ;;
"windows" )
name="Windows"
error "To install $name use: https://github.com/dockur/windows" && return 1 ;;
"xubuntu" )
name="Xubuntu"
error "No image for $name is available for ARM64 yet! " && return 1 ;;
esac
case "${ret,,}" in
"test" ) ;;
"name" ) echo "$name" ;;
*) echo "$url";;
esac
return 0
}
return 0

View file

@ -363,7 +363,7 @@ createDevice () {
local result=" -drive file=$DISK_FILE,id=$DISK_ID,format=$DISK_FMT,cache=$DISK_CACHE,aio=$DISK_IO,discard=$DISK_DISCARD,detect-zeroes=on" local result=" -drive file=$DISK_FILE,id=$DISK_ID,format=$DISK_FMT,cache=$DISK_CACHE,aio=$DISK_IO,discard=$DISK_DISCARD,detect-zeroes=on"
case "${DISK_TYPE,,}" in case "${DISK_TYPE,,}" in
"none" ) ;; "none" ) ;;
"auto" ) "auto" )
echo "$result" echo "$result"
;; ;;
@ -611,7 +611,11 @@ if [ -z "$DISK_FMT" ]; then
if [ -f "$DISK1_FILE.qcow2" ]; then if [ -f "$DISK1_FILE.qcow2" ]; then
DISK_FMT="qcow2" DISK_FMT="qcow2"
else else
DISK_FMT="raw" if [[ "$BOOT" == *".qcow2" ]] && [ ! -f "$DISK1_FILE.img" ]; then
DISK_FMT="qcow2"
else
DISK_FMT="raw"
fi
fi fi
fi fi

View file

@ -7,7 +7,8 @@ set -Eeuo pipefail
cd /run cd /run
. reset.sh # Initialize system . reset.sh # Initialize system
. install.sh # Get bootdisk . define.sh # Define images
. install.sh # Download image
. disk.sh # Initialize disks . disk.sh # Initialize disks
. display.sh # Initialize graphics . display.sh # Initialize graphics
. network.sh # Initialize network . network.sh # Initialize network

View file

@ -1,6 +1,26 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -Eeuo pipefail set -Eeuo pipefail
moveFile() {
local file="$1"
local ext="${file##*.}"
local dest="$STORAGE/boot.$ext"
if [[ "$file" == "$dest" ]] || [[ "$file" == "/boot.$ext" ]]; then
BOOT="$file"
return 0
fi
if ! mv -f "$file" "$dest"; then
error "Failed to move $file to $dest !"
return 1
fi
BOOT="$dest"
return 0
}
detectType() { detectType() {
local dir="" local dir=""
@ -10,25 +30,26 @@ detectType() {
[ ! -s "$file" ] && return 1 [ ! -s "$file" ] && return 1
case "${file,,}" in case "${file,,}" in
*".iso" | *".img" | *".raw" | *".qcow2" ) *".iso" | *".img" | *".raw" | *".qcow2" ) ;;
BOOT="$file" ;;
* ) return 1 ;; * ) return 1 ;;
esac esac
[ -n "$BOOT_MODE" ] && return 0 if [ -n "$BOOT_MODE" ] || [[ "${file,,}" != *".iso" ]]; then
[[ "${file,,}" != *".iso" ]] && return 0 ! moveFile "$file" && return 1
return 0
fi
# Automaticly detect UEFI-compatible ISO's # Automaticly detect UEFI-compatible ISO's
dir=$(isoinfo -f -i "$file") dir=$(isoinfo -f -i "$file")
if [ -z "$dir" ]; then if [ -n "$dir" ]; then
BOOT="" dir=$(echo "${dir^^}" | grep "^/EFI")
error "Failed to read ISO file, invalid format!" && return 1 [ -z "$dir" ] && BOOT_MODE="legacy"
else
error "Failed to read ISO file, invalid format!"
fi fi
dir=$(echo "${dir^^}" | grep "^/EFI") ! moveFile "$file" && return 1
[ -z "$dir" ] && BOOT_MODE="legacy"
return 0 return 0
} }
@ -36,7 +57,8 @@ downloadFile() {
local url="$1" local url="$1"
local base="$2" local base="$2"
local msg rc total total_mb progress local name="$3"
local msg rc total total_mb progress name
local dest="$STORAGE/$base.tmp" local dest="$STORAGE/$base.tmp"
rm -f "$dest" rm -f "$dest"
@ -48,8 +70,14 @@ downloadFile() {
progress="--progress=dot:giga" progress="--progress=dot:giga"
fi fi
msg="Downloading image" if [ -z "$name" ]; then
info "Downloading $base..." name="$base"
msg="Downloading image"
else
msg="Downloading $name"
fi
info "Downloading $name..."
html "$msg..." html "$msg..."
/run/progress.sh "$dest" "0" "$msg ([P])..." & /run/progress.sh "$dest" "0" "$msg ([P])..." &
@ -189,7 +217,22 @@ findFile "qcow2" && return 0
if [ -z "$BOOT" ] || [[ "$BOOT" == *"example.com/image.iso" ]]; then if [ -z "$BOOT" ] || [[ "$BOOT" == *"example.com/image.iso" ]]; then
hasDisk && return 0 hasDisk && return 0
error "No boot disk specified, set BOOT= to the URL of a disk image file." && exit 64 error "No value specified for the BOOT variable." && exit 64
fi
! getURL "$BOOT" "test" && exit 34
url=$(getURL "$BOOT" "url")
name=$(getURL "$BOOT" "name")
[ -n "$url" ] && BOOT="$url"
if [[ "$BOOT" != *"."* ]]; then
error "Invalid BOOT value specified, shortcut \"$BOOT\" is not recognized!" && exit 64
fi
if [[ "${BOOT,,}" != "http"* ]]; then
error "Invalid BOOT value specified, \"$BOOT\" is not a valid URL!" && exit 64
fi fi
base=$(basename "${BOOT%%\?*}") base=$(basename "${BOOT%%\?*}")
@ -227,7 +270,7 @@ case "${base,,}" in
* ) error "Unknown file extension, type \".${base/*./}\" is not recognized!" && exit 33 ;; * ) error "Unknown file extension, type \".${base/*./}\" is not recognized!" && exit 33 ;;
esac esac
if ! downloadFile "$BOOT" "$base"; then if ! downloadFile "$BOOT" "$base" "$name"; then
rm -f "$STORAGE/$base.tmp" && exit 60 rm -f "$STORAGE/$base.tmp" && exit 60
fi fi
@ -298,4 +341,4 @@ dst="$STORAGE/${base%.*}.$target_ext"
base=$(basename "$dst") base=$(basename "$dst")
detectType "$STORAGE/$base" && return 0 detectType "$STORAGE/$base" && return 0
error "Cannot read file \"${base}\"" && exit 36 error "Cannot convert file \"${base}\"" && exit 36