Compare commits
No commits in common. "f946d9b08d4f5daeba002ba323809849a92ccd18" and "3d2ab9137e1bd7f111469234cc71513409a1f0c0" have entirely different histories.
f946d9b08d
...
3d2ab9137e
18 changed files with 66 additions and 587 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -1,5 +1,6 @@
|
||||||
art
|
art
|
||||||
crud
|
crud
|
||||||
|
blob
|
||||||
media
|
media
|
||||||
/*root
|
/*root
|
||||||
|
|
||||||
|
|
@ -8,7 +9,6 @@ blog/vcf*-20*.html
|
||||||
blog.html
|
blog.html
|
||||||
blog.inner.html
|
blog.inner.html
|
||||||
*.head.html
|
*.head.html
|
||||||
blog/feed.xml
|
|
||||||
|
|
||||||
index.html
|
index.html
|
||||||
git.html
|
git.html
|
||||||
|
|
|
||||||
47
GNUmakefile
47
GNUmakefile
|
|
@ -1,12 +1,14 @@
|
||||||
DEPLOY_HTTPROOT ?= httproot
|
DEPLOY_HTTPROOT ?= httproot
|
||||||
DEPLOY_BLOBS := $(foreach blob,$(wildcard blob/*),$(DEPLOY_HTTPROOT)/$(blob))
|
DEPLOY_BLOBS = andrea0s-plain-noextfonts.svg \
|
||||||
|
blob/ebrimabd.ttf \
|
||||||
# AWESOME_BLOGS := -s https://lwn.net/headlines/rss \
|
blob/window-capture \
|
||||||
# -s https://lobste.rs/rss \
|
blob/vcf-2024-pile.jpg
|
||||||
# -s https://blog.haskell.org/atom.xml \
|
AWESOME_BLOGS := -s https://lwn.net/headlines/rss \
|
||||||
# -s https://www.phoronix.com/rss.php \
|
-s https://lobste.rs/rss \
|
||||||
# -s https://static.fsf.org/fsforg/rss/news.xml \
|
-s https://blog.haskell.org/atom.xml \
|
||||||
# -s https://emersion.fr/blog/rss.xml
|
-s https://www.phoronix.com/rss.php \
|
||||||
|
-s https://static.fsf.org/fsforg/rss/news.xml \
|
||||||
|
-s https://emersion.fr/blog/rss.xml
|
||||||
|
|
||||||
UNAME = $(shell uname)
|
UNAME = $(shell uname)
|
||||||
ifeq ($(UNAME),Linux)
|
ifeq ($(UNAME),Linux)
|
||||||
|
|
@ -27,11 +29,13 @@ blog/%.indicator.html: indicators
|
||||||
blog/%.html: %.head.html nav.head.html %.indicator.html nav.tail.html window.head.html %.inner.html window.tail.html
|
blog/%.html: %.head.html nav.head.html %.indicator.html nav.tail.html window.head.html %.inner.html window.tail.html
|
||||||
cat $^ > $@
|
cat $^ > $@
|
||||||
|
|
||||||
blog/feed.xml blog.inner.html: $(BLOG_SRC) scripts/blogposts.bash #modules/openring/openring
|
vcf%.html: vcf%.head.html nav.head.html blog/vcf%.indicator.html nav.tail.html window.head.html blog/vcf%.inner.html window.tail.html
|
||||||
scripts/blogposts.bash > $@
|
cat $^ > $@
|
||||||
# scripts/blogposts.bash \
|
|
||||||
# | modules/openring/openring -n 12 -p 3 \
|
blog.inner.html: $(BLOG_SRC)
|
||||||
# $(AWESOME_BLOGS) > $@
|
scripts/blogposts.bash \
|
||||||
|
| modules/openring/openring -n 12 -p 3 \
|
||||||
|
$(AWESOME_BLOGS) > $@
|
||||||
|
|
||||||
modules/openring/openring.go: .gitmodules
|
modules/openring/openring.go: .gitmodules
|
||||||
git submodule update --init --recursive -- modules/openring
|
git submodule update --init --recursive -- modules/openring
|
||||||
|
|
@ -62,22 +66,17 @@ index.html: indexhead.html nav.head.html index.indicator.html nav.tail.html inde
|
||||||
%.html: %.head.html nav.head.html %.indicator.html nav.tail.html window.head.html %.inner.html window.tail.html
|
%.html: %.head.html nav.head.html %.indicator.html nav.tail.html window.head.html %.inner.html window.tail.html
|
||||||
cat $^ > $@
|
cat $^ > $@
|
||||||
|
|
||||||
test: deploy
|
test: index.html
|
||||||
#$(OPEN) $@.html
|
$(OPEN) $<
|
||||||
cd $(DEPLOY_HTTPROOT) \
|
|
||||||
&& (ln -s . '~targetdisk' || :) \
|
|
||||||
&& python -m http.server
|
|
||||||
|
|
||||||
$(DEPLOY_HTTPROOT)/blob/%: blob/% $(DEPLOY_HTTPROOT)/blob
|
|
||||||
cp -rv $< $@
|
|
||||||
|
|
||||||
$(DEPLOY_HTTPROOT)/blob:
|
$(DEPLOY_HTTPROOT)/blob:
|
||||||
mkdir -p $@
|
mkdir -p $(@)
|
||||||
|
cp -rv $(DEPLOY_BLOBS) $(@)
|
||||||
|
|
||||||
deploy: all $(DEPLOY_BLOBS)
|
deploy: all $(DEPLOY_HTTPROOT)/blob
|
||||||
cp -rv *.css *.html blog media \
|
cp -rv *.css *.html blog media \
|
||||||
$(DEPLOY_HTTPROOT)
|
$(DEPLOY_HTTPROOT)
|
||||||
|
|
||||||
all: blog-posts index.html blog.html resume.html
|
all: blog-posts index.html blog.html resume.html vcfmw-2024.html
|
||||||
|
|
||||||
.PHONY: all blog-posts indicators deploy
|
.PHONY: all blog-posts indicators deploy
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 21 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 1.3 MiB |
Binary file not shown.
|
Before Width: | Height: | Size: 164 KiB |
|
|
@ -18,8 +18,7 @@ and Xen?
|
||||||
With [QEMU](https://www.qemu.org/) your VMs are defined as the arguments passed
|
With [QEMU](https://www.qemu.org/) your VMs are defined as the arguments passed
|
||||||
to QEMU on its invocation at the command line. For example, you might invoke a
|
to QEMU on its invocation at the command line. For example, you might invoke a
|
||||||
VM as such (note that **`>`** is a
|
VM as such (note that **`>`** is a
|
||||||
[$PS2 prompt](http://tldp.org/HOWTO/Bash-Prompt-HOWTO/x157.html)):
|
[**$PS2** prompt](http://tldp.org/HOWTO/Bash-Prompt-HOWTO/x157.html)):
|
||||||
|
|
||||||
```
|
```
|
||||||
$ qemu-system-x86_64 -machine type=q35 --enable-kvm -cpu host -smp cpus=8 \
|
$ qemu-system-x86_64 -machine type=q35 --enable-kvm -cpu host -smp cpus=8 \
|
||||||
> -m 512M -netdev user,id=net0 -device e1000,netdev=net0 -hda dsk/vm-hdd.qcow
|
> -m 512M -netdev user,id=net0 -device e1000,netdev=net0 -hda dsk/vm-hdd.qcow
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ with `xwininfo`:
|
||||||
|
|
||||||
<center>
|
<center>
|
||||||
<video height="100%" width="700vmin" autoplay loop>
|
<video height="100%" width="700vmin" autoplay loop>
|
||||||
<source src="/~targetdisk/media/xwininfo.mp4" type="video/mp4" />
|
<source src="/media/xwininfo.mp4" type="video/mp4" />
|
||||||
</video>
|
</video>
|
||||||
</center>
|
</center>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,466 +0,0 @@
|
||||||
# 9p rootfs on Ubuntu Server VM Using QEMU
|
|
||||||
|
|
||||||
This post is a guide on how to install Ubuntu Server to a Plan 9 filesystem.
|
|
||||||
|
|
||||||
If you are impatient you can skip to the actual tutorial content by clicking
|
|
||||||
[here](#teal-deer).
|
|
||||||
|
|
||||||
## What is Plan 9?
|
|
||||||
[Plan 9](https://en.wikipedia.org/wiki/Plan_9_from_Bell_Labs) started out as a
|
|
||||||
research operating system developed at
|
|
||||||
[Bell Labs](https://en.wikipedia.org/wiki/Bell_Labs). It extends the
|
|
||||||
"everything is a file" API metaphor of UNIX even farther. Filesystem APIs for
|
|
||||||
networking sockets, graphics, and more. Any resource of any system, be it
|
|
||||||
remote or local, can be accessed if you have a mounted filesystem with these
|
|
||||||
special files in them!
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
To accomplish all of this resource and file sharing, the
|
|
||||||
[Plan 9 Filesystem Protocol](https://en.wikipedia.org/wiki/9P_(protocol)) (also
|
|
||||||
known as **9p**) was devised.
|
|
||||||
|
|
||||||
Within the last few years, a lot of people have begun to realise that 9p was
|
|
||||||
really neat and started to use it in Linux. It is especially popular for
|
|
||||||
sharing resources with virtual machines because of how lightweight it is as a
|
|
||||||
protocol.
|
|
||||||
|
|
||||||
### What happened to Plan 9?
|
|
||||||
Sadly because of the pressures of the capitalistic hellscape we all live under,
|
|
||||||
Bell Labs changed hands and some of this research got pared down. Bell Labs was
|
|
||||||
first spun off into AT&T Technologies which was then bought by
|
|
||||||
Lucent that later merged with the French Alcatel to form Alcatel-Lucent that
|
|
||||||
then got bought again by the undead corpse of Nokia. Standard murder-execution,
|
|
||||||
er, merger-acquisition stuff.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
The researchers were scattered like ashes to the
|
|
||||||
wind, many of them finding homes at places like Google et. al. They took their
|
|
||||||
work with them to the BSD, Linux, and Macintosh systems that they ended up
|
|
||||||
working with at their new jobs. They ported a lot of the features from Plan 9
|
|
||||||
to user spaces of other operating systems and even made kernel modules and
|
|
||||||
extensions to add back some of the features they sorely missed.
|
|
||||||
|
|
||||||
*(See [#1](#no1) for more details on this.)*
|
|
||||||
|
|
||||||
## Why use a 9p rootfs?
|
|
||||||
The most common way that developers boot their VMs is using disk images. This
|
|
||||||
is "fine," but it introduces a lot of annoyances and inefficiencies.
|
|
||||||
|
|
||||||
Let's look at the latter first. When you are booting a virtual machine with a
|
|
||||||
disk image you are literally telling your virtual machine software to emulate an
|
|
||||||
entire computer motherboard *and* hard drive. This isn't something that can
|
|
||||||
typically be accelerated with your host system's virtualisation features,
|
|
||||||
either. Your virtual machine software (like QEMU, for instance) literally has
|
|
||||||
to do the grunt work of emulating the behavior a motherboard's
|
|
||||||
[controller chips](https://en.wikipedia.org/wiki/Intel_440BX),
|
|
||||||
[buses](https://en.wikipedia.org/wiki/Bus_(computing)), and attached devices
|
|
||||||
(like the drive serving up your disk image).
|
|
||||||
|
|
||||||
Let's also look at why booting a VM this way might be annoying for a developer.
|
|
||||||
Because all of your VM's files are trapped in a disk image file this means that
|
|
||||||
you have run an extra command to `mount` the disk image on some sort of loopback
|
|
||||||
device. If you use a QEMU Qcow image you have to do an extra step of mapping
|
|
||||||
the image to a
|
|
||||||
[network block device](https://www.qemu.org/docs/master/tools/qemu-nbd.html).
|
|
||||||
Some of these things may require administrative/`root` privileges without
|
|
||||||
special configuration magic. Even worse, you often can't directly write to a
|
|
||||||
running VM's filesystem without first turning off the virtual machine! This
|
|
||||||
leads users down iSCSI, NFS, SMB, and SSH rabbit holes if they want to poke at
|
|
||||||
the filesystems of running VMs. What if there was a better way?
|
|
||||||
|
|
||||||
With 9p filesystems, you can inject the filesystem directly into a mapped space of
|
|
||||||
guest's kernel without the baggage of emulating block devices and running
|
|
||||||
traditional filesystems designed for physical disks. You can directly modify
|
|
||||||
the filesystems of a running VM in situ without any catastrophic consequences.
|
|
||||||
You can even map the permissions of the shared filesystem to the user account
|
|
||||||
running the VM.
|
|
||||||
|
|
||||||
Meaning on your VM you can have this on the mapped guest 9p filesystem:
|
|
||||||
|
|
||||||
```
|
|
||||||
root@ubuntu-server:~# ls /
|
|
||||||
total 32K
|
|
||||||
drwxr-xr-x 1 1000 1000 266 Aug 7 05:15 .
|
|
||||||
drwxr-xr-x 1 1000 1000 266 Aug 7 05:15 ..
|
|
||||||
-rwxr-xr-x 1 1000 1000 6.9K Aug 7 05:10 arch-chroot
|
|
||||||
lrwxrwxrwx 1 root root 7 Apr 22 2024 bin -> usr/bin
|
|
||||||
drwxr-xr-x 1 root root 0 Feb 26 2024 bin.usr-is-merged
|
|
||||||
drwxr-xr-x 1 root root 306 Aug 7 17:26 boot
|
|
||||||
drwxr-xr-x 15 root root 3.7K Aug 8 17:59 dev
|
|
||||||
drwxr-xr-x 1 root root 2.8K Aug 7 18:03 etc
|
|
||||||
drwxr-xr-x 1 root root 0 Apr 22 2024 home
|
|
||||||
lrwxrwxrwx 1 root root 7 Apr 22 2024 lib -> usr/lib
|
|
||||||
drwxr-xr-x 1 root root 0 Apr 8 2024 lib.usr-is-merged
|
|
||||||
lrwxrwxrwx 1 root root 9 Apr 22 2024 lib64 -> usr/lib64
|
|
||||||
drwxr-xr-x 1 root root 0 Aug 7 05:00 media
|
|
||||||
drwxr-xr-x 1 root root 0 Aug 7 05:00 mnt
|
|
||||||
drwxr-xr-x 1 root root 0 Aug 7 05:00 opt
|
|
||||||
dr-xr-xr-x 417 root root 0 Aug 8 17:59 proc
|
|
||||||
drwx------ 1 root root 142 Aug 8 2025 root
|
|
||||||
drwxr-xr-x 15 root root 500 Aug 8 17:59 run
|
|
||||||
lrwxrwxrwx 1 root root 8 Apr 22 2024 sbin -> usr/sbin
|
|
||||||
drwxr-xr-x 1 root root 0 Mar 31 2024 sbin.usr-is-merged
|
|
||||||
drwxr-xr-x 1 root root 12 Aug 7 17:44 snap
|
|
||||||
drwxr-xr-x 1 root root 0 Aug 7 05:00 srv
|
|
||||||
dr-xr-xr-x 13 root root 0 Aug 8 17:59 sys
|
|
||||||
drwxrwxrwt 1 root root 640 Aug 8 17:59 tmp
|
|
||||||
drwxr-xr-x 1 root root 94 Aug 7 05:00 usr
|
|
||||||
drwxr-xr-x 1 root root 124 Aug 7 17:44 var
|
|
||||||
```
|
|
||||||
|
|
||||||
...and get this on your host machine:
|
|
||||||
```
|
|
||||||
targetdisk@vm-host:~$ ls 9p/
|
|
||||||
total 32K
|
|
||||||
drwxr-xr-x 1 targetdisk targetdisk 266 Aug 7 00:15 .
|
|
||||||
drwxr-xr-x 1 targetdisk targetdisk 76 Aug 5 14:48 ..
|
|
||||||
-rwxr-xr-x 1 targetdisk targetdisk 6.9K Aug 7 00:10 arch-chroot
|
|
||||||
-rw------- 1 targetdisk targetdisk 7 Apr 22 2024 bin
|
|
||||||
drwx------ 1 targetdisk targetdisk 0 Feb 26 2024 bin.usr-is-merged
|
|
||||||
drwx------ 1 targetdisk targetdisk 306 Aug 7 12:26 boot
|
|
||||||
drwx------ 1 targetdisk targetdisk 128 Aug 7 00:00 dev
|
|
||||||
drwx------ 1 targetdisk targetdisk 2.8K Aug 7 13:03 etc
|
|
||||||
drwx------ 1 targetdisk targetdisk 0 Apr 22 2024 home
|
|
||||||
-rw------- 1 targetdisk targetdisk 7 Apr 22 2024 lib
|
|
||||||
-rw------- 1 targetdisk targetdisk 9 Apr 22 2024 lib64
|
|
||||||
drwx------ 1 targetdisk targetdisk 0 Apr 8 2024 lib.usr-is-merged
|
|
||||||
drwx------ 1 targetdisk targetdisk 0 Aug 7 00:00 media
|
|
||||||
drwx------ 1 targetdisk targetdisk 0 Aug 7 00:00 mnt
|
|
||||||
drwx------ 1 targetdisk targetdisk 0 Aug 7 00:00 opt
|
|
||||||
drwx------ 1 targetdisk targetdisk 0 Apr 22 2024 proc
|
|
||||||
drwx------ 1 targetdisk targetdisk 142 Aug 8 12:59 root
|
|
||||||
drwx------ 1 targetdisk targetdisk 44 Aug 7 00:06 run
|
|
||||||
-rw------- 1 targetdisk targetdisk 8 Apr 22 2024 sbin
|
|
||||||
drwx------ 1 targetdisk targetdisk 0 Mar 31 2024 sbin.usr-is-merged
|
|
||||||
drwx------ 1 targetdisk targetdisk 12 Aug 7 12:44 snap
|
|
||||||
drwx------ 1 targetdisk targetdisk 0 Aug 7 00:00 srv
|
|
||||||
drwx------ 1 targetdisk targetdisk 0 Apr 22 2024 sys
|
|
||||||
drwx------ 1 targetdisk targetdisk 478 Aug 8 12:59 tmp
|
|
||||||
drwx------ 1 targetdisk targetdisk 94 Aug 7 00:00 usr
|
|
||||||
drwx------ 1 targetdisk targetdisk 124 Aug 7 12:44 var
|
|
||||||
```
|
|
||||||
<a name="teal-deer">
|
|
||||||
|
|
||||||
## Installing Ubuntu Server to a 9p filesystem
|
|
||||||
|
|
||||||
### Get Ubuntu Server
|
|
||||||
First, download the
|
|
||||||
[Ubuntu Server installer ISO](https://ubuntu.com/download/server)
|
|
||||||
from [Ubuntu's website](https://ubuntu.com/).
|
|
||||||
|
|
||||||
### Start the VM
|
|
||||||
Make a directory you'd like to export as a `9p` filesystem. For the purposes of
|
|
||||||
this demonstration, we'll call our directory `ubuntu-9p`:
|
|
||||||
```bash
|
|
||||||
mkdir ubuntu-9p
|
|
||||||
```
|
|
||||||
|
|
||||||
Now you can run your installer VM with your Ubuntu ISO attached and your 9p
|
|
||||||
filesystem mapped and exported! You'll need to substitute the path for
|
|
||||||
`UBUNTU_ISO` to the path of your downloaded Ubuntu Server ISO. I threw on some
|
|
||||||
extra flags to enable some of the extra sandboxing features of QEMU.
|
|
||||||
|
|
||||||
Run the following on your host:
|
|
||||||
```bash
|
|
||||||
qemu-system-$(uname -m) \
|
|
||||||
-cpu max \
|
|
||||||
-enable-kvm \
|
|
||||||
-smp $(nproc) \
|
|
||||||
-nodefaults \
|
|
||||||
-no-user-config \
|
|
||||||
-nographic \
|
|
||||||
-chardev stdio,id=virtcons0 \
|
|
||||||
-device virtio-serial-pci \
|
|
||||||
-device virtconsole,chardev=virtcons0 \
|
|
||||||
-m 8G \
|
|
||||||
-net user,hostfwd=tcp::2221-:22 \
|
|
||||||
-net nic \
|
|
||||||
-device virtio-9p-pci,id=fs0,fsdev=fsdev-fs0,mount_tag=fs0 \
|
|
||||||
-sandbox on,obsolete=deny,elevateprivileges=deny,spawn=deny,resourcecontrol=deny \
|
|
||||||
-drive file=UBUNTU_ISO,media=cdrom,id=virtiso1 \
|
|
||||||
-fsdev local,security_model=mapped,id=fsdev-fs0,multidevs=remap,path=ubuntu-9p
|
|
||||||
```
|
|
||||||
|
|
||||||
This will start a virtual machine with the local directory `ubuntu-9p` mapped to
|
|
||||||
a 9p filesystem on the guest named `fs0`.
|
|
||||||
|
|
||||||
### Get to a shell
|
|
||||||
After a little wait the VM should boot into the text-mode Ubuntu installer
|
|
||||||
interface. At the time of writing the Ubuntu installer doesn't support
|
|
||||||
installing to systems without block devices. This means we will have to install
|
|
||||||
by other means in a shell on our booted install media.
|
|
||||||
|
|
||||||
Select `Enter shell` from the `[ Help ]` menu.
|
|
||||||
|
|
||||||
```
|
|
||||||
================================================================================
|
|
||||||
Serial ┌──────────────[ Help ]┐
|
|
||||||
=======================================================│ Help on this screen │=
|
|
||||||
│ Keyboard shortcuts │
|
|
||||||
As the installer is running on a serial console, it h│ Enter shell │
|
|
||||||
mode, using only the ASCII character set and black an│ View error reports │
|
|
||||||
├──────────────────────┤
|
|
||||||
If you are connecting from a terminal emulator such a│ About this installer │
|
|
||||||
supports unicode and rich colours you can switch to "│ Help on SSH access │
|
|
||||||
unicode, colours and supports many languages. ├──────────────────────┤
|
|
||||||
│ Toggle rich mode │
|
|
||||||
You can also connect to the installer over the networ└──────────────────────┘
|
|
||||||
allow use of rich mode.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[ Continue in rich mode > ]
|
|
||||||
[ Continue in basic mode > ]
|
|
||||||
[ View SSH instructions ]
|
|
||||||
```
|
|
||||||
|
|
||||||
If during this install process you want a bigger terminal you can `exit` the
|
|
||||||
shell and select `Help on SSH access`. You'll get the name of the `installer`
|
|
||||||
account and a password that was randomly-generated when you booted the Ubuntu
|
|
||||||
live installer media.
|
|
||||||
|
|
||||||
```
|
|
||||||
┌────────────────────────── Help on SSH access ──────────────────────────┐
|
|
||||||
│ │
|
|
||||||
│ It is possible to connect to the installer over the network, which │
|
|
||||||
│ might allow the use of a more capable terminal and can offer more │
|
|
||||||
│ languages than can be rendered in the Linux console. │
|
|
||||||
│ │
|
|
||||||
│ To connect, SSH to installer@10.0.2.15. │
|
|
||||||
│ │
|
|
||||||
│ The password you should use is "Qhs_3:@C^#H'nw`4rd6%". │
|
|
||||||
│ │
|
|
||||||
│ │
|
|
||||||
│ │
|
|
||||||
│ [ Close ] │
|
|
||||||
│ │
|
|
||||||
└────────────────────────────────────────────────────────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
In another terminal on your host machine `ssh` like so:
|
|
||||||
```bash
|
|
||||||
ssh -p 2221 installer@127.0.0.1
|
|
||||||
```
|
|
||||||
|
|
||||||
If you run the VM multiple times, you might have to edit your
|
|
||||||
`~/.ssh/known_hosts` file to edit the host fingerprint entry for the `127.0.0.1:2221`
|
|
||||||
host.
|
|
||||||
|
|
||||||
### Mount your 9p filesystem
|
|
||||||
Now that you have a working shell, you'll need to mount the 9p filesystem:
|
|
||||||
```
|
|
||||||
root@ubuntu-server:/# mount -t 9p -o trans=virtio fs0 /mnt
|
|
||||||
```
|
|
||||||
|
|
||||||
### Bootstrap the base Ubuntu system
|
|
||||||
With the destination 9p filesystem mounted, it's now time to bootstrap a base
|
|
||||||
Ubuntu installation to it. The Ubuntu Server installation media at the time of
|
|
||||||
writing does not include the `debootstrap` tool so we'll have to install it.
|
|
||||||
|
|
||||||
First, update the package lists:
|
|
||||||
```
|
|
||||||
root@ubuntu-server:/# apt update
|
|
||||||
```
|
|
||||||
|
|
||||||
Now, install the `debootstrap` tool:
|
|
||||||
```
|
|
||||||
root@ubuntu-server:/# apt install debootstrap
|
|
||||||
```
|
|
||||||
|
|
||||||
It's time to begin bootstrapping our base system. You'll need the shortened
|
|
||||||
codename of Ubuntu release you'd like to install. For instance, if
|
|
||||||
you were installing Ubuntu 20.04 "Noble Numbat," you'd use the short name
|
|
||||||
`noble`.
|
|
||||||
*(See [#2](#no2) for more details.)*
|
|
||||||
|
|
||||||
Bootstrap the new system with the `debootstrap` tool like so:
|
|
||||||
```
|
|
||||||
root@ubuntu-server:/# debootstrap noble /mnt
|
|
||||||
```
|
|
||||||
|
|
||||||
### Change root to the target system
|
|
||||||
For the rest of the installation process, the rest of the steps will need to be
|
|
||||||
performed from a shell on the target system we just bootstrapped. To do this,
|
|
||||||
we'll need to pass some pseudo-filesystems on from our live installation
|
|
||||||
environment and execute the `chroot` command to "change root" into the target
|
|
||||||
that lives on our 9p filesystem.
|
|
||||||
|
|
||||||
First, let's pass over the live environment's pseudo-filesystems as `bind`
|
|
||||||
mounts:
|
|
||||||
```
|
|
||||||
root@ubuntu-server:/# mount -o bind /proc /mnt/proc
|
|
||||||
root@ubuntu-server:/# mount -o bind /dev /mnt/dev
|
|
||||||
root@ubuntu-server:/# mount -o bind /dev/pts /mnt/dev/pts
|
|
||||||
root@ubuntu-server:/# mount -o bind /sys /mnt/sys
|
|
||||||
```
|
|
||||||
|
|
||||||
Now change root to the 9p filesystem:
|
|
||||||
```
|
|
||||||
root@ubuntu-server:/# chroot /mnt /usr/bin/bash
|
|
||||||
```
|
|
||||||
|
|
||||||
### Installing a kernel
|
|
||||||
The earlier `debootstrap` command line installed most of the components of a
|
|
||||||
working system, but not quite all of them. The next thing you'll need to do is
|
|
||||||
install a Linux kernel. Later on you'll be passing this kernel and its
|
|
||||||
associated initial RAM disk image as command-line flags to QEMU as `-kernel` and
|
|
||||||
`-initrd`, respectively.
|
|
||||||
|
|
||||||
We're going to pick the `linux-virtual` package here for a smaller footprint on
|
|
||||||
the host machine:
|
|
||||||
```
|
|
||||||
root@ubuntu-server:/# apt install linux-virtual
|
|
||||||
```
|
|
||||||
|
|
||||||
### Enable 9p kernel modules
|
|
||||||
To allow the installed system to boot properly, you'll need to add 9p kernel
|
|
||||||
modules to the initial RAM disk image. The following lines need to be appended
|
|
||||||
to the end of `/etc/initramfs-tools/modules`:
|
|
||||||
```
|
|
||||||
9p
|
|
||||||
9pnet
|
|
||||||
9pnet_virtio
|
|
||||||
```
|
|
||||||
|
|
||||||
You can add them with an editor like `vi` or with shell I/O redirects like so:
|
|
||||||
```
|
|
||||||
root@ubuntu-server:/# cd /etc/initramfs-tools
|
|
||||||
root@ubuntu-server:/etc/initramfs-tools# echo 9p >> modules
|
|
||||||
root@ubuntu-server:/etc/initramfs-tools# echo 9pnet >> modules
|
|
||||||
root@ubuntu-server:/etc/initramfs-tools# echo 9pnet_virtio >> modules
|
|
||||||
```
|
|
||||||
|
|
||||||
The lines added to `/etc/initramfs-tools/modules` tell Ubuntu's scripts to
|
|
||||||
include the `9p`, `9pnet`, and `9pnet_virtio` kernel modules in the initial RAM
|
|
||||||
disk image. With that done, update the initial RAM filesystem:
|
|
||||||
```
|
|
||||||
root@ubuntu-server:/# update-initramfs -u
|
|
||||||
```
|
|
||||||
|
|
||||||
### Enable DHCP on boot
|
|
||||||
To get internet access when your VM boots, you'll need to configure a network
|
|
||||||
interface. The VM can automatically get an IP address and a gateway at with
|
|
||||||
DHCP enabled on its virtual network interface (`ens2` on my VM). Ubuntu has
|
|
||||||
this ~~terrible~~ thing called [netplan](https://netplan.io/) in its
|
|
||||||
base installation that can be used to configure network interfaces. Since it's
|
|
||||||
already here, we might as well use it.
|
|
||||||
|
|
||||||
Get the name of the virtual Ethernet interface with the `ip` command:
|
|
||||||
```
|
|
||||||
root@ubuntu-server:/# ip a
|
|
||||||
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
|
|
||||||
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
|
|
||||||
inet 127.0.0.1/8 scope host lo
|
|
||||||
valid_lft forever preferred_lft forever
|
|
||||||
inet6 ::1/128 scope host noprefixroute
|
|
||||||
valid_lft forever preferred_lft forever
|
|
||||||
2: ens2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
|
|
||||||
link/ether 52:54:00:12:34:56 brd ff:ff:ff:ff:ff:ff
|
|
||||||
altname enp0s2
|
|
||||||
inet 10.0.2.15/24 metric 100 brd 10.0.2.255 scope global dynamic ens2
|
|
||||||
valid_lft 85077sec preferred_lft 85077sec
|
|
||||||
inet6 fec0::5054:ff:fe12:3456/64 scope site dynamic mngtmpaddr noprefixroute
|
|
||||||
valid_lft 86078sec preferred_lft 14078sec
|
|
||||||
inet6 fe80::5054:ff:fe12:3456/64 scope link
|
|
||||||
valid_lft forever preferred_lft forever
|
|
||||||
```
|
|
||||||
|
|
||||||
Your network interface should be named something like `ens2`. With that known,
|
|
||||||
tell the `netplan` command to enable DHCPv4 on the interface like so:
|
|
||||||
```
|
|
||||||
root@ubuntu-server:/# netplan set --origin-hint ens2 ethernets.ens2.dhcp4=true
|
|
||||||
```
|
|
||||||
|
|
||||||
This will create a YAML file with the `.yaml` extension in `/etc/netplan` that
|
|
||||||
has `ens2` somewhere in the name. Hints are merely suggestions, after all.
|
|
||||||
|
|
||||||
### Set root password
|
|
||||||
There's one last thing you need to do before you can enjoy your newly-installed
|
|
||||||
VM: set a `root` password! You can do it by invoking the `passwd` command with
|
|
||||||
no arguments:
|
|
||||||
```
|
|
||||||
root@ubuntu-server:/# passwd
|
|
||||||
New password:
|
|
||||||
Retype new password:
|
|
||||||
passwd: password updated successfully
|
|
||||||
```
|
|
||||||
|
|
||||||
With the password set, you may now `exit` the changed-root shell and `poweroff`
|
|
||||||
the installer VM.
|
|
||||||
|
|
||||||
## Enjoying your VM
|
|
||||||
You can now boot your new VM with the following command:
|
|
||||||
```
|
|
||||||
qemu-system-$(uname -m) \
|
|
||||||
-cpu max \
|
|
||||||
-enable-kvm \
|
|
||||||
-smp $(nproc) \
|
|
||||||
-nodefaults \
|
|
||||||
-no-user-config \
|
|
||||||
-nographic \
|
|
||||||
-chardev stdio,id=virtcons0 \
|
|
||||||
-device virtio-serial-pci \
|
|
||||||
-device virtconsole,chardev=virtcons0 \
|
|
||||||
-m 8G \
|
|
||||||
-net user,hostfwd=tcp::2222-:22 \
|
|
||||||
-net nic \
|
|
||||||
-device virtio-9p-pci,id=fs0,fsdev=fsdev-fs0,mount_tag=fs0 \
|
|
||||||
-sandbox on,obsolete=deny,elevateprivileges=deny,spawn=deny,resourcecontrol=deny \
|
|
||||||
-kernel ubuntu-9p/boot/$(<vmlinuz) \
|
|
||||||
-append "earlyprintk=ttyS0 root=fs0 rw rootfstype=9p rootflags=trans=virtio,version=9p2000.L,msize=5000000,cache=mmap,posixacl console=ttyS0" \
|
|
||||||
-initrd ubuntu-9p/boot/$(<initrd.img) \
|
|
||||||
-fsdev local,security_model=mapped,id=fsdev-fs0,multidevs=remap,path=ubuntu-9p
|
|
||||||
```
|
|
||||||
|
|
||||||
After a little wait, you should be greeted with a text-mode `getty` login prompt.
|
|
||||||
Log into the `root` account with the password you set earlier.
|
|
||||||
|
|
||||||
### Logging with SSH
|
|
||||||
If you would like to log in with SSH, you'll need to install the OpenSSH server
|
|
||||||
software and configure it. Install it like so:
|
|
||||||
```
|
|
||||||
root@ubuntu-server:~# apt install openssh-server
|
|
||||||
```
|
|
||||||
|
|
||||||
The Ubuntu install scripts for the OpenSSH server package should enable the
|
|
||||||
daemon automatically, but you won't be able to get in yet. To do that, you'll
|
|
||||||
need to copy a public key from your host so you can log in. If you don't
|
|
||||||
already have a key, you can make one with `ssh-keygen`.
|
|
||||||
|
|
||||||
Once you have a key that you'd like to use, make a place to put it on the guest
|
|
||||||
VM:
|
|
||||||
```
|
|
||||||
root@ubuntu-server:~# mkdir .ssh
|
|
||||||
root@ubuntu-server:~# chmod 700 .ssh
|
|
||||||
root@ubuntu-server:~# touch .ssh/authorized_keys
|
|
||||||
root@ubuntu-server:~# chmod 600 .ssh/authorized_keys
|
|
||||||
```
|
|
||||||
|
|
||||||
In another terminal on your host machine, add the public key you'd like to use to
|
|
||||||
the end of the `authorized_keys` file like so:
|
|
||||||
```
|
|
||||||
targetdisk@vm-host:~$ cat ~/.ssh/id_ed25519.pub >> ubuntu-9p/root/.ssh/authorized_keys
|
|
||||||
```
|
|
||||||
|
|
||||||
Now you can log in to the VM with the following command:
|
|
||||||
```bash
|
|
||||||
ssh -p 2222 root@127.0.0.1
|
|
||||||
```
|
|
||||||
|
|
||||||
## Conclusion
|
|
||||||
That's it! You now have a working minimal Ubuntu server installation that you
|
|
||||||
can use and abuse from within and without, thanks to the Plan 9 filesystem!
|
|
||||||
You'll probably want to save the long QEMU command to a shell script so that
|
|
||||||
you can quickly boot up your VM later.
|
|
||||||
|
|
||||||
## SEE ALSO
|
|
||||||
1. <a name="no1">[Why did Plan 9's creators give up on Plan 9?](https://fqa.9front.org/fqa0.html#0.2.3)
|
|
||||||
via [9front](https://9front.org)
|
|
||||||
2. <a name="no2">[Ubuntu Version History](https://en.wikipedia.org/wiki/Ubuntu_version_history) via [Wikipedia](https://wikipedia.org)
|
|
||||||
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" name="viewport" content="width=device-width, initial-scale=1">
|
<meta charset="utf-8">
|
||||||
<link rel="stylesheet" href="page.css" />
|
<link rel="stylesheet" href="page.css" />
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<div class="fc">
|
<div class="fc">
|
||||||
<img src="/~targetdisk/blob/andrea0s-plain-noextfonts.svg" />
|
<img src="andrea0s-plain-noextfonts.svg" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|
|
||||||
18
page.css
18
page.css
|
|
@ -3,10 +3,6 @@ body {
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
pre code {
|
|
||||||
font-family: AnonymicePro Nerd Font;
|
|
||||||
}
|
|
||||||
|
|
||||||
.black {
|
.black {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
|
|
@ -53,13 +49,6 @@ pre code {
|
||||||
margin: 0.7pt;
|
margin: 0.7pt;
|
||||||
padding: 2%;
|
padding: 2%;
|
||||||
background-color: #ffffff;
|
background-color: #ffffff;
|
||||||
max-width: 100%;
|
|
||||||
overflow-x: auto;
|
|
||||||
|
|
||||||
img {
|
|
||||||
max-width: 100%;
|
|
||||||
height: auto;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.content-border-right {
|
.content-border-right {
|
||||||
|
|
@ -141,10 +130,5 @@ pre code {
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: Ebrima;
|
font-family: Ebrima;
|
||||||
src: url(/~targetdisk/blob/ebrimabd.ttf);
|
src: url(ebrimabd.ttf);
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: AnonymicePro Nerd Font;
|
|
||||||
src: url(/~targetdisk/blob/AnonymiceProNerdFontMono-Regular.ttf);
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,92 +1,55 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
HEADING='Posts'
|
|
||||||
TITLE="Andrea's blog"
|
|
||||||
BASENAME=${BASENAME-blog}
|
|
||||||
BASE_URL=${BASE_URL-https://sqt.wtf}
|
|
||||||
DESCRIPTION="Andrea's personal blog."
|
|
||||||
N_DESC_CHARS=500
|
|
||||||
|
|
||||||
articles=( $BASENAME/*.md )
|
|
||||||
|
|
||||||
cat <<HDR
|
cat <<HDR
|
||||||
<div class="inner">
|
<div class="inner">
|
||||||
<h1>$HEADING</h1>
|
<h1>Posts</h1>
|
||||||
<dl> <!-- no longer me -->
|
<dl> <!-- no longer me -->
|
||||||
HDR
|
HDR
|
||||||
|
|
||||||
cat > blog/feed.xml <<RSSHDR
|
for blog_post_md in blog/*.md; do
|
||||||
<rss version="2.0">
|
date=$(grep -o '[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}' <<<"$blog_post_md")
|
||||||
<channel>
|
title=$(grep -m 1 '^#\s\+' "$blog_post_md" | sed 's/^#\s\+//')
|
||||||
<title>$TITLE</title>
|
html=$(sed 's/\.md$/.html/' <<<"$blog_post_md")
|
||||||
<link>$BASE_URL/$BASENAME.html</link>
|
|
||||||
<description>$DESCRIPTION</description>
|
|
||||||
RSSHDR
|
|
||||||
|
|
||||||
for ((i=${#articles[@]}-1; i>=0; i--)); do
|
|
||||||
post_md=${articles[$i]}
|
|
||||||
date=$(grep -o '[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}' <<<"$post_md")
|
|
||||||
title=$(grep -m 1 '^#\s\+' "$post_md" | sed 's/^#\s\+//')
|
|
||||||
html=$(sed 's/\.md$/.html/' <<<"$post_md")
|
|
||||||
rss_desc=$(grep -v '^\s*$' "$post_md" | grep -v '^\s*\*by' | grep -v '^#' | grep -v '^\s*!\[' | grep -v '<.\+>'| head -c $N_DESC_CHARS)'...'
|
|
||||||
|
|
||||||
cat <<INNIE
|
cat <<INNIE
|
||||||
<dt>$date</dt>
|
<dt>$date</dt>
|
||||||
<dd><a href="$html">$title</a></dd>
|
<dd><a href="$html">$title</a></dd>
|
||||||
INNIE
|
INNIE
|
||||||
|
|
||||||
cat >> $BASENAME/feed.xml <<RSSINNIE
|
|
||||||
<item>
|
|
||||||
<title>$title</title>
|
|
||||||
<link>$BASE_URL/~targetdisk/$html</link>
|
|
||||||
<description>$rss_desc</description>
|
|
||||||
<pubDate>$(date -d "$date" '+%a, %d %b %Y %H:%M:%S %Z')</pubDate>
|
|
||||||
</item>
|
|
||||||
RSSINNIE
|
|
||||||
done
|
done
|
||||||
|
|
||||||
cat <<FTR # Short for Fetterman
|
cat <<FTR # Short for Fetterman
|
||||||
</dl> <!-- no longer on the dl -->
|
</dl> <!-- no longer on the dl -->
|
||||||
<p><a href="/~targetdisk/$BASENAME/feed.xml">RSS</a></p>
|
|
||||||
|
<h2>Other People's Posts</h2>
|
||||||
|
{{range .Articles}}
|
||||||
|
<div>
|
||||||
|
<h4 class="title" dir="auto">
|
||||||
|
<a href="{{.Link}}" target="_blank" rel="noopener">{{.Title}}</a>
|
||||||
|
</h4>
|
||||||
|
<p class="summary" dir="auto">{{.Summary}}</p>
|
||||||
|
<small class="source">
|
||||||
|
via <a href="{{.SourceLink}}">{{.SourceTitle}}</a>
|
||||||
|
</small>
|
||||||
|
<small class="date">{{.Date | datef "January 2, 2006"}}</small>
|
||||||
</div>
|
</div>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
</br></br>
|
||||||
|
<small>
|
||||||
|
<p>
|
||||||
|
Generated by
|
||||||
|
<a href="https://git.sr.ht/~sircmpwn/openring">openring</a>
|
||||||
|
</p>
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.webring .title {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
.webring .summary {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
flex: 1 1 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
FTR
|
FTR
|
||||||
|
|
||||||
#
|
|
||||||
# <h2>Other People's Posts</h2>
|
|
||||||
# {{range .Articles}}
|
|
||||||
# <div>
|
|
||||||
# <h4 class="title" dir="auto">
|
|
||||||
# <a href="{{.Link}}" target="_blank" rel="noopener">{{.Title}}</a>
|
|
||||||
# </h4>
|
|
||||||
# <p class="summary" dir="auto">{{.Summary}}</p>
|
|
||||||
# <small class="source">
|
|
||||||
# via <a href="{{.SourceLink}}">{{.SourceTitle}}</a>
|
|
||||||
# </small>
|
|
||||||
# <small class="date">{{.Date | datef "January 2, 2006"}}</small>
|
|
||||||
# </div>
|
|
||||||
# {{end}}
|
|
||||||
#
|
|
||||||
# </br></br>
|
|
||||||
# <small>
|
|
||||||
# <p>
|
|
||||||
# Generated by
|
|
||||||
# <a href="https://git.sr.ht/~sircmpwn/openring">openring</a>
|
|
||||||
# </p>
|
|
||||||
# </small>
|
|
||||||
#</div>
|
|
||||||
#
|
|
||||||
#<style>
|
|
||||||
#.webring .title {
|
|
||||||
# margin: 0;
|
|
||||||
#}
|
|
||||||
#.webring .summary {
|
|
||||||
# font-size: 0.8rem;
|
|
||||||
# flex: 1 1 0;
|
|
||||||
#}
|
|
||||||
#</style>
|
|
||||||
#FTR
|
|
||||||
|
|
||||||
cat >> $BASENAME/feed.xml <<RSSFTR
|
|
||||||
</channel>
|
|
||||||
</rss>
|
|
||||||
RSSFTR
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue