Creating a Dev VM should be simple and easy. No manual work to deploy configurations / tools every time we need a new distribution. For that purpose, we’ve used Vagrant (under MIT license) and, in this example, VirtualBox base package (under GPLv2).

 

Create Vagrant configuration file

We start by creating an initial Vagrant configuration file specifying the box we want to use.

We can either use a custom box (see how to create one here) or use an existing one from here.

To initialize the Vagrant file, we need to type the command vagrant init and the name of the box. In this case it’s a customized box:

# vagrant init example_centos7-box

We start the VM with the command

# vagrant up

NOTE: We are using VirtualBox for this. So what if we wanted to use a different provider? In that case, we could specify it on the same command we’ve seen before, so we would end up with:

# vagrant up --provider hyperv

We can check VirtualBox and see that the new VM is available and ready to be used

Figure 1: Oracle VM VirtualBox Manager with new VM already running

We now have a basic VM but, we will stop it for now. We still need to make changes to the configuration file. So, Vagrant has a command we can use for that:

# vagrant halt

If we check VirtualBox now, we can see that the VM is not running. So, to completely destroy the VM, we use the command (confirm with ‘y’ when asked):

# vagrant destroy

VirtualBox will no longer list the VM.

 

Use Vagrant to configure the VM

 

Guest additions for VirtualBox

Vagrant can handle VirtualBox guest additions for us. To have that, we just need to install a plugin:

# vagrant auto upgrade guest additions

Vagrant will check to see if the guest additions are already on the VM and, if yes, on which version. As a result, guest additions will be installed or upgraded as needed.

Vagrant project structure

We wanted a simple structure. So, we added the following folders to the VM root

Inside the “src” folder, we have set 3 others:

  • The “config” contains all configuration files to copy to the VM
  • The “scripts” hold the scripts to be executed during provisioning
  • The “tar” has the specific tar versions for tools to install on the VM

Vagrant configuration file

To create the VM we want, we need to change the configuration file to set:

  • A shared folder
config.vm.synced_folder "c:\\VMShare", "/vagrant", type: "virtualbox", automount: true
  • The VM name
vb.name = "myvagrantcentos7"
  • Memory to use
vb.memory = "8192"
vb.customize ["modifyvm", :id, "--vram", "64"]
  • Number of Cpus to use
vb.cpus = 2
  • Folders to copy for the VM installation
config.vm.provision "file", source: "src/tar", destination: "/tmp/"  
  • Files to copy for the VM installation (ex.:)
config.vm.provision "file", source: "src/config/maven_settings.xml", destination: "/tmp/maven_settings.xml"
  • External scripts to install required tools (ex.:)
config.vm.provision "shell", path: "src/scripts/start.sh"

NOTE: We need to verify the box authenticity when not using a customized one. Consequently, we need to specify the expected checksum

override.vm.box_download_checksum_type
override.vm.box_download_checksum 
override.vm.box_url

NOTE: In some cases, we may not want Vagrant to manage guest additions for a specific VM. So, we do that by disabling the check in the configuration file with:

config.vbguest.auto_update = false

Here is the complete Vagrant configuration file:

