Objective is to create a disposable, minimal Alpine Linux install in FreeBSD bhyve that allows you to run docker containers. The storage for docker is on your FreeBSD host mounted using NFS. You should be able to rebuild the bhyve VM at any time and replace it with the latest version.
Bootstrap Alpine Linux on FreeBSD bhyve
All content is hosted in on Github. This article is stand-alone from the earlier article.
Objective is to create a disposable, minimal Alpine Linux install in FreeBSD bhyve that allows you to run docker containers. The storage for docker is on your FreeBSD host mounted using NFS. You should be able to rebuild the bhyve VM at any time and replace it with the latest version. Description of this is planned to be a next blog-post.
All content is hosted in on Github in the FreeBSD
branch of the repo.
Prepare FreeBSD
Assumptions:
- You have a bhyve capable FreeBSD host;
- You have the vm-bhyve port installed, configured to use ZFS dataset
zroot/bhyve
mounted on/vm
for storage, already initialized usingvm init
; - You have the bhyve-firmware port installed;
- You have a working NFS configuration on your system;
- You have configured NFS with an export that is usable by your to-be-created VM for Docker storage.
Getting the installer image
Get the latest Alpine "Virtual" iso link (also available in this git repo as get-latest-alpine.py
)
#!/usr/bin/env python3
import urllib.request
import yaml
BASE_URL = "https://dl-cdn.alpinelinux.org/alpine/latest-stable/releases/x86_64"
with urllib.request.urlopen(f"{BASE_URL}/latest-releases.yaml") as response:
data = yaml.safe_load(response.read().decode())
iso = [flavor["iso"] for flavor in data if flavor["flavor"] == "alpine-virt"][0]
print(f"{BASE_URL}/{iso}")
Use the generated URL to download it into the vm-bhyve ISO store.
vm iso https://dl-cdn.alpinelinux.org/alpine/latest-stable/releases/x86_64/alpine-virt-3.17.2-x86_64.iso
You'll need the filename alpine-virt-3.17.2-x86_64.iso
later on during the install stage.
Create and configure the bhyve VM
Create the Docker VM and the swap ZFS volume. We don't need ZFS snapshots of the swap so we'll put it in a child dataset. At the time of writing, /boot
used 18MB and /
used 335MB.
Create bhyve VM
vm create -t alpine -s 512M Docker
zfs create zroot/bhyve/Docker/swap
The vm
command creates the ZFS dataset zroot/bhyve/Docker
which will be mounted on /vm/Docker
. A disk0.img
sparse file of 512MB and configuration file Docker.conf
based off of the "alpine" template are created as well. Further configuration of the disk is done by the Alpine installer.
Following commands in FreeBSD are run from the /vm/Docker
directory.
cd /vm/Docker
Create storage files
Create the storage files for the swap file and the overlay.
Create the APKOVL image and add a FAT volume.
truncate -s 32M apkovl.img
mdapk=$(mdconfig apkovl.img)
gpart create -s GPT /dev/${mdapk}
gpart add -t linux-data -l apkovl -a 4k ${mdapk}
newfs_msdos /dev/${mdapk}p1
mdconfig -d -u ${mdapk}
Create the swap image and partition. Initializing swap happens in the Alpine install stage.
truncate -s 1024M swap/swap1.img
mdswp=$(mdconfig swap/swap1.img)
gpart create -s GPT /dev/${mdswp}
gpart add -i 1 -t linux-swap /dev/${mdswp}
mdconfig -d -u ${mdswp}
Update the VM configuration
Edit the generated configuration file Docker.conf
. Change/add the following items
- add
disk1
anddisk2
_name
and_type
for swap and APKOVL. - All
grub
entries: change-vanilla
to-virt
- The
grub_run0
entry: changeroot
to/dev/vda2
- Add the
grub_run_partition=2
entry
You can use the network0_mac
to provide your VM with a default IP via dhcp.
loader="grub"
cpu=1
memory=512M
network0_type="virtio-net"
network0_switch="public"
disk0_type="virtio-blk"
disk0_name="disk0.img"
disk1_type="virtio-blk"
disk1_name="swap/disk1.img"
disk2_type="virtio-blk"
disk2_name="apkovl.img"
grub_install0="linux /boot/vmlinuz-virt initrd=/boot/initramfs-virt alpine_dev=cdrom:iso9660 modules=loop,squashfs,sd-mod,usb-storage,sr-mod"
grub_install1="initrd /boot/initramfs-virt"
grub_run_partition=2
grub_run1="linux /boot/vmlinuz-virt root=/dev/vda2 modules=ext4"
grub_run2="initrd /boot/initramfs-virt"
uuid="ca77e22d-b60e-11ed-8105-84a93843eb75"
network0_mac="de:ad:be:ef:ca:fe"
Now we're ready to create the bootstrap content.
Prepare the bootstrap content
Use the make.sh
script in this directory to create the overlay image that will be used by the Alpine ISO install.
You can influence the result with the following environment variables
Variable | default | function |
---|---|---|
HOSTNAME |
docker |
The hostname that the VM will use (can be a FQDN) |
PUBKEY |
/root/.ssh/id_ed25519.pub |
The SSH public key that can be used to login to the VM via SSH as root |
APKOVLIMG |
/vm/Docker/apkovl.img |
The disk image file that the bhyve VM will use |
APKOVLMNT |
/mnt/apkovl |
Temporary mountpoint for generating the image |
NFSDOCKER |
192.0.2.1:/var/docker |
The NFS location that Docker will use (mounted to /var/lib/docker in the VM) |
DEBUG |
If defined, the installer won't shut down, allowing you to inspect the system |
When the make.sh
script is executed, it will
- Show you the variables and their current settings
- Create the required additional file(s)
- Add/update the apkovl.tar.gz file in the disk image file.
- Clean up temporary mounts
Install Alpine Linux in the bhyve VM
This repo provides an overlay file to initially boot the headless system (leveraging Alpine distro's initramfs
feature): it enables a basic ssh server to log-into from another Computer, in order to finalize system set-up.
Start the installer using the filename that was returned by the get-latest-alpine.py
script
vm install Docker alpine-virt-3.17.2-x86_64.iso
Starting Docker
* found guest in /vm/Docker
* booting...
This will:
- Boot the ISO
- Run the bootstrap.start script from the overlay file
- Poweroff the the VM
If you immediately start the serial console, you can observe the installation steps.
vm console Docker
The installation doesn't take long, query the status using.
vm list
NAME DATASTORE LOADER CPU MEMORY VNC AUTO STATE
Docker default grub 1 512M - No Running (49473)
Once the installation is done, the status changes to "Stopped".
Regular start of the Alpine VM
Starting the vm should create the docker directories and files on your FreeBSD host using the NFS mount.
vm start Docker
You can login to the console or via SSH with the private key belonging to the public key that was configured while building the APKOVL image, or via the console.
vm console Docker
NOTE: This is the time to set a root
password!!! The root
account does not have a password yet, if you have access to the console you get access without a password.
On the FreeBSD system you should now see the directories in /var/docker
.
How to customize further ?
Fork / clone / download this repository and edit to your heart's content. All content is MIT licensed.
The main script file is bootstrap.start.in
. It's just a shell script, make sure you stay close to POSIX compatibility, it's not a full ZSH or bash shell!
Execute ./make.sh
to rebuild the APKOVL image after changes. If you set DEBUG
you drop into a shell at the end of the script so you can inspect your script's results.
Remember to snapshot your vm storage during testing so you can easily roll back.
Credits
Thanks for the original instructions & scripts from @macmpi, and by extension to @sodface and @davidmytton.