Vagrant: Creating a FreeBSD 11 base box (virtualbox) – pt. 2

The previous post discussed what Vagrant is, explained the installation (on FreeBSD), detailed the process of creating a new VM and briefly described how to install FreeBSD 11. The next step is to prepare the fresh installation for Vagrant and eventually create an actual base box from it. If you’re new to VirtualBox or you don’t know what a provider is when it comes to Vagrant, you might want to read the first part. If you however already have a decent idea of virtualization and making sensible choices when installing FreeBSD, just do a fresh install in a VM and continue reading here.

If you haven’t read the first part: These two posts weren’t written without cause. The idea was to dive into Bacula (a program for doing backups). For testing backups properly you need more than one machine obviously. I don’t have enough spare PCs, so using Virtual Machines seemed like a good way of working around that limitation. Since Vagrant makes working with these VMs really easy, it totally makes sense to use it. I’ve used it quite a bit in the past and while I was at it again, I decided to blog about this great tool so that you maybe consider adding it to your tool set as well.

Preparing the VM for Vagrant: Settings

There are a few things on the side of the guest system that need to be in place so that Vagrant can work with it properly.

The first step is optional but considered good practice if you intend to create a public base box: Disable unneeded resources! To do so, go to the settings of your VM template in the VirtualBox GUI.

Selecting VM settings

A good candidate to disable is audio support which is not generally needed in a Vagrant box.

Disabling audio for the VM

Also deactivate USB support. It’s enabled by default but is most likely unneeded in Vagrant boxes (there are other ways to share data between the VM and the host system).

Disabling USB for the VM

Now fire up your fresh FreeBSD 11 system and log in as root. A little tweak that I suggest is to disable the auto delay of the boot loader. This will make the VM boot up 10 seconds faster because it won’t wait for possible user interaction at the boot loader stage. To do so, you can use the following command:

# echo autoboot_delay="-1" >> /boot/loader.conf

Preparing the VM for Vagrant: Packages

If you’re not using a new version that was just released a few days ago, it’s always a good idea to update the base system first:

# freebsd-update fetch install

Reboot if the kernel was updated:

# shutdown -r now

The FreeBSD package manager (pkg) ist not part of the base system (that way it can evolve faster) so let’s bootstrap it first:

# env ASSUME_ALWAYS_YES=yes pkg install pkg

Vagrant needs sudo to work. And not having bash available works but doesn’t make Vagrant happy. It’s best to just install both:

# pkg install -y sudo bash

Now configure sudo. The configuration file is /usr/local/etc/sudoers on FreeBSD – but you may want to forget that again as you shouldn’t touch that file by hand! Rather issue the command

# visudo

which will call a wrapper script that lets you edit the file and check it for validity before actually saving changes. Why’s that? Because on certain system configurations you can easily lock yourself out of the system with a defunct sudo (and you basically lose sudo when you ruin its configuration file)! Even though the script has vi in its name, that’s just the default. You may want to set the EDITOR environment variable to another editor if you prefer emacs/nano/joe/whatever. Not liking vi is NOT an excuse for not using visudo!

When editing the sudoers file, look for the line %wheel ALL=(ALL) NOPASSWD: ALL. It’s commented out by default. Remove the comment sign and save. That’s actually all that needs to be changed. What that change does: It grants all members of the wheel group unrestricted sudo access without having to enter their password.

Depending on what kind of base box you want to create, you may want to install the VirtualBox guest additions. They enable the hypervisor to directly interact with the guest system enabling some features like a shared clipboard, enhanced graphics options, shared folder support (which are not available on *BSD at the present time however), etc. The downside is that they are quite large (due to their dependencies): ca. 350 MB. If you’re aiming for a small base box, leave them out if you don’t need them. Otherwise consider installing them.

In case you built VirtualBox on your host system from ports you might do the same for the guest additions so that versions match. Building them from ports does complicate things a bit however. You need the system source installed, it will use quite some space and take a long time. Usually it’s not worth the hassle. Unless you require some feature that only works when the versions match (I’ve never run into one), just install the guest additions using packages:

# pkg install virtualbox-ose-additions

Installing the vbox guest additions

If you installed them, enable the guest additions for the next boot:

# sysrc vboxguest_enable="YES"
# sysrc vboxservice_enable="YES"