# You can execute vagrant init on a folder to recreate a conf file with all comments
# All unnecessary comments on this file were removed to make it clearer
Vagrant.configure("2") do |config|
  # Every Vagrant development environment requires a box. In this case it’s our customization
  config.vm.box = "example_centos7-box"

  # Configure shared folder considering guest additions are already available
  config.vm.synced_folder "c:\\VMShare", "/vagrant", type: "virtualbox", automount: true

  # VirtualBox configuration
   config.vm.provider "virtualbox" do |vb, override|
  #   # Customize name to display on VirtualBox:
	 vb.name = "myvagrantcentos7"
  #   # Customize the amount of memory on the VM:
     vb.memory = "8192"
  #   # Customize the number of CPU on the VM:
	 vb.cpus = 2
  #   # Customize the amount of video memory on the VM:
     vb.customize ["modifyvm", :id, "--vram", "64"]
  #   # Check if Centos7 image is official release and one expected (if uncustomized box):
	 override.vm.box_download_checksum_type = "sha256"
     	 override.vm.box_download_checksum = "de768cf0180d712a6eac1944bd78870c060999a8b6617f8f9af98ddbb9f2d271"
     	 override.vm.box_url = "https://cloud.centos.org/centos/7/vagrant/x86_64/images/CentOS-7-x86_64-Vagrant-1905_01.VirtualBox.box"
   end
   
  # Generic initialization
  config.vm.provision "shell", path: "src/scripts/start.sh"
  # copy required tar for installation
  config.vm.provision "file", source: "src/tar", destination: "/tmp/"  
  # Copy maven settings file
  config.vm.provision "file", source: "src/config/maven_settings.xml", destination: "/tmp/maven_settings.xml"
  # Copy glassfish domain file
  config.vm.provision "file", source: "src/config/glassfish_domain.xml", destination: "/tmp/glassfish_domain.xml"
  # Environment variables setting
  config.vm.provision "shell", path: "src/scripts/variables_install.sh"
  # java development kit 8 installation
  config.vm.provision "shell", path: "src/scripts/jdk8_install.sh"
  # java development kit 7 installation
  config.vm.provision "shell", path: "src/scripts/jdk7_install.sh"
  # glassfish 3.1.2.2 installation
  config.vm.provision "shell", path: "src/scripts/glassfish3_install.sh"
  # Maven installation
  config.vm.provision "shell", path: "src/scripts/maven_install.sh"
  # Firefox installation
  config.vm.provision "shell", path: "src/scripts/firefox68_install.sh"
  # Tomcat 8 installation
  config.vm.provision "shell", path: "src/scripts/tomcat8_install.sh"
  # Xfce installation
   config.vm.provision "shell", path: "src/scripts/xfce_install.sh"
  # Closing provisioning
  config.vm.provision "shell", path: "src/scripts/closure.sh"	
end

External scripts definition

First of all, Vagrant allows inline shell scripts. It also allows external scripts. So, rather than using inline shell scripts, we preferred to use the later. These are created for each tool we want to include on the VM.

  • JDK 7 and JDK 8
  • Glassfish 3
  • Maven
  • Firefox as the browser
  • Tomcat 8
  • Xfce as the graphical environment

NOTE: All scripts start with #! /bin/bash

start.sh

The start.sh script guarantees that the system is up to date and adds some utilities required for the remaining scripts.

NOTE: We have set the default keyboard to the preferred layout when not using a custom box.

NOTE: The developers can add their own preferred IDE, text editor, …

#!/bin/bash

echo "Updating system..."
sudo yum update -y

echo "Adding user vagrant to vboxsf group (to access shared folder) ..."
sudo gpasswd -a vagrant vboxsf
sudo chown -R vagrant: /media/sf_vagrant

echo "Setting default keyboard..."
sudo localectl set-x11-keymap pt

echo "Installing wget..."
sudo yum -y install wget

echo "Updating metadata cache to install unzip..."
sudo yum -y makecache
echo "Installing unzip..."
sudo yum -y install unzip

echo "Initial script finished!"

variables_install.sh

The variables_install.sh script creates and adds the required environment variables to a new file. The file is then loaded and the environment variables made available every time the VM boots up.

 

#!/bin/bash

echo "Starting to set custom environment variables..."
echo "Creating custom file to add environment variables..."
sudo touch /etc/profile.d/custom.sh
echo "Granting permissions to file for user vagrant..."
sudo chown vagrant: /etc/profile.d/custom.sh
echo "Adding environment variables..."
sudo echo export PATH=/opt/apache-maven-3.5.2/bin:${PATH} >> /etc/profile.d/custom.sh

echo "Custom environment variables all set!"

jdk8_install.sh

The jdk8_install.sh script installs JDK 8 with the specified tar file, copied into the VM. The JDK 8 is installed first, to set it as the default java option.

 

#!/bin/bash

echo "preparing JDK 8 installation..."
echo "checking if jdk 1.8.0_152 is already installed and exit if it does..."
[ -d "/opt/jdk1.8.0_152" ] && exit 0

