From 8a0e1955c9040a3856b7a261d5d4e6f4ee326e62 Mon Sep 17 00:00:00 2001 From: Taras Vozniuk Date: Fri, 4 Feb 2022 06:14:35 +0800 Subject: [PATCH] Update archlinux build docs (#613) Update archlinux build docs, add throttling note in networking --- docs/archlinux.md | 276 +++++++++++++++++++++++++++++++++------------ docs/networking.md | 2 + 2 files changed, 204 insertions(+), 74 deletions(-) diff --git a/docs/archlinux.md b/docs/archlinux.md index 40ebd3c4ad..f5de2995a2 100644 --- a/docs/archlinux.md +++ b/docs/archlinux.md @@ -13,11 +13,14 @@ Basic installation using QEMU Installing Archlinux like this will result in a raw disk image that can be booted by v86. ```sh +# fetch archlinux32 installer +wget https://mirror.archlinux32.org/archisos/archlinux32-2021.12.01-i686.iso + # Create a 10 gigabyte disk image. If you intend to pacstrap only 'base' then 1.5G should be fine also. qemu-img create arch.img 10G # Follow the normal installation process (you can add accel=kvm if your system supports it to speed up the installation) -qemu-system-x86_64 -m 256 -drive file=arch.img,format=raw -cdrom archlinux-2017.02.01-dual.iso +qemu-system-x86_64 -m 256 -drive file=arch.img,format=raw -cdrom archlinux32-2021.12.01-i686.iso ``` For keyboard support it is necessary to open /etc/mkinitcpio.conf and edit the following line: @@ -56,35 +59,39 @@ cat > packer/template.json << 'EOF' ], "builders": [ { + "accelerator": "kvm", "type": "qemu", "boot_command": [ - "", - "dhcpcd", - "usermod --password $(echo toor | openssl passwd -1 -stdin) root", + "", + "dhcpcd", + "usermod --password $(echo root | openssl passwd -1 -stdin) root", + "echo 'root:magic' | chpasswd", "systemctl start sshd" ], "headless": true, "boot_wait": "10s", "disk_size": 1500, "disk_interface": "ide", - "http_directory": "http", - "iso_url": "https://mirror.archlinux32.org/archisos/archlinux-2017.04.01-i686.iso", - "iso_checksum": "aa4718837c95e607233aecca43824c08c798b1a4", + "iso_url": "https://mirror.archlinux32.org/archisos/archlinux32-2021.12.01-i686.iso", + "iso_checksum": "90c6f5aecb095d5578f6c9970539da7c5e9324ec", "iso_checksum_type": "sha1", "ssh_wait_timeout": "120s", "ssh_pty": true, "ssh_username": "root", - "ssh_password": "toor", + "ssh_password": "magic", "ssh_port": 22, "format": "raw", - "vm_name": "Archlinux-v86" + "vm_name": "archlinux", + "disk_detect_zeroes": "unmap", + "memory": 2048, + "vnc_bind_address": "0.0.0.0" } ] } EOF ``` -You can tweak the options a bit to match your situation. For debugging you can set `headless` to `false`. That will show you the vnc instead of running the `boot_command` in the background. For a `base` pacstrap using a 1.5G disk should be sufficient. The `raw` disk format is important. v86 does not read qcow2 images, only raw disk images. If your system does not support kvm (the default accelerator), you can add `"accelerator": "none"` to the settings. Other accelerator options can be found [here](https://www.packer.io/docs/builders/qemu.html#accelerator). +You can tweak the options a bit to match your situation. For debugging you can set `headless` to `false`. That will show you the vnc instead of running the `boot_command` in the background. For a `base` pacstrap using a 1.5G disk should be sufficient. The `raw` disk format is important. v86 does not read qcow2 images, only raw disk images. If your system does not support kvm (the default accelerator), you can change `"accelerator": "none"` to the settings, in macos you may use `"accelerator": "hvf"`. Other accelerator options can be found [here](https://www.packer.io/docs/builders/qemu.html#accelerator). After gaining SSH connectivity to the VM, packer will run the `scripts/provisioning.sh` script in the guest. @@ -120,9 +127,15 @@ mkdir -p /mnt/var/cache/pacman/pkg echo "Mount the package cache dir in memory so it doesn't fill up the image" mount -t tmpfs none /mnt/var/cache/pacman/pkg -# Install the Archlinux base system +echo "Updating archlinux-keyring" +pacman -Sy archlinux-keyring --noconfirm + +# uncomment to remove signing if unable to resolve signing errors +sed -i 's/SigLevel.*/SigLevel = Never/g' /etc/pacman.conf + +# Install the Archlinux base system, feel free to add packages you need here echo "Performing pacstrap" -pacstrap -i /mnt base --noconfirm +pacstrap -i /mnt base linux dhcpcd curl openssh --noconfirm echo "Writing fstab" genfstab -p /mnt >> /mnt/etc/fstab @@ -136,10 +149,10 @@ ExecStart= ExecStart=-/usr/bin/agetty --autologin root --noclear %I $TERM EOF -# This is the tricky part. The current root will be mounted on /dev/sda1 but after we reboot +# This is the tricky part. The current root will be mounted on /dev/sda1 but after we reboot # it will try to mount root during boot using the 9p network filesystem. This means the emulator -# will request all files over the network using XMLHttpRequests from the server. This is great -# because then you only need to provide the client with a saved state (the memory) and the +# will request all files over the network using XMLHttpRequests from the server. This is great +# because then you only need to provide the client with a saved state (the memory) and the # session will start instantly and load needed files on the fly. This is fast and it saves bandwidth. echo "Ensuring root is remounted using 9p after reboot" mkdir -p /mnt/etc/initcpio/hooks @@ -150,7 +163,7 @@ run_hook() { mount_9p_root() { msg ":: mounting '$root' on real root (9p)" - # Note the host9p. We won't mount /dev/sda1 on root anymore, + # Note the host9p. We won't mount /dev/sda1 on root anymore, # instead we mount the network filesystem and the emulator will # retrieve the files on the fly. if ! mount -t 9p host9p "$1"; then @@ -175,38 +188,120 @@ EOF # want to use the network filesystem you only need these. The 9p, 9pnet and 9pnet_virtio # modules are needed for being able to mount 9p network filesystems using the emulator. echo "Configure mkinitcpio for 9p" -sed -i 's/MODULES=""/MODULES="atkbd i8042 virtio_pci 9p 9pnet 9pnet_virtio"/g' /mnt/etc/mkinitcpio.conf -# Because we want to mount the root filesystem over the network during boot, we need to +sed -i 's/MODULES=()/MODULES=(atkbd i8042 psmouse virtio_pci 9p 9pnet 9pnet_virtio)/g' /mnt/etc/mkinitcpio.conf + +# dump mkinitcpio.conf to check if MODULES get actually set +cat /mnt/etc/mkinitcpio.conf + +# Because we want to mount the root filesystem over the network during boot, we need to # hook into initcpio. If you do not want to mount the root filesystem during boot but # only want to mount a 9p filesystem later, you can leave this out. Once the system # has been booted you should be able to mount 9p filesystems with mount -t 9p host9p /blabla # without this hook. sed -i 's/fsck"/fsck 9p_root"/g' /mnt/etc/mkinitcpio.conf +# enable ssh password auth and root login +sed -i 's/#PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_config +sed -i 's/#PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config + echo "Writing the installation script" cat << 'EOF' > /mnt/bootstrap.sh #!/usr/bin/bash echo "Re-generate initial ramdisk environment" mkinitcpio -p linux -echo "Installing the grub package" -pacman -S os-prober grub --noconfirm +# uncomment to remove signing if you are unable to resolve signing errors otherwise +sed -i 's/SigLevel.*/SigLevel = Never/g' /etc/pacman.conf -echo "Setting grub timeout to 0 seconds" -sed -i 's/GRUB_TIMEOUT=5/GRUB_TIMEOUT=0/g' /etc/default/grub +pacman -S --noconfirm syslinux gptfdisk +syslinux-install_update -i -a -m -echo "Installing bootloader" -grub-install --target=i386-pc --recheck /dev/sda --force +# disabling ldconfig to speed up boot (to remove Rebuild dynamic linker cache...) +# you may want to comment this out +echo "Disabling ldconfig service" +systemctl mask ldconfig.service -echo "Writing grub config" -grub-mkconfig -o /boot/grub/grub.cfg sync EOF echo "Chrooting and bootstrapping the installation" arch-chroot /mnt bash bootstrap.sh + +cat << 'EOF' > /mnt/boot/syslinux/syslinux.cfg +# Config file for Syslinux - +# /boot/syslinux/syslinux.cfg +# +# Comboot modules: +# * menu.c32 - provides a text menu +# * vesamenu.c32 - provides a graphical menu +# * chain.c32 - chainload MBRs, partition boot sectors, Windows bootloaders +# * hdt.c32 - hardware detection tool +# * reboot.c32 - reboots the system +# +# To Use: Copy the respective files from /usr/lib/syslinux to /boot/syslinux. +# If /usr and /boot are on the same file system, symlink the files instead +# of copying them. +# +# If you do not use a menu, a 'boot:' prompt will be shown and the system +# will boot automatically after 5 seconds. +# +# Please review the wiki: https://wiki.archlinux.org/index.php/Syslinux +# The wiki provides further configuration examples + +DEFAULT arch +PROMPT 0 # Set to 1 if you always want to display the boot: prompt +TIMEOUT 100 + +# Menu Configuration +# Either menu.c32 or vesamenu32.c32 must be copied to /boot/syslinux +UI menu.c32 +#UI vesamenu.c32 + +# Refer to http://syslinux.zytor.com/wiki/index.php/Doc/menu +MENU TITLE Arch Linux +#MENU BACKGROUND splash.png +MENU COLOR border 30;44 #40ffffff #a0000000 std +MENU COLOR title 1;36;44 #9033ccff #a0000000 std +MENU COLOR sel 7;37;40 #e0ffffff #20ffffff all +MENU COLOR unsel 37;44 #50ffffff #a0000000 std +MENU COLOR help 37;40 #c0ffffff #a0000000 std +MENU COLOR timeout_msg 37;40 #80ffffff #00000000 std +MENU COLOR timeout 1;37;40 #c0ffffff #00000000 std +MENU COLOR msg07 37;40 #90ffffff #a0000000 std +MENU COLOR tabmsg 31;40 #30ffffff #00000000 std + +# boot sections follow +# +# TIP: If you want a 1024x768 framebuffer, add "vga=773" to your kernel line. +# +#-* + +LABEL arch + MENU LABEL Arch Linux 9p + LINUX ../vmlinuz-linux + APPEND root=/dev/sda1 rw quiet + INITRD ../initramfs-linux.img + +LABEL arch2 + MENU LABEL Arch Linux Disk + LINUX ../vmlinuz-linux + APPEND root=/dev/sda1 rw quiet disablehooks=9p_root + INITRD ../initramfs-linux.img + +LABEL hdt + MENU LABEL HDT (Hardware Detection Tool) + COM32 hdt.c32 + +LABEL reboot + MENU LABEL Reboot + COM32 reboot.c32 + +LABEL poweroff + MENU LABEL Poweroff + COM32 poweroff.c32 +EOF umount -R /mnt ``` @@ -216,14 +311,7 @@ With the packer template and the script you have enough to create an image that Now that we have an image that contains a filesystem, we can convert that filesystem into something we can host on the webserver together with the v86 library. -To do so, we need to mount the image once and create a json mapping of the filesystem. This can be done with the [fs2json](https://github.com/copy/fs2json) python script. - -Get the script: -```sh -wget https://raw.githubusercontent.com/copy/fs2json/master/fs2json.py -``` - -The following script shows how to map the filesystem in an automated fashion. +To do so, we need to mount the image once and create a json mapping of the filesystem. The following script shows how to map the filesystem in an automated fashion. Create a script to builds the image and then creates v86 compatible artifacts: ```sh @@ -235,82 +323,114 @@ Example script: ```sh #!/bin/sh +SRC=packer +TARGET=output + # build the boxfile from the iso -(cd packer && packer build -force template.json) +(cd $SRC && sudo PACKER_LOG=1 PACKER_LOG_PATH="./packer.log" packer build -force template.json) # test if there is a boxfile where we expected it -if [ ! -f packer/output-qemu/Archlinux-v86 ]; then +if [ ! -f $SRC/output-qemu/archlinux ]; then echo "Looks like something went wrong building the image, maybe try again?" exit 1 fi; # clean up any previous loops and mounts echo "Making sure mountpoint is empty" +LOOP_DEV=$(sudo losetup -f) + sudo umount diskmount -f || /bin/true -sudo kpartx -d /dev/loop0 || /bin/true -sudo losetup -d /dev/loop0 || /bin/true +sudo kpartx -d $LOOP_DEV || /bin/true +sudo losetup -d $LOOP_DEV || /bin/true # mount the generated raw image, we do that so we can create # a json mapping of it and copy it to host on the webserver mkdir -p diskmount echo "Mounting the created image so we can convert it to a p9 image" -sudo losetup /dev/loop0 packer/output-qemu/Archlinux-v86 -sudo kpartx -a /dev/loop0 -sudo mount /dev/mapper/loop0p1 diskmount +sudo losetup $LOOP_DEV $SRC/output-qemu/archlinux +sudo kpartx -a $LOOP_DEV +sudo mount /dev/mapper/$(basename $LOOP_DEV)p1 diskmount # make images dir -mkdir -p output/images +mkdir -p $TARGET +mkdir -p $TARGET/images +mkdir -p $TARGET/images/arch # map the filesystem to json with fs2json -sudo python fs2json.py --exclude /boot/ --out output/images/fs.json diskmount +sudo ./tools/fs2json.py --out $TARGET/images/fs.json diskmount +sudo ./tools/copy-to-sha256.py diskmount $TARGET/images/arch # copy the filesystem and chown to nonroot user -echo "Copying the filesystem to output/arch" -mkdir output/arch -p -sudo rsync -q -av diskmount/ output/arch -sudo chown -R $(whoami):$(whoami) output/arch +echo "Copying the filesystem to $TARGET/arch" +mkdir $TARGET/arch -p +sudo rsync -q -av diskmount/ $TARGET/arch +sudo chown -R $(whoami):$(whoami) $TARGET/arch # clean up mount echo "Cleaning up mounts" sudo umount diskmount -f -sudo kpartx -d /dev/loop0 -sudo losetup -d /dev/loop0 +sudo kpartx -d $LOOP_DEV +sudo losetup -d $LOOP_DEV # Move the image to the images dir -mv packer/output-qemu/Archlinux-v86 output/images/arch.img +sudo mv $SRC/output-qemu/archlinux $TARGET/images/arch.img +``` + +Given that the packer template and provision.sh is rooted at `packer` (adjust the value of `$SRC` otherwise), run the `build.sh` at root of your `v86` repo: + +``` +chmod +x build.sh +./build.sh ``` -An example repository with these scripts can be found [here](https://github.com/vdloo/archlinux-v86-builder) +Generated artifacts are now available for serving from `output`. ### Using the created artifacts in v86 Now that we have everything we need to host a server that serves an Archlinux environment over the network. -Create a checkout of v86 and run `make build/libv86.js`. Then edit `examples/arch.html` and replace the `hda` and `filesystem` section with something like this: -```sh -hda: { - url: "http://localhost:8000/images/arch.img", - async: true, # For this option we need to run a webserver that supports the Range header - size: 1.5 * 1024 * 1024 * 1024, # This needs to be the size of the raw disk. - # See the `disk_size` item in the packer template. -}, -filesystem: { - baseurl: "http://localhost:8000/arch/", - basefs: "http://localhost:8000/images/fs.json", -}, -``` +Create a checkout of v86 and run `make build/libv86.js`. +We can then edit `examples/arch.html`, we have two options: -Then copy the created image, filesystem and json file to the v86 directory: -```sh -cp -f /your/packer/dir/output/images/arch.img /your/v86/dir/images/arch.img -cp -f /your/packer/dir/output/images/fs.json /your/v86/dir/images/fs.json -cp -r /your/pacher/dir/output/arch /your/v86/dir/ -``` +1. Boot the arclinux from the 9p filesystem (generated .bin artifacts at `/output/images/arch`): + + ```sh + filesystem: { + baseurl: "../output/images/arch/", + basefs: "../output/images/fs.json", + }, + + bzimage_initrd_from_filesystem: true, -Next, we need a webserver that supports the Range header. For example [this extension of the SimpleHTTPServer](https://github.com/smgoller/rangehttpserver). + cmdline: [ + "rw", + "root=host9p rootfstype=9p rootflags=trans=virtio,cache=loose", + ].join(" "), + + acpi: false, + autostart: true, + ``` +2. Boot the archlinux from the qemu raw disk image: + + ```sh + hda: { + url: "../output/images/arch.img", + # set to true if you want to load it asynchrously during runtime (for this option we need to run a webserver that supports the Range header) + # NOTE: async: false is slow but proved to be more realiable + async: false, + + # This needs to be the size of the raw disk. + size: 1.5 * 1024 * 1024 * 1024, + # See the `disk_size` item in the packer template. + }, + + acpi: false, + autostart: true, + ``` + +Next, we need a webserver that supports the Range header. For example [this extension of the SimpleHTTPServer](https://github.com/smgoller/rangehttpserver). At your `v86` root, run: ```sh -cd /your/v86/dir wget https://raw.githubusercontent.com/smgoller/rangehttpserver/master/RangeHTTPServer.py python2 RangeHTTPServer.py ``` @@ -335,8 +455,9 @@ network_relay_url: "ws://localhost:8080/", This will make the emulator try to connect to a [WebSockets proxy](https://github.com/benjamincburns/websockproxy). Running the proxy is very easy if you use the Docker container. ```sh -sudo docker run --privileged -p 8080:80 --name relay benjamincburns/jor1k-relay:latest +sudo docker run --privileged -p 8080:80 --name relay bennottelling/websockproxy ``` +**NOTE:** original `benjamincburns/jor1k-relay:latest` has throttling built-in by default which will degrade the networking. `bennottelling/websockproxy` has this throttling removed via [websockproxy/issues/4#issuecomment-317255890](https://github.com/benjamincburns/websockproxy/issues/4#issuecomment-317255890). You can check if the relay is running correctly by going to `http://localhost:8080/` in your browser. There you should see a message that reads `Can "Upgrade" only to "Websocket".`. @@ -357,7 +478,14 @@ It might take a while for a carrier to become available on the interface. If the When the network is up you should be able to curl a website. To check, run `curl icanhazip.com`. There you should see the public IP of the machine running the proxy. -You can't do inbound traffic into the VM with the websockproxy Docker container because it uses a basic NAT. To SSH into the VM running in the browser, you can create a reverse SSH tunnel to expose the SSH port of the sshd in the VM to the outside world. +You can't do inbound traffic into the VM with the websockproxy Docker container because it uses a basic NAT. To SSH into the VM running in the browser, you can create a reverse SSH tunnel to expose the SSH port of the sshd in the VM to the outside world. You may need to start `sshd` first, it may also be reasonable to change root password: + +```sh +passwd root +systemctl start sshd +``` + +then create a reverse SSH tunnel: ```sh # This will create a port 1122 on the example.com server diff --git a/docs/networking.md b/docs/networking.md index e124eb87a1..1c5bc10895 100644 --- a/docs/networking.md +++ b/docs/networking.md @@ -5,3 +5,5 @@ https://github.com/benjamincburns/websockproxy. The network card could also be controlled programatically, but this is currently not exposed. + +**NOTE:** original `benjamincburns/jor1k-relay:latest` docker image has throttling built-in by default which will degrade the networking. `bennottelling/websockproxy`docker image has this throttling removed via [websockproxy/issues/4#issuecomment-317255890](https://github.com/benjamincburns/websockproxy/issues/4#issuecomment-317255890). \ No newline at end of file