Recently I was given a technical challenge that required me to create a rails application inside an isolated environment. I was given the choice of either using a Docker container or a virtual machine.
I didn't have any experience with either of these environments but after doing some research I decided to use a virtual machine (vm). Though they both perform the same task, Vagrant seemed to need less set up to get started.
To begin I downloaded VirtualBox which is the virtualization engine that Vagrant will be built on top of. Then I downloaded Vagrant.
I then created a directory that will be the root of my vagrant environment and cd'd into the directory.
mkdir vagrant_demo cd vagrant_demo
To initialize this directory to be used with Vagrant you must run 'vagrant init' followed by the name of the base operating system you want to be used in your Vagrant environment. I used 'ubuntu/trusty64' to create a Linux environment.
vagrant init ubuntu/trusty64
The above command creates a VagrantFile in your directory. You receive the following message after running 'vagrant init':
A `Vagrantfile` has been placed in this directory. You are now ready to `vagrant up` your first virtual environment! Please read the comments in the Vagrantfile as well as documentation on `vagrantup.com` for more information on using Vagrant.
This Vagrantfile dictates how your Vagrant environment is configured and can be changed to fit each individual application. Below is a copy of the Vagrantfile we just created:
# -*- mode: ruby -*- # vi: set ft=ruby : # All Vagrant configuration is done below. The "2" in Vagrant.configure # configures the configuration version (we support older styles for # backwards compatibility). Please don't change it unless you know what # you're doing. Vagrant.configure("2") do |config| # The most common configuration options are documented and commented below. # For a complete reference, please see the online documentation at # https://docs.vagrantup.com. # Every Vagrant development environment requires a box. You can search for # boxes at https://vagrantcloud.com/search. config.vm.box = "ubuntu/trusty64" # Disable automatic box update checking. If you disable this, then # boxes will only be checked for updates when the user runs # `vagrant box outdated`. This is not recommended. # config.vm.box_check_update = false # Create a forwarded port mapping which allows access to a specific port # within the machine from a port on the host machine. In the example below, # accessing "localhost:8080" will access port 80 on the guest machine. # NOTE: This will enable public access to the opened port # config.vm.network "forwarded_port", guest: 80, host: 8080 # Create a forwarded port mapping which allows access to a specific port # within the machine from a port on the host machine and only allow access # via 127.0.0.1 to disable public access # config.vm.network "forwarded_port", guest: 80, host: 8080, host_ip: "127.0.0.1" # Create a private network, which allows host-only access to the machine # using a specific IP. # config.vm.network "private_network", ip: "192.168.33.10" # Create a public network, which generally matched to bridged network. # Bridged networks make the machine appear as another physical device on # your network. # config.vm.network "public_network" # 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. # config.vm.synced_folder "../data", "/vagrant_data" # Provider-specific configuration so you can fine-tune various # backing providers for Vagrant. These expose provider-specific options. # Example for VirtualBox: # # config.vm.provider "virtualbox" do |vb| # # Display the VirtualBox GUI when booting the machine # vb.gui = true # # # Customize the amount of memory on the VM: # vb.memory = "1024" # end # # View the documentation for the provider you are using for more # information on available options. # Enable provisioning with a shell script. Additional provisioners such as # Puppet, Chef, Ansible, Salt, and Docker are also available. Please see the # documentation for more information about their specific syntax and use. # config.vm.provision "shell", inline: <<-SHELL # apt-get update # apt-get install -y apache2 # SHELL end
This file is written in the Ruby programming language and as you can see most of it is commented out. The only lines not commented out are the lines to configure the vagrant box (or operating system):
Vagrant.configure("2") do |config| config.vm.box = "ubuntu/trusty64" end
In order to define other aspects of your virtual machine you can modify the Vagrant file as needed. If no modifications are made default settings are used. There are 5 specs in this file that can be modified:
-config.vm.box - This defines the operating system of your virtual machine and for our app we used ubuntu/trusty64.
-config.vm.provider- This defines the vm provider or base for our vagrant environment. We are using VirtualBox. We can also modify the memory and number of cpu's needed for the vm. For my rails app I increased the memory from the default value to 4G:
config.vm.provider "virtualbox" do |vb| vb.memory = "4096" end
If you needed more cpu's you could use:
config.vm.provider "virtualbox" do |vb| vb.cpus = 2 end
-config.vm.network - This is how your host computer sees your vagrant box and application. Here you can configure the ip address and ports for your application.
Since rails applications default to port 3000 I updated this network setting:
config.vm.network "forwarded_port", guest: 3000, host: 3000
Where the guest is the vm and the host is our computer.
-config.vm.synced.folder - This is where you define how the files on your virtual machine (your Vagrant box) will access files from the host (your computer). This allows you to create and alter your project files on your computer without having to do it in the virtual machine. These files will then be automatically synced with the Vagrant box if desired. I used the following:
config.vm.synced_folder ".", "/vagrant_files"
The first argument "." points to the current directory on our computer or the 'vagrant_demo' directory. This is where we will put our rails application and tells our vagrant box to use these files. The second argument, "/vagrant" is the directory we want to be built on the vm to house our rails application. In essence our files are on both our computer and in the vm but we can alter them on our computer and they will be automatically housed and synced on the vm in the "/vagrant_files" directory. You can name this directory whatever you want. I just used "/vagrant_files" for simplicity.
-config.vm.provision - This is the heart and soul of the Vagrantfile. This is where we define how we want to set up the virtual environment. We can instruct the vm to retrieve and install any applications, gem, modules, or whatever we need here. In the above automatically generated Vagrantfile we see an example of this:
config.vm.provision "shell", inline: <<-SHELL apt-get update apt-get install -y apache2 SHELL
Notice that because this is a linux machine we can use normal linux commands to define and set up our environment.
The final version of the Vagrant File is:
Vagrant.configure("2") do |config| config.vm.box = "ubuntu/trusty64" config.vm.network "forwarded_port", guest: 3000, host: 3000 config.vm.synced_folder ".", "/vagrant_files" config.vm.provider "virtualbox" do |vb| vb.memory = "4096" end
Once we have defined the Vagrantfile we can use the command vagrant up and this will get our vagrant box up and running.
In my next blog post I will describe how to add the rails application to your vagrant box.