# move into opt folder
cd /opt/

# install JDK 8
echo "Setting JDK 8..."
echo "Untar JDK 8 into /opt/..."
sudo mv /tmp/tar/jdk-8u152-linux-x64.tar.gz /opt/jdk-8u152-linux-x64.tar.gz
echo "untar JDK 1.8.0_152 ..."
sudo tar xvf jdk-8u152-linux-x64.tar.gz
echo "removing JDK 1.8.0_152 tar file..."
sudo rm /opt/jdk-8u152-linux-x64.tar.gz
echo "granting required permissions to jdk1.8.0_152 folder..."
sudo chown -R root: jdk1.8.0_152
echo "making JDK 1.8.0_152 available in the system..."
sudo alternatives --install /usr/bin/java java /opt/jdk1.8.0_152/bin/java 1

echo "Java 8 installation finished!"

The java default option can be changed later with the command:

# sudo update-alternatives --config java

jdk7_install.sh

The jdk7_install.sh script installs JDK 7 with the specified tar file, copied into the VM.

#!/bin/bash

echo "preparing JDK 7 installation..."
echo "checking if jdk 1.7.0_80 is already installed and exit if it does..."
[ -d "/opt/jdk1.7.0_80" ] && exit 0

# move into opt folder
cd /opt/

# install JDK 7 
echo "Setting JDK 7..."
echo "copying JDK 1.7.0_80 tar into /opt/..."
sudo mv /tmp/tar/jdk-7u80-linux-x64.tar.gz /opt/jdk-7u80-linux-x64.tar.gz
echo "untar JDK 1.7.0_80 ..."
sudo tar xvf jdk-7u80-linux-x64.tar.gz
echo "removing JDK 1.7.0_80 tar file..."
sudo rm /opt/jdk-7u80-linux-x64.tar.gz
echo "granting required permissions to jdk1.7.0_80 folder..."
#sudo chown -R root: jdk1.7.0_80
echo "making JDK 1.7.0_80 available in the system..."
sudo alternatives --install /usr/bin/java java /opt/jdk1.7.0_80/bin/java 1

echo "Java 7 installation finished!"

glassfish3_install.sh

The glassfish3_install.sh script downloads, installs and configures glassfish 3 on the VM. The configuration is done with a pre-prepared file copied into the VM, containing the connections to existing databases.

 

#!/bin/bash

echo "preparing glassfish installation..."
echo "checking if glassfish is already installed and exit if it does..."
[ -d "/opt/glassfish3" ] && exit 0

cd /opt
echo "downloading glassfish 3.1.1.2 ..."
sudo wget http://download.oracle.com/glassfish/3.1.2.2/release/glassfish-3.1.2.2.zip
echo "installing glassfish 3.1.2.2..."
sudo unzip -q glassfish-3.1.2.2.zip
echo "cleaning up downloaded file..."
sudo rm glassfish-3.1.2.2.zip
echo "changing glassfish3 owner to vagrant..."
sudo chown -R vagrant: glassfish3

echo "Replace glassfish domain xml file ..."
sudo mv /opt/glassfish3/glassfish/domains/domain1/config/domain.xml /opt/glassfish3/glassfish/domains/domain1/config/domain.xml.bkp
sudo mv /tmp/glassfish_domain.xml /opt/glassfish3/glassfish/domains/domain1/config/domain.xml

echo "Glassfish installation finished!"

maven_install.sh

The maven_install.sh script downloads, installs and configures maven 3.5.2 on the VM. The configuration is done with a pre-prepared file copied into the VM, containing the settings to be used.

 

#!/bin/bash

echo "Setting maven..."

mvn -version && exit 0

echo "Downloading maven 3.5.2 ..."
sudo wget http://archive.apache.org/dist/maven/maven-3/3.5.2/binaries/apache-maven-3.5.2-bin.tar.gz -O /tmp/apache-maven-3.5.2-bin.tar.gz

echo "Untar downloaded file..."
sudo tar -xvzf /tmp/apache-maven-3.5.2-bin.tar.gz -C /opt/

