Vagrant (for Mac and Windows)¶
In order to set up the JEDI environment with Singularity, you’ll need to first set up a Linux operating system. We will often focus on Ubuntu for illustration purposes but if you prefer other varieties of Linux, these are also available from the Virtualbox provider that we describe below.
So, if you’re using a Mac or Windows computer, you will want to set up a local, self-contained Linux environment within your broader operating system. This is commonly called a virtual machine (VM). Once you have a linux VM up and running, you will be able to install Singularity and triumphantly enter the corresponding JEDI Container.
This can all be achieved using an application called Vagrant, which is developed and distributed by a company called Hashicorp. Though we will sometimes refer to Vagrant as the virtual machine provider, the actual Linux operating system is ultimately provided by Oracle’s VirtualBox software package. Vagrant is essentially a tool will allow you to build, configure, and manage a VirtualBox operating system. In particular, we will use Vagrant and VirtualBox to create an Ubuntu virtual machine on your Mac workstation or laptop. We’ll then populate that Linux VM with specific JEDI software tools (compilers, ecbuild, etc.) using Singularity.
From this brief introduction, it is clear that you do not need to worry about Vagrant or VirtualBox if your working machine (whether it is a workstation, laptop, or HPC system) is already running Linux and/or is already running Singularity. By working machine we mean whatever machine you plan to compile and run JEDI on.
You do need Vagrant and VirtualBox (or something equivalent) if you wish to run JEDI from a Mac or Windows machine. Though you can use Vagrant for both platforms, we focus here on macOS.
We refer Windows users to the Vagrant download page where you can download a binary implementation for windows and install it using the Windows package manager. After installing Vagrant, you may wish to return to this document for tips on how to configure it for JEDI (skipping Step A of the next section).
Warning
On macOS at least, the virtualization that underpins the container environments can have heavily degraded performance with MPI oversubscription (running more tasks than cores (virtual cores in this case)). As an example, a ctest using 12 MPI processes on a VM providing 6 virtual cores can take hundreds of times longer to run than in a native environment.
Installing and Configuring Vagrant¶
A: Install Vagrant and VirtualBox¶
As with Windows, you can install Vagrant on a Mac by downloading a pre-compiled binary package from the Vagrant Download Page. However, we recommend that you install with Homebrew as described below to give you more flexibility in managing both vagrant and virtualbox.
Before you begin you should install or update Homebrew.
You’ll need a relatively recent version in order to use the cask
extension.
Once you have done this, you can proceed as follows:
brew cask install virtualbox
brew cask install vagrant
brew cask install vagrant-manager
B: Download JEDI Configuration File¶
Now we need to tell Vagrant what type of virtual machine we want to create and how to
provision it with the software we need. This is done by means of a configuration
file that goes by the default name of Vagrantfile
.
So, to proceed, you should first create a directory where you will place your
Vagrantfile. This is where you will launch your virtual machine. You should also
create a subdirectory called vagrant_data
that we will use.
If you don’t create this directory, you will get an error when vagrant tried to mount it.
You can call the parent directory whatever you wish but if you change the name of
the vagrant_data
directory then you will also have to change the Vagrantfile.
mkdir $HOME/jedi-vm
cd $HOME/jedi-vm
mkdir vagrant_data
In what follows, we will refer to this as the home directory of your Vagrant Virtual Machine (VM).
We at JCSDA provide a Vagrantfile that can be used to create a virtual machine that is pre-configured to build and run JEDI, with both Singularity pre-installed.
Or, alternatively, you can retrieve it with
wget http://data.jcsda.org/containers/Vagrantfile
Place this Vagrantfile in the home directory of your Vagrant VM.
Warning
If you already have a Vagrant VM installed and you want to install a new one (particularly using a Vagrantfile in the same directory as before), then you may have to fully delete the previous VM first to avoid any conflicts. Instructions on how to do this are provided in the Deleting a Vagrant VM section below.
Note
If you have problems with this JEDI Vagrantfile, there an alternative Vagrantfile
that you can download
that expands the disk storage using the disksize
plugin to Vagrant.
This also comes with Singularity pre-installed. After downloading this file,
it’s easiest to change its name to Vagrantfile
and then run vagrant up
again.
However, before trying this make sure that you either destroy your previous VM
or create the new VM from a different directory and give it a different
name (edit the Vagrantfile and search for jedibox).
C: Launch your Virtual Machine¶
Now you are ready to create your virtual machine by running this command:
vagrant up
The first time you run this command, it will take several minutes. Vagrant is installing Singularity and a few other supporting software packages. Once created, these will be part of your virtual machine and they do not need to be re-installed (unless you explicitly tell vagrant to do so).
So, when this command finishes, you can log into your virtual machine with
vagrant ssh
Now you are in a linux environment (CentoOS 7). From here you can pull the JEDI container of your choice,
Depending on which Vagrantfile you use, your VM may run either the Ubuntu or the CentOS operating system. However, you shouldn’t need to be too concerned about this because you’ll be working mostly in the Singularity container which runs Ubuntu. So, if you work within the container, you will be in an Ubuntu environment regardless of which OS your vagrant VM is running.
D: Exit Container and Vagrant¶
Normally you will be spending your time working in the Singularity container.
When you’re finished working for the day, it’s important to remember to
enter exit
twice, once to exit the container and once to log out of the
Vagrant virtual machine:
exit # to exit Singularity
exit # to exit Vagrant
Now, to temporarily shut down your virtual machine, enter
vagrant halt
Note that this is very different than the vagrant destroy
command,
which should be used with caution. As the name of the command suggests, vagrant
destroy will completely destroy the virtual machine along with all the files and data it contains.
So, if you do this, you will have to re-create the virtual machine and re-install
any JEDI bundles that you are working with. And, you will lose any files that
you have been editing. By contrast, vagrant halt will merely shut down the virtual machine,
retaining all your files. This will allow you to gracefully log out of your workstation
or laptop without harming your JEDI environment. For further details see the Vagrant
command reference.
E: Enable X Forwarding (Optional)¶
If you’d like to use graphical tools such as emacs
from within the
Singularity container, you will need to set up X forwarding. If you’re doing this
on a Mac, you will first need to install XQuartz,
if it’s not already installed.
After XQuartz is up and running, you can create and enter your VM as described
in step C above. Next you will have to set your DISPLAY
environment variable
to use your local machine. This is best done from within the container because
environment variables set outside the container may not be accessible from within.
# inside the container
export DISPLAY=10.0.2.2:0.0
You may wish to add the appropriate display definition to an initialization script that you can run every time you enter the singularity container as described here. Then, enter this on your host machine (i.e. your Mac or Windows machine), to grant the VM permission to display
#On your Mac
xhost + 127.0.0.1
These are the addresses that Vagrant uses for by default. You may wish to add the appropriate display definition to an initialization script that you can run every time you enter the singularity container as described here.
To test the display, you can start a graphical application. For example:
# inside the container
emacs &
Troubleshooting Tips
If the above procedure did not work, there are several things to try.
First, if you have a Mac, make sure XQuartz is installed. You may need to re-boot your VM for a new installation to take effect.
Next, try running emacs from outside the container to see if the problem is with Vagrant or with the container.
If you used a different Vagrant box than the one specified in the JEDI Vagrantfile (for example, if you used one from Singularityware), if might help to set your DISPLAY variable in the container to this instead:
export DISPLAY=localhost:10.0
If the display still does not work, then you may need to explicitly grant Vagrant
access to your display through xauth
as we now describe.
Exit the container and exit vagrant. Then edit your Vagrantfile and add these
two lines (at the bottom, just before the end
in the main Vagrant.configure("2") do |config|
loop will do)
config.ssh.forward_agent = true
config.ssh.forward_x11 = true
Then recreate your vagrant VM, log in, and enter the container (for example, for Singularity):
vagrant halt # restart vagrant
vagrant up
vagrant ssh
singularity shell --bind ./vagrant_data -e <singularity-image-file>
Now create an .Xauthority
file and generate an authorization key for your display:
touch ~/.Xauthority
xauth generate 10.0.2.2:0.0 . trusted
You can list your new authorization key as follows:
xauth list
There should be at least one entry, corresponding to the display you entered in
the xauth generate
command above (you can ignore other entries, if present).
For example, it should look something like this:
10.0.2.2:0 MIT-MAGIC-COOKIE-1 <hex-key>
where <hex-key>
is a hexadecimal key with about 30-40 digits.
Now, copy this information and paste it onto the end of the xauth add
command as follows:
xauth add 10.0.2.2:0 MIT-MAGIC-COOKIE-1 <hex-key>
If all worked as planned, this should grant permission for vagrant to use your display.
Customizing the Vagrantfile (optional)¶
The JEDI Vagrantfile you downloaded in Step B above is already provisioned with everything you need to run JEDI, by means of the Singularity software containers.
However, it’s useful to point out a few configuration options that some users may wish to customize.
Creating your own Vagrantfile¶
First comes the choice of machine. The JEDI Vagrantfile uses a CentOS 7 operating system but there are a number of other options available, particularly with the well-maintained bento boxes provided by Vagrant. You may wish to maintain multiple virtual machines with different Linux operating systems.
For example, you can create your own Vagrantfile by entering something like this:
vagrant init bento/ubuntu-20.04
When you then run vagrant up
, this will create an Ubuntu 20.04 operating system.
You can then install Singularity manually.
The makers of Singularity also provide their own Vagrant box, with Singularity pre-installed:
vagrant init sylabs/singularity-3.0-ubuntu-bionic64
Allocating Resources for your Virtual Machine¶
The JEDI Vagrantfile comes pre-configured to allocate 16GB of memory and 18 virtual CPUS to the VM. This is the minimum resource allocation to run many tests and applications. Furthermore, if you create your own Vagrantfile, the default resource allocation will likely be insufficient to run JEDI.
You can change these resource allocations by editing the Vagrantfile.
Look for the following section that specifies the provider-specific configuration (variable names may differ).
Change the vb.memory
(in MB) and vb.cpus
fields as shown here:
config.vm.provider "virtualbox" do |vb|
# [...]
# Customize the amount of memory on the VM:
vb.memory = "16384"
# Customize the number of cores in the VM:
vb.cpus = "18"
# [...]
end
File transfer between your Mac and the VM¶
In Step B above we created a directory called vagrant_data
.
The JEDI Vagrantfile is configured to use this directory to transfer files between
your host machine (which may be running macOS or Windows) and your VM.
Within the VM, this directory is mounted as $HOME/vagrant_data
.
To change this, you can edit the Vagrantfile and find the section for a synced folder:
# Share an additional folder to the guest VM. The first argument is
# the path on the host to the actual folder. The second argument is
# the path on the guest to mount the folder. And the optional third
# argument is a set of non-required options.
c.vm.synced_folder "vagrant_data", "/home/vagrant/vagrant_data"
The first argument specifies the directory on the host machine, relative to the home directory of your Vagrant VM (i.e. the directory where the Vagrantfile is). The second specifies the path of the directory on the VM. You can change these paths and/or names if you wish but make sure the host directory exists before running vagrant up so it can be properly mounted.
It might also be necessary to create the mount point from within the vagrant VM:
mkdir ~/vagrant_data # from within the VM, if necessary
And, here is another tip: Use an absolute path for your guest directory.
Vagrant will complain if you use a relative path, such as ./vagrant_data
.
You will need root permission if you want to branch off of root (for example /vagrant_data
is
the default mounting if you run vagrant init
.)
On a related note: your default user name when you enter Vagrant will be vagrant
and your home directory will be /home/vagrant
.
If you want to change this you can do so by adding a line like this to your Vagrantfile:
config.ssh.username = 'vagabond'
For more information, and more options, see the Vagrant documentation.
Working with Vagrant and the JEDI Container¶
Once you have Vagrant and a container provider all set up as discussed above, your daily workflow may be as follows. You might start by going to the directory where you put your Vagrantfile. Then fire up and log in to your virtual machine.
cd $HOME/jedi-vm
vagrant up
vagrant ssh
From there you can enter the container and (optionally) run your startup script. For example:
singularity shell -e <singularity-image-file>
source startup.sh
Now you’re in the JEDI container and you can do whatever you wish: edit files, build, compile and run JEDI, etc. If you want to use X-forwarding you’ll have to explicitly tell your Mac to accept graphical input from the Vagrant VM as described in Step G above:
#On your Mac
xhost + 127.0.0.1
You may be tempted to automate this so you don’t have to enter this command every
time you start up your virtual machine. However, this is more subtle than you might expect.
Since this is the IP address of localhost, placing this command in your .bash_profile
file might cause your terminal application to hang when you first start it up because localhost is not yet defined.
You can avoid this by adding xhost +
to your .bash_profile
but be
careful with this because it may open you up to security vulnerabilities by allowing
clients to connect to your machine from any remote host.
Entering the explicit command above or putting it in a bash script that you execute
manually every time you log in is somewhat inconvenient but much safer.
When you’re done for the day you can exit and shut down the VM:
exit # to exit Singularity
exit # to exit Vagrant
vagrant halt # to shut down the virtual machine
Deleting a Vagrant VM¶
When you shut down a Vagrant virtual machine (VM) with vagrant halt
, it’s
like shutting down your laptop or workstation. When you restart the VM, you can
pick up where you left off. You’ll see all the files and directories that were there before.
This is usually desirable. However, it does mean that the VM is occupying disk space on your machine even when it is suspended. If you have created multiple VMs, this can add up. So, it is often useful to delete a VM if you are done using it.
To check vagrant’s status at any time enter
vagrant global-status
This is a useful command to know about. It will tell you all the VMs vagrant knows
about on your computer including the path where the Vagrantfile is located and the state.
A vagrant up
command will put the VM in a running
state while a vagrant halt
command will put the VM in a poweroff state.
If you want to delete one or more of these VMs, the first step is to save
any files you have on the VM that you want to preserve. This can be done by
moving them to the ~/vagrant_data
directory which will still exists on your
local computer after the VM is deleted.
Now, the best way to proceed is to go to the directory where the vagrant file is and enter:
vagrant destroy # enter y at the prompt
rm -rf .vagrant
The first command deletes all of the disks used by the virtual machine, with the
exception of the cross-mounted vagrant_data
directory which still exists
on your local computer. The second command resets the vagrant configuration.
This is particularly important if you re-install a new VM where another VM had
been previously. If you skip this step, vagrant up
may give you errors
that complain about mounting the vagrant_data
directory (“…it seems
that you don’t have the privileges to change the firewall…”).
This is a start, but you’re not done. As mentioned at the top of this document, Vagrant is really just an interface to VirtualBox, which provides the Linux OS. The Virtualbox VM that contains the Linux OS still exists and is still using resources on your computer. To see the VirtualBoxes that are currently installed though Vagrant, run
vagrant box list
If you used the JEDI Vagrantfile as described in Step B above, then you’ll see
one or more entries with the name centos/7
. The first step here is to
prune any that are not being used any more with
vagrant box prune
However, even this might not delete the VM you want to delete.
Run vagrant list
to see if it is still there and if it is, you can delete it with
vagrant box remove centos/7
..or ubuntu or singularityware or whatever name is listed for the box you want to delete.
In some cases it might also help to delete the hidden .vagrant
file that
is created by vagrant in the same directory as your Vagrantfile. So, from that directory, enter:
rm -rf .vagrant
Now, this should be sufficient for most situations. Most users can stop here with confidence that they have deleted their unwanted VMs and have freed up the resources on their local computer.
However, it is possible that there might still be VirtualBox VMs on your machine
that Vagrant has lost track of. You might notice this if you try to create a new
VM with vagrant up
and it complains that “A VirtualBox machine with the
name jedibox already exists” (or a similar error message).
If this is the case, you can run VirtualBox directly to manage your VMs. This
can be done through the command line with the vboxmanage
command
(run vboxmanage --help
for information) but we recommend the VirtualBox GUI,
which is more user-friendly.
To access the GUI on a Mac or Windows machine, just go to your Applications folder and double click on the VirtualBox icon. There you will see a complete list of all the VirtualBox VMs installed on your system and you can delete any that you don’t want by selecting the machine menu item and then remove.
Tunneling to Host from Singularity: jupyter-lab Example¶
Tunneling from Singularity to the host can enable several useful ways of interacting
between the host and the container. The benefits are multiple but some of the syntax
for doing it could be described as obscure. A motivating example use case is
running jupyter-lab
in Singularity and accessing it from the host machine.
This not only allows the user to run jupyter notebooks from the browser, a terminal
in jupyterlab
can also be used to build and run JEDI repositores. The general
outlines of establishing the tunnel below are followed by a recipe for installing
python virtual environments in the container, including jupyter-lab
.
Tunneling starts in the Vagrantfile, search “forwarded_port” and set the following line as follows (with your choice of port, we use 8111 throughout):
config.vm.network "forwarded_port", guest: 8111, host: 8111
On the host machine, restart Vagrant (if necessary) and enter Vagrant using the special syntax:
vagrant halt # if running
vagrant up
vagrant ssh -- -L 8111:localhost:8111
Now inside Vagrant, start Singularity thusly:
singularity shell -e jedi-clang-mpich-dev_latest.sif portmap=8111:8111/tcp
The above should establish the tunnel from the host through Vagrant to Singularity.
Next we install a python virtual environment with jupyter-lab
and test the tunnel.
We choose to install our virtual environment(s) in a directory mounted into Vagrant from the host.
For example, the vagrant_data
directory as specified above in the Vagrantfile:
config.vm.synced_folder "./vagrant_data", "/home/vagrant/vagrant_data",
mount_options: ["dmode=775,fmode=777"]
The following script is to be sourced inside Singularity, configring the venv_dir
variable to install the virtual environment in a synced directory. The example
script installs a virtual environment and jupyter-lab
in that resulting environment:
#!/bin/bash
# Configure where to install:
venv_dir=~/vagrant_data/venvs/my_venv
# ----------------------------------------------------
(return 0 2>/dev/null) && sourced=1 || sourced=0
if [[ sourced -eq 0 ]]; then
echo "This script must be sourced."
return 1
else
echo "Setting up virtual env: $venv_dir"
fi
if [ -d $venv_dir ]; then
echo "The environment ($venv_dir) already exists, returning."
return 2
fi
export PATH=$PATH:/home/vagrant/.local/bin/
python -m pip install --user virtualenv
# If subsequent installation troubles arise,
# run this line to update wheels in venv and try again:
# virtualenv --upgrade-embed-wheels True $venv_dir
virtualenv $venv_dir
source $venv_dir/bin/activate
pip install jupyter jupyterlab
return 0
The above script must be sourced in bash
and will produce an error if otherwise
executed. If the script completes successfully, the virtual environment will be activated.
In future Singularity sessions, it can be activated as normal with virtual environments,
using the $venv_dir
specified in the script to locate the activate
script:
source ~/vagrant_data/venvs/my_venv/bin/activate
Then we can navigate to the desired root directory and start jupyter-lab
:
cd /the/path/of/choice
jupyter-lab --no-browser --port 8111
Jupyter will print output to the terminal, including a url to use to connect from a browser. Copy and paste the URL from jupyter into your host’s browser and go!
We note that in the current containers (March 2021), the following harmless warning is printed in the jupyter-lab session when the browser connects: Could not determine jupyterlab build status without nodejs. Also noteworthy is that testing the tunnel on any machine (Singularity, Vagrant, or the host) can be done via
curl localhost:8111
If working, jupyter-lab
will register GETs in the terminal resembling
[I 2021-01-05 22:25:35.249 ServerApp] 302 GET / (::1) 0.62ms