- Install qemu
brew install qemu
- Download QEMU_EFI.fd
Get one of the .tar.gz
from the following link.
https://gist.github.com/theboreddev/5f79f86a0f163e4a1f9df919da5eea20
I pick QEMU_EFI-a096471-edk2-stable202011.tar.gz
.
curl -O https://gist.githubusercontent.com/theboreddev/5f79f86a0f163e4a1f9df919da5eea20/raw/f546faea68f4149c06cca88fa67ace07a3758268/QEMU_EFI-a096471-edk2-stable202011.tar.gz
Decompress to get QEMU_EFI.fd
.
tar -xvf QEMU_EFI-a096471-edk2-stable202011.tar.gz
- Download Ubuntu cloud image
Download it from Ubuntu.
curl -O https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-arm64.img
- Generate SSH key pair
ssh-keygen -t ed25519 -C "my_testing_key" -f "id_ed25519" -N '' <<< y
The above command will generate 2 files id_ed25519
(Private key) and id_ed25519.pub
(Public key).
- Create user-data file (
cloud-init
configuration)
public_key=$(cat id_ed25519.pub)
cat << EOF > user-data
#cloud-config
users:
- name: franz
shell: /bin/bash
sudo: "ALL=(ALL) NOPASSWD:ALL"
primary_group: my_test_group
groups: sudo
lock_passwd: true
ssh_authorized_keys:
- "${public_key}"
groups:
- my_test_group
disable_root: true
mounts:
- ["shared", "/mnt/raw-shared", "9p", "trans=virtio,version=9p2000.L", "0", "0"]
- ["/mnt/raw-shared", "/mnt/shared", "fuse.bindfs", "map=501/1000:@20/@1000", "0", "0"]
output:
all: ">> /var/log/cloud-init-output.log"
package_update: true
packages:
- bindfs
runcmd:
- groupmod -g 1000 my_test_group
- ufw default deny incoming
- ufw default allow outgoing
- ufw allow 22/tcp
- ufw enable
- sed -i -e '/^PermitRootLogin/s/^.*$/PermitRootLogin no/' /etc/ssh/sshd_config
- sed -i -e '$aAllowUsers franz' /etc/ssh/sshd_config
- systemctl restart ssh
EOF
- Create vendor-data file (
cloud-init
configuration)
touch vendor-data
- Create meta-data file (
cloud-init
configuration)
cat << EOF > meta-data
instance-id: my-test-instance
EOF
- Start ad hoc IMDS server
IMDS stands for "Instance Metadata Service". It can expose cloud-init
configuration to VM.
(This command blocks. You need to start another terminal session for the remaining steps.)
python3 -m http.server --directory .
- Create shared folder
mkdir -p shared
- Enlarge cloud image
qemu-img resize noble-server-cloudimg-arm64.img +50G
- Start VM with qemu
(This command blocks. You need to start another terminal session for the remaining steps.)
qemu-system-aarch64 \
-machine type=virt-9.0,accel=hvf \
-bios QEMU_EFI.fd \
-cpu host \
-m 1024 \
-nographic \
-hda noble-server-cloudimg-arm64.img \
-virtfs local,path=shared,mount_tag=shared,security_model=mapped-xattr \
-smbios type=1,serial=ds='nocloud;s=http://10.0.2.2:8000/' \
-netdev user,id=mynet0,hostfwd=tcp::2222-:22 \
-device e1000,netdev=mynet0
-m 1024
- Allocate 1024MB memory
-virtfs local,path=shared,mount_tag=shared,security_model=mapped-xattr
- Share host folder shared
with the VM
-smbios type=1,serial=ds='nocloud;s=http://10.0.2.2:8000/
- Tell cloud-init
where IMDS is
-hda noble-server-cloudimg-arm64.img
- Use cloud image as virtual hard disk
-netdev user,id=mynet0,hostfwd=tcp::2222-:22
- Map host port 2222
to VM port 22
- Connect to VM
ssh -p 2222 -i "id_ed25519" franz@localhost
- Wait for
cloud-init
complete
(Run in VM)
sudo cloud-init status --wait
-
Reboot VM
-
Check shared folder
(Run in VM)
ls -l -d /mnt/shared
That's it.