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.
A good candidate to disable is audio support which is not generally needed in a Vagrant box.
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).
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
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
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:
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
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
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
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
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.
% 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.
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.
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.
% 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.
The next post will be an introduction to the Bacula backup software, exploring the basic functionality.