Preparing the VM for Vagrant: Users

The most important requirement for Vagrant is that a specific user has to be present. In FreeBSD you can create it all by issuing one line:

# echo vagrant | pw adduser -n vagrant -m -s /bin/tcsh -h 0 -L default -c "Vagrant user" -G wheel

This will make pw add a user with the name vagrant to the system, create a home directory for them, set the shell (you can also choose another one here like /usr/local/bin/bash for example) and make it use what is piped into it as the password (that’s a zero following the -h, btw.). It will also set the default login class for the user, use the provided user comment and add it to the wheel group (for which we’ve already configured sudo access).

Now that the vagrant user is present, Vagrant could log you into a VM that it has started from the base box. However it will ask for the password. This is just a small annoyance really, but we can do better. So let’s prepare the vagrant user for automatic login (using SSH keys). To do so, we first change to the new user:

# su -l vagrant

Next we create a .ssh dot directory in user vagrant’s home directory:

% mkdir .ssh

Then we download the public key from the Vagrant insecure keypair (it’s insecure because the private key is public, too – Vagrant uses it to log in via SSH and it’s open source software! But that’s not a problem here) into the new directory e.g. with the following line:

% fetch --no-verify-peer https://raw.githubusercontent.com/mitchellh/vagrant/master/keys/vagrant.pub -o .ssh/authorized_keys

This downloads the vagrant.pub file as authorized_keys (the file that SSH checks against) and skips verifying the SSL certificate of the remote web server (this is necessary because FreeBSD does not ship with a collection of trusted root certificates and we haven’t installed one).

The last thing to do is setting the correct permissions for the new directory and file (SSH is quite picky about that – and rightfully so):

% chmod 0700 .ssh
% chmod 0600 .ssh/authorized_keys

When that’s done, we can log out as vagrant, back to the still logged in root:

% exit

With the key in place we have everything that’s required for a simple FreeBSD 11 base box.

Customizing the base box

Now’s the time to customize your base box. You could install additional software, add more users, do specific configuration, etc. I’m going to prepare the template for testing Bacula with multiple nodes. Since I need to build Bacula with non-standard options, I need to use the ports tree. So let’s put that in /usr/ports first:

# portsnap fetch extract

Then we change into the directory for the Bacula client:

# cd /usr/ports/sysutils/bacula-client

We configure the compile options for the Bacula client as well as for all its dependencies next:

# make config-recursive

I usually deactivate NLS (support for non-English translations), IPv6, DOCS and EXAMPLES for all programs. You may choose different options of course.

Since I need the Bacula client on every machine I can simply build and install it now:

# make install clean

Now let’s change into the Bacula server ports directory:

# cd ../bacula-server

Again we need to set the build options for the port and dependencies:

# make config-recursive

Setting compile options for bacula server

Deselect postgresql and select sqlite instead! When you accept the settings, you will be asked to select the settings for postgresql next. This is because the list of ports to configure was compiled before you changed the dependencies by choosing to build with support for another database. Hit CTRL+C to cancel the operation and then run make config-recursive again.

Just like before, leave out unneeded options to keep the whole system a little lighter. Leave sqlite3 as-is if you don’t know too much about it (it’s a port with A LOT of options and can look rather daunting).

Then we fetch the source archives for Bacula server and its dependencies (this is done because I want to configure the VMs to be restricted to the local network later and thus they won’t be able to connect to the internet then):

# make fetch-recursive

Finalizing the VM