echo "Replace maven settings file ..."
sudo rm /opt/apache-maven-3.5.2/conf/settings.xml
sudo mv /tmp/maven_settings.xml /opt/apache-maven-3.5.2/conf/settings.xml
sudo mv /tmp/custom_config.sh /etc/profile.d/custom.sh

echo "Maven installation finished!"

firefox68_install.sh

The firefox68_install.sh script downloads and installs Firefox ESR 68 on the VM.

 

#!/bin/bash

echo "preparing firefox installation..."
echo "checking if firefox is already installed and exit if it does..."
[ -d "/opt/firefox" ] && exit 0

echo "downloading firefox 68 ESR..."
sudo cd /opt/
sudo wget http://ftp.mozilla.org/pub/firefox/releases/68.0esr/linux-x86_64/en-US/firefox-68.0esr.tar.bz2

echo "untar firefox 68 ESR..."
sudo tar xvjf firefox-68.0esr.tar.bz2 -C /opt

echo "cleaning up downloaded file..."
sudo rm firefox-68.0esr.tar.bz2

echo "Firefox installation finished!"

tomcat8_install.sh

The tomcat8_install.sh script downloads and installs Tomcat 8 on the VM.

 

#!/bin/bash

echo "preparing tomcat 8 installation..."
echo "checking if tomcat 8 is already installed and exit if it does..."
#[ -d "/opt/apache-tomcat-8.5.47" ] && exit 0

echo "downloading tomcat 8 ..."
cd /opt/
sudo wget http://www-us.apache.org/dist/tomcat/tomcat-8/v8.5.47/bin/apache-tomcat-8.5.47.tar.gz

echo "untar tomcat 8 ..."
sudo tar -zxvf apache-tomcat-8.5.47.tar.gz

echo "setting permissions ..."

sudo chown -R vagrant: /opt/apache-tomcat-8.5.47

echo "cleaning up downloaded file..."
sudo rm apache-tomcat-8.5.47.tar.gz

echo "Tomcat 8 installation finished!"

xfce_install.sh

The xfce_install.sh script installs a graphical environment on the VM. We have chosen xfce to have a lightweight desktop environment.

#!/bin/bash

echo "preparing xfce installation..."

echo "installing epel-release required for xfce..."
sudo yum -y install epel-release

echo "installing xfce desktop environment..."
yum -y groupinstall x11
yum -y groups install "Xfce"

echo "setting graphical environment as default..."
systemctl set-default graphical.target

echo "Xfce installation finished!"

closure.sh

The closure.sh script closes the installation, clearing unwanted files and shutting down the VM.

 

#!/bin/bash

# remove previously created folder and files
sudo rm -R /tmp/tar/
sudo rm /tmp/apache-maven-3.5.2-bin.tar.gz

echo "Finished cleaning up!"

echo "Shuting down!"
sudo shutdown -h now

Recreating the VM

Once we have finished the configuration file, we can finally recreate the VM with:

# vagrant up

There is no need to halt and destroy the VM every time we want to add a new tool with Vagrant. We just need to change the configuration file and run vagrant up with provision:

# vagrant up --provision

Booting the new VM

Now that we have created the VM, we can go to VirtualBox and start our VM. There, we can find it with the name and definitions specified in our configuration file

Figure 2: Oracle VM VirtualBox Manager with new VM running

We login to the VM with vagrant/vagrant. The first time we login, we should select the Xfce Session environment.

Figure 3: VM login screen

In conclusion

The development VM is still missing some required tools for a developer to start working, but, we have opted to offer them the possibility to choose the remaining tools to install. For example, the IDE.

We are also building a repository with installation scripts for other tools. That way, the developers can choose the ones they want and easily include them on their own Vagrant configuration file to provision the VM just the way they want!

 

Author

  • Daniel Olival

    Born in France. Raised in Portugal. A family man. Husband to a great woman. Father of 2 beautiful girls. Fighting games enthusiast. Horror stories avid reader. Proud Tech leader of the Product domain at La Redoute.