diff --git a/compose.yml b/compose.yml index d350261..1f4c834 100644 --- a/compose.yml +++ b/compose.yml @@ -3,7 +3,7 @@ services: container_name: qemu image: qemux/qemu-arm environment: - BOOT: "https://dl-cdn.alpinelinux.org/alpine/v3.19/releases/aarch64/alpine-virt-3.19.1-aarch64.iso" + BOOT: "alpine" devices: - /dev/kvm - /dev/net/tun diff --git a/kubernetes.yml b/kubernetes.yml index 7ff1f83..7ad8693 100644 --- a/kubernetes.yml +++ b/kubernetes.yml @@ -31,7 +31,7 @@ spec: image: qemux/qemu-arm env: - 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 value: "16G" ports: diff --git a/readme.md b/readme.md index 2dd7fe5..61ed984 100644 --- a/readme.md +++ b/readme.md @@ -32,7 +32,7 @@ services: container_name: qemu image: qemux/qemu-arm environment: - BOOT: "https://dl-cdn.alpinelinux.org/alpine/v3.19/releases/aarch64/alpine-virt-3.19.1-aarch64.iso" + BOOT: "alpine" devices: - /dev/kvm - /dev/net/tun @@ -49,7 +49,7 @@ services: Via Docker CLI: ```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: @@ -72,7 +72,7 @@ kubectl apply -f https://raw.githubusercontent.com/qemus/qemu-arm/refs/heads/mas 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. @@ -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! -### 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: - | **Extension** | **Format** | + | **Extension** | **Format** | |---|---| - | `.img` | Raw | - | `.raw` | Raw | - | `.iso` | Optical | - | `.qcow2` | QEMU | - | `.vmdk` | VMware | - | `.vhd` | VirtualPC | - | `.vhdx` | Hyper-V | - | `.vdi` | VirtualBox | + | `.img` | Raw | + | `.raw` | Raw | + | `.iso` | Optical | + | `.qcow2` | QEMU | + | `.vmdk` | VMware | + | `.vhd` | VirtualPC | + | `.vhdx` | Hyper-V | + | `.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? 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] > 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? 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] > 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? 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. -### 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? Only Linux and Windows 11 support KVM virtualization, macOS and Windows 10 do not unfortunately. diff --git a/src/define.sh b/src/define.sh new file mode 100644 index 0000000..4ea3e85 --- /dev/null +++ b/src/define.sh @@ -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 diff --git a/src/disk.sh b/src/disk.sh index 90c6c27..ab4eebf 100644 --- a/src/disk.sh +++ b/src/disk.sh @@ -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" case "${DISK_TYPE,,}" in - "none" ) ;; + "none" ) ;; "auto" ) echo "$result" ;; @@ -611,7 +611,11 @@ if [ -z "$DISK_FMT" ]; then if [ -f "$DISK1_FILE.qcow2" ]; then DISK_FMT="qcow2" else - DISK_FMT="raw" + if [[ "$BOOT" == *".qcow2" ]] && [ ! -f "$DISK1_FILE.img" ]; then + DISK_FMT="qcow2" + else + DISK_FMT="raw" + fi fi fi diff --git a/src/entry.sh b/src/entry.sh index 7424cbd..83053e0 100755 --- a/src/entry.sh +++ b/src/entry.sh @@ -7,7 +7,8 @@ set -Eeuo pipefail cd /run . reset.sh # Initialize system -. install.sh # Get bootdisk +. define.sh # Define images +. install.sh # Download image . disk.sh # Initialize disks . display.sh # Initialize graphics . network.sh # Initialize network diff --git a/src/install.sh b/src/install.sh index d20ceb3..ee6a69b 100644 --- a/src/install.sh +++ b/src/install.sh @@ -1,6 +1,26 @@ #!/usr/bin/env bash 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() { local dir="" @@ -10,25 +30,26 @@ detectType() { [ ! -s "$file" ] && return 1 case "${file,,}" in - *".iso" | *".img" | *".raw" | *".qcow2" ) - BOOT="$file" ;; + *".iso" | *".img" | *".raw" | *".qcow2" ) ;; * ) return 1 ;; esac - [ -n "$BOOT_MODE" ] && return 0 - [[ "${file,,}" != *".iso" ]] && return 0 + if [ -n "$BOOT_MODE" ] || [[ "${file,,}" != *".iso" ]]; then + ! moveFile "$file" && return 1 + return 0 + fi # Automaticly detect UEFI-compatible ISO's dir=$(isoinfo -f -i "$file") - if [ -z "$dir" ]; then - BOOT="" - error "Failed to read ISO file, invalid format!" && return 1 + if [ -n "$dir" ]; then + dir=$(echo "${dir^^}" | grep "^/EFI") + [ -z "$dir" ] && BOOT_MODE="legacy" + else + error "Failed to read ISO file, invalid format!" fi - dir=$(echo "${dir^^}" | grep "^/EFI") - [ -z "$dir" ] && BOOT_MODE="legacy" - + ! moveFile "$file" && return 1 return 0 } @@ -36,7 +57,8 @@ downloadFile() { local url="$1" 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" rm -f "$dest" @@ -48,8 +70,14 @@ downloadFile() { progress="--progress=dot:giga" fi - msg="Downloading image" - info "Downloading $base..." + if [ -z "$name" ]; then + name="$base" + msg="Downloading image" + else + msg="Downloading $name" + fi + + info "Downloading $name..." html "$msg..." /run/progress.sh "$dest" "0" "$msg ([P])..." & @@ -189,7 +217,22 @@ findFile "qcow2" && return 0 if [ -z "$BOOT" ] || [[ "$BOOT" == *"example.com/image.iso" ]]; then 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 base=$(basename "${BOOT%%\?*}") @@ -227,7 +270,7 @@ case "${base,,}" in * ) error "Unknown file extension, type \".${base/*./}\" is not recognized!" && exit 33 ;; esac -if ! downloadFile "$BOOT" "$base"; then +if ! downloadFile "$BOOT" "$base" "$name"; then rm -f "$STORAGE/$base.tmp" && exit 60 fi @@ -298,4 +341,4 @@ dst="$STORAGE/${base%.*}.$target_ext" base=$(basename "$dst") detectType "$STORAGE/$base" && return 0 -error "Cannot read file \"${base}\"" && exit 36 +error "Cannot convert file \"${base}\"" && exit 36