If you’re building a base box that you intend to share with others, it makes sense to try to cut down the size as far as possible. Here are a few suggestions:

  • Clean the pkg cache (removing package files no longer needed after installing them:
    # pkg clean -a
  • Remove the distfiles (/usr/ports/distfiles) if you don’t require them to be available later; if you need some of them, delete the others!
  • If you’ve installed the ports tree to build software and don’t need it in the base box, remove it completely
  • In case you installed the system source (e.g. for building the VirtualBox guest additions) or for customizing the FreeBSD system you probably want to delete /usr/src/* and/or /usr/obj/*
  • Used freebsd-update? Clear any files it may have downlodad or kept for rollback:
    rm -rf /var/db/freebsd-update/*
  • Have installed programs from ports and removed the ports tree again? You can also uninstall programs that were installed as build time dependencies only

Just deleting stuff won’t make your VM’s virtual hard drive smaller during packaging, though! If you’re using a traditional filesystem (i.e. UFS) there’s an easy trick to “reclaim” the now unused space: Zero it out! Don’t try to do this if you’re using ZFS – you won’t be able to fill your drive with zeros if the filesystem compresses them away! So for UFS filesystems do the following:

# dd if=/dev/zero of=/ZERO bs=1m

This will create the file ZERO in / which will be filled with all zeros until the filesystem runs out of space. If you delete that file afterwards, the part of the filesystem that is free again is all zeroed out and thus compresses well when packaging the base box:

# rm /ZERO

Zeroing out free space

If you chose to use multiple filesystems, you may want to dd to a ZERO file on each separate filesystem (e.g. /usr/ZERO, /var/ZERO, etc.).

Finally everything is ready, so shutdown the VM now:

# shutdown -p now

Building the base box

Wait for the VM to power off. Now open a terminal emulator on your host system and tell Vagrant to build a base box from the VM:

% vagrant package --base fbsd-template -o fbsd-template.box

The argument after –base is the name of the VM as it appears in VirtualBox. Mind upper and lower case! Choose any name for the output file (the extension is usually .box). This will take a moment but if all goes well you should eventually have the base box file!

% vagrant box list

This lists all Vagrant boxes available on your system. If you’ve just installed Vagrant before it will tell you that it doesn’t have any boxes yet. So let’s import our newly built box:

% vagrant box add --name fbsd-template fbsd-template.box

Give it any name you want the base box to be known as by Vagrant and point the program to the .box file. If you do

% vagrant box list

Base box created and added!

again, you should see that it’s available now. What’s left? Let’s test if it actually works.

Testing the base box

To do so, I suggest creating a directory for your Vagrant boxes:

% mkdir -p ~/vagrant/testvm
% cd ~/vagrant/testvm

In that directory issue the following command:

% vagrant init

This creates a default Vagrantfile. Think of this as the central configuration for a single VM that Vagrant manages. It contains the name of the base box to create it from, allows configuring of the network, synced folders, overriding base box settings (like the amount of RAM for the VM), provisioning, etc.

Edit this file, have a look at the contents (you can also do this at a later time – vagrant init will always create this default Vagrantfile for you if you need it) and delete it. Put the following lines in the Vagrantfile:

Vagrant.configure("2") do |config|
config.vm.box = "fbsd-template"
config.vm.synced_folder ".", "/vagrant", disabled: true
end

Substitute fbsd-template with the name of your base box if you chose a different one. The second configuration directive disables synced folders: They don’t work for *BSD guests at the present time and Vagrant would issue an unnecessary warning if we didn’t disable it. This is all you need for a very basic configuration. Save the file and exit your editor.

Now run:

% vagrant up

This command tells Vagrant to create a new VM from the base box (VM template) selected in the Vagrantfile and fire it up. Vagrant will do so in the background – it runs the VM in so-called headless mode.

VM created from base box has booted up

You don’t need the VirtualBox GUI for Vagrant but right now take a look. You’ll see a new VM that was created by Vagrant and in fact you could also use VirtualBox to control it. But that’s rarely necessary. Vagrant is meant to manage boxes all for you after all!

To enter the VM, you can execute

% vagrant ssh

Now you’re SSH’ed into the VM! It’s as easy as that. Issue an ls or something to see that it’s working. Exit the machine by logging out (type exit or press CTRL-D) and you’re back in your host machine’s VM directory. Try vagrant ssh again and you see that you’re inside the VM again.

SSH’ed into the box using Vagrant

Cleaning up

Shutdown the VM now:

% sudo shutdown -p now

When the VM shuts down the SSH daemon, you’re automatically dropped back to your host system. Let’s quickly do some cleaning up and we’re done for now:

% vagrant destroy

This will purge the VM. If you keep the Vagrantfile, you can just vagrant up afterwards to start over with a clean VM (from the base box) again. This is great for testing things. You can also control the VM from outside using commands like vagrant halt, vagrant suspend, vagrant resume, etc. I suggest you take a look yourself and learn what Vagrant can do for you. It really has some neat and useful features.

Just a

% cd ..
% rm -r testvm

later we’re done with cleaning up after ourselves. The base box works and can be used to quickly spin up VMs based off of it. While this is neat, the real power Vagrant has and the real comfort it provides show when you’re working with several VMs at the same time. Which is what I intend to do in the post after the next one.

What’s next?

The next post will be an introduction to the Bacula backup software, exploring the basic functionality.

Vagrant: Creating a FreeBSD 11 base box (virtualbox) – pt. 1

For a while I’ve been messing with backup stuff (namely a program called Bacula). To test backups properly it of course makes sense to have multiple nodes available. Now I do not have several unused PCs and other hardware available nor would I want to set up multiple nodes just to configure them similarly in the end. The easy solution? Virtualization. It allows to set up a virtual machine once and then clone it as the need arises. Also it means that I can try out things, do away with the VM and start over with a clean one if I want to.

Give it a try even if you’re new to VirtualBox! Working with it is very easy and just as useful. The idea of virtualization can be daunting if you’re just starting. Therefore this post is meant as an introduction (I’ll even detail VM creation with pictures). If you already know how to use VirtualBox and have a good idea of what Vagrant is about you may skip this post and go to the next one where the actual base box is being built (not written yet, will link it back here once it’s available).

What is Vagrant?

So what’s Vagrant? Vagrant is a program written in Ruby that runs on multiple platforms (FreeBSD, Linux, OS X and even Windows). It basically is a wrapper for virtualization software that makes working with VMs extremely easy and convenient. Vagrant supports multiple hypervisors and containers (simply called providers in Vagrant terminology): VirtualBox, VMWare, KVM, LXC and Docker. A GSoC effort exists to also support FreeBSD’s native hypervisor Bhyve – I’ll definitely give this one a shot in the future.

Vagrant uses a configuration file (the Vagrantfile) for each VM to know which template (called base box) to create it from, how to configure it and so on. It also supports a lot advanced functionality like provisioning a newly created VM using configuration management tools like the veterans Puppet and Chef or the newer generation like Salt Stack and Ansible. There are many cases where Vagrant can help you – just think about it for a moment.

There are a LOT of base boxes already made for you to download and use (have a look here or here). If you need to create new base boxes quite often, you even may want to automate this step. This is possible with a tool called Packer that allows you to create base boxes from a configuration file. This post however details the manual creation of a Vagrant box using FreeBSD 11 as the target OS.

Installing Vagrant

You can probably install Vagrant using the package manager of your OS. If you are using a strange system that has no package management, you have to find out how to do it yourself as I have given up on those systems for almost a decade now and have no idea how it works there. I’ll discuss setting it up on FreeBSD here. First issue:

# pkg install vagrant

Keep in mind however, that by default FreeBSD uses the quarterly package repositories now and you should either change that or simply install from ports (sysutils/vagrant) if you want the newest version.

Now think about the provider that you want to use. If you want to follow along with this article, we’re using VirtualBox. So go ahead and install it. On FreeBSD VirtualBox 5.x is finally available (Oracle does not support FreeBSD as a host system and the complicated work of porting it over was done by the community – thanks to everybody involved!) and it totally makes sense to install this new version. At the time of this writing it’s still version 4.x in the quarterly repository. So make sure whether

# pkg install virtualbox-ose

would install the old or the new version. Configure the latest repository instead of quarterly or build from ports (emulators/virtualbox-ose). If you choose to build from ports, consider to do the same thing for Vagrant. Otherwise you may build a version of VirtualBox that is newer than what Vagrant supports. To be able to run VirtualBox, make your user a member of the vboxusers group:

# pw groupmod vboxusers -m username

Remember that you have to log out and log back in for the new group membership to take effect. Ensure that the kernel modules for VirtualBox are loaded during system startup and load them ad hoc without having to restart:

# echo 'vboxdrv_load="YES"' >> /boot/loader.conf
# kldload vboxdrv.ko

Now make sure that VirtualBox’ network daemon gets started by default and make it start in the current session:

sysrc vboxnet_enable="YES"
service vboxnet start

All done. VirtualBox is ready to be used. There’s more configuration suggested if e.g. you want to use USB in your VMs (which in this case I don’t).

Creating a VM

VirtualBox has a headless mode and can be controlled using e.g. using the command line. But most people would probably prefer to use the GUI that it also comes with. So open up that program. (For steps where you can just accept the defaults I haven’t made a screenshot.)

The VirtualBox GUI

Click on New to launch an assistant for creating a new VM.

Choosing Name and type of the new VM

Give the new VM a name and select the type of operating system that it’s meant for. If you use a name that is somewhat like “freebsd”, VirtualBox will automatically suggest the right type and OS. Since this VM is going to be a template rather than a single-purpose one, I chose the name “freebsd-template” to reflect that.

Setting the amount of RAM for the VM

Set the amount of ram for the new VM. Think about the correct value for a moment. It’s no problem if you notice that you need more later – you can always change the amount of RAM allocated for the VM when it is turned off. But setting it right now saves you the time and effort to re-adjust it later. So how much should you select here? It depends on several factors.

I’m planning for a template that I want to spin up as multiple VMs so the host system must have quite a bit more RAM than the three to five VMs (that I want to run in parallel) together. However my host machine has 24GB of RAM and so there’s no need for me to be stingy and I’m allocating 1024 MB because I have plenty available. If you have little free RAM go for less. I intend to use FreeBSD in text-mode with not too many services running. You could probably do with 256 MB or even less if you really have to.

Allocating space for the virtual hard drive

The VM needs a virtual hard disk. Set the maximum size for that. Just as with RAM chose some value that’s sensible for your case. Again: I have enough space so I don’t have to go with ultra-low values of 3 GB or so. Making the virtual hard drive dynamically allocated means that it’s only going to take the actual size of its data of space on your real hard drive. This means that it can “grow” until it reaches its maximum size. Note that it won’t automatically shrink if you delete data.

Starting the VM

That’s all, you have created a VM. Start it now.

Selecting the ISO image

On first start, VirtualBox will ask you to insert some kind of installer media. If it didn’t the same thing would happen that happens on a PC with an empty hard drive: The system would fail to boot. Download an ISO image of FreeBSD 11 and select it as the boot iso in VirtualBox.

Selecting the ISO image

Now let the VM boot! I’m using FreeBSD11-RC2 here because the date for the final release has been delayed (it should have been out now and that’s what I had planned for).

Installing FreeBSD 11

The OS should boot up and offer you to go to the installer. Proceed and install FreeBSD. It’s pretty straight-forward but there are a few things noteworthy about the installation options. I don’t want to repeat myself, so if you’re completely new to installing FreeBSD, you might want to take a look here where I detailed the installation of FreeBSD 10.1 (I explained disklabels and such). Here I’ll only cover what’s new in the 11.0 installer.

De-selecting all optional distribution sets

I use the hostname “fbsd-template.local”. The installation sets are different because the base system structure has been redesigned. Most likely you won’t need any of the optional sets. To keep the template nice and small I suggest to de-select all of them. Go with UFS as the file system unless you have special needs – and can spare a fair amount of RAM (2G+) for each VM. So going with AUTO (UFS) and using the entire disk is probably fine. Choose GPT partitioning – we’re not dealing with legacy hardware here.

Setting the date

Enter a root password; if you intend to share your base box, it’s common to set the password to vagrant so that others might easily access and modify it. Configure your network (most likely an IPV4 network with DHCP and no IPV6). Thanks to DHCP you should not need to configure the resolver but can accept the values that the installer was told. Configure the timezone. The FreeBSD 11 installer will let you set date and time now which is a nice feature.

Setting system time

Deselect all services except for SSH which is how Vagrant will connect to the VMs. The system hardening dialog is also new. In my case it’s not terribly important since I’m creating a simple VM template for testing purposes. But for production servers it is actually a pretty good idea to tweak some options. I’ve grown a habit of cutting down services that are remotely accessible to the necessary minimum and thus simply selecting the two last options saves me some hassle of editing rc.conf to do just that.

Tweaking the hardening options

We don’t need to add users right now and can quit the installation without final modifications. So let’s reboot.

Removing installation iso

It’s necessary to remove the installation iso or the machine will boot to the installer again instead of into the new operating system. If you’re not fast enough and the system is already booting the installation iso again, just force the unmount and reset the VM.

Resetting the VM

Now the VM should boot into your new FreeBSD 11 system!

What’s next?

While this part discussed the requirements and detailed the preparations, the second part will describe how to actually build the base box for Vagrant.