Self Hosting: Episode 1 - Hypervisor
Software Used:
Introduction
Before we can deploy any services we need two things. First a place to store those services and two a place to run those services from (i.e storage and compute). These two requirements do not need to run on the same system and for larger self hosted sites or businesses, they probably wont. But for these examples I will present them using a single system.
In these examples I will be utilizing FreeBSD as my compute and storage system. There are other systems out there: Proxmox, XCP-NG, etc. Please feel free to use any/all of these. My preference is FreeBSD because it gives me all the underlying services I need in a rock solid operating system.
Installing Base OS
Installing FreeBSD is straight forward. Chapter 2 of the FreeBSD handbook will walk you through installing FreeBSD on a bare system.
Network Prep
Within the hypervisor we will create separate virtual networks. Each virtual network will be on a separate VLAN. The hypervisor is not required to have an interface on any of the virtual networks. In fact, we don't want it to.
Create Bridge for Virtual Networks
On FreeBSD (as in Linux) a bridge network interface is used to create the virtual network. These commands will create the bridge and rename it to something more meaningful.
ifconfig bridge1 create
ifconfig bridge1 name net-common
ifconfig bridge2 create
ifconfig bridge2 name net-iot
ifconfig bridge3 create
ifconfig bridge3 name net-dmz
ifconfig bridge4 create
ifconfig bridge4 name net-external
Attach each bridge to the appropriate VLAN. Creating VLANs allows this system to communicate with other systems while maintaining the segments. For this example I will assume that the physical interface of the hypervisor is "vmx0". Replace this with the actual physical interface name.
ifconfig vlan10 create
ifconfig vlan10 vlan 10 vlandev vmx0
ifconfig net-common addm vlan10
ifconfig vlan20 create
ifconfig vlan20 vlan 20 vlandev vmx0
ifconfig net-iot addm vlan20
ifconfig vlan30 create
ifconfig vlan30 vlan 30 vlandev vmx0
ifconfig net-dmz addm vlan30
ifconfig vlan90 create
ifconfig vlan90 vlan 90 vlandev vmx0
ifconfig net-external addm vlan90
Next we will update /etc/rc.conf to make sure the changes will take affect on next reboot.
sysrc ifconfig_vlan10="vlan 10 vlandev vmx0
sysrc ifconfig_bridge1="name net-common addm vlan10"
sysrc ifconfig_vlan20="vlan 20 vlandev vmx0
sysrc ifconfig_bridge2="name net-iot addm vlan20"
sysrc ifconfig_vlan30="vlan 30 vlandev vmx0
sysrc ifconfig_bridge3="name net-dmz addm vlan30"
sysrc ifconfig_vlan90="vlan 90 vlandev vmx0
sysrc ifconfig_bridge4="name net-external addm vlan90"
sysrc cloned_interfaces+=" bridge1 vlan10"
sysrc cloned_interfaces+=" bridge2 vlan20"
sysrc cloned_interfaces+=" bridge3 vlan30"
sysrc cloned_interfaces+=" bridge4 vlan90"
Storage Prep
FreeBSD comes with ZFS. If you are not familiar with it see here, here and here for explanations. ZFS provides the many features we will need to hosting our environment.
Create data_dirs
This environment will have data that we want to protect. While ZFS will do everything reasonable to keep the data safe that isn't a 100% guarantee. Setting up our data_dirs will help us determine what data we consider important.
zpool create data01 da2
Now we create a dataset for virtual machine images
zfs create data01/vms
Now we create a dataset for jail'd processes.
zfs create data01/jails
Create a dataset for shared user data.
zfs create data01/user_data
Finally we create a dataset for backups
zfs create data01/backup_data
Virtual machines
Virtual machines can take several different flavors. They can be fully emulated hardware (type 1/2) or just isolated processes in containers (type 3). In this environment both will be used. To start with we will make use of FreeBSD Jails.
Prepare for Jails
To prepare the server for jails add a /etc/jail.conf file
#
.include "/etc/jail.conf.d/*.conf";
/etc/jail.conf
And then enable the jails to start on boot.
service jails enable
One nice feature of ZFS is that it can do snapshots. A snapshot is a exact copy of a dataset at the moment the snapshot is taken. Any updates to the dataset will not update the snapshot. We will use this feature of ZFS to create a snapshot of a jail. Then we will use that jail snapshot when we create new jails. By doing this we make adding new jail very quick.
To prepare the jail template first we create a new dataset.
zfs create -p data01/jails/templates/14.2-RELEASE
Next we will download the FreeBSD base archive and extract into the new dataset.
fetch -o - https://download.freebsd.org/ftp/releases/amd64/amd64/14.2-RELEASE/base.txz | tar -xf - -C /data01/jailes/templates/14.2-RELEASE --unlink
Update the resolv.conf and localtime settings.
cp /etc/resolv.conf /data01/jails/templates/14.2-RELEASE/etc/resolv.conf
cp /etc/localtime /data01/jails/templates/14.2-RELEASE/etc/localtime
Optimally we can perform any OS updates between now and when the base.txz was originally created.
freebsd-update -b /data01/jails/templates/14.2-RELEASE fetch install
Now take a snapshot of the dataset
zfs snapshot data01/jails/templats/14.2-RELEASE@base
An when we are ready to deploy a new jail we will "clone" the dataset for our jail.
zfs clone data01/jails/templates/14.2-RELEASE@base data01/jails/containers/<jailname>
Prepare for Virtual Machines
The virtual machines using Bhyve (the FreeBSD hypervisor) takes a few more steps. First install some packages
pkg install -y vm-bhyve bhyve-firmware edk2-bhyve grub-bhyve
After the packages are installed update the rc.conf with the following variables
sysrc vm_delay=5
sysrc vm_dir=zfs:/data01/vms
Enable the VMs to start on boot
service vm enable
Initialize the VM configuration
/usr/local/sbin/vm init
And finally update the VM config file adding the different segments so they were be available to any VMs.
vm switch create -t manual -b net-iot net-iot
vm switch create -t manual -b net-dmz net-dmz
vm switch create -t manual -b net-common net-common
vm switch create -t manual -b net-external net-external
Now the hypervisor is ready for VMs
Backups
While ZFS is incredibly stable and will do everything it can to protect your data, problems can happen outside of ZFS's control. For those case we need to create a backup. (See discussion on 3-2-1 backup scheme: here, here, here). Perhaps the best tool I've found to automate these backups is Sanoid/Syncoid.
Sanoid
Sanoid is a script that can be called from cron that will create and manage snapshots automatically. This will allow us to protect the files on the filesystem from accidental deletion. However we are not fully protected. If something were to happen to the hose or to enough hard drives all data could be lost. So we need to copy the data off of this system to someplace else.
First install sanoid on the system
pkg install sanoid
Next configure the sanoid.conf file located in /usr/local/etc/sanoid directory
#
[ data01/vms ]
use_template = production
recursive = yes
[ data01/jails ]
use_template = production
recursive = yes
[ data01/data ]
use_template = production
#############################
# templates below this line #
#############################
# name your templates template_templatename. you can create your own, and use them in your module definitions above.
[template_demo]
daily = 60
[template_production]
frequently = 0
hourly = 36
daily = 30
monthly = 3
yearly = 0
autosnap = yes
autoprune = yes
/usr/local/etc/sanoid/sanoid.conf
Finally update crontab using 'crontab -e' command add the sanoid command.
*/15 * * * * TZ=UTC /usr/local/bin/sanoid --cron
Syncoid
Syncoid is also a script run from cron. It will take the snapshots created by Sanoid and ZFS send the snapshots to another system running ZFS. This systems does not need to be FreeBSD.
Syncoid uses the sanoid.conf file to determine what to sync so we only need to specify the destination server. Update cron and specify bkupuser, bkuphost, and bkuppath to tell syncoid where to sync the snapshots.
0 1 * * * TZ=UTC /usr/local/bin/syncoid --no-privilege-elivation --create-bookmark data01/vms <bkupuser>@<bkuphost>:<backuppath>
15 1 * * * TZ=UTC /usr/local/bin/syncoid --no-privilege-elivation --create-bookmark data01/jails <bkupuser>@<bkuphost>:<backuppath>
30 1 * * * TZ=UTC /usr/local/bin/syncoid --no-privilege-elivation --create-bookmark data01/data <bkupuser>@<bkuphost>:<backuppath>
Conclusion
With the physical systems out of the way, we can now begin creating the different services that will be needed to setup our self hosted environment.