You've seen how to boot a simple virtual machine using Vagrant, so next, let's look at how to provision that VM in a repeatable way. As already mentioned, Vagrant supports a wide range of provisioners, but for the sake of this article, bash scripts will be used due to their familiarity. Adding a provisioning step is a matter of adding a single line inside the configure block in the Vagrantfile. The bootstrap also can be an inline script, but for most cases, it makes sense to supply a script file that contains the provisioning steps.
Add the following bootstrap.sh script to the same directory as the Vagrantfile:
#!/usr/bin/env bash # provisioning is run as root by default # make sure system sources are up to date. apt-get update # install a web server echo "==== Installing NGINX ====" apt-get install -y nginx echo "==== Start the NGINX Server ====" service nginx start
This bootstrap script makes sure the system sources are up to date first. It then installs the nginx Web server. The provisioning is added to the Vagrantfile by adding the following line to the configure block so that your Vagrantfile now looks like this:
Vagrant.configure("2") do |config| config.vm.box = "hashicorp/precise32" config.vm.provision :shell, :path => "bootstrap.sh" end
To use the new provisioning, destroy the running VM. This will stop and
remove the virtual machine. To destroy the VM, simply use the command
vagrant destroy. The base box still will be available for use after
running the destroy command. Now to test the new configuration, simply run
vagrant up. When a provisioning step is present in the Vagrantfile,
Vagrant automatically will provision the box once it has booted. You
can turn off the provisioning by using the
vagrant up is complete, you will be able to
ssh in to the
machine as before. As shown below, let's make sure that the provisioning has been
successful. Note that nginx is now installed on the system and running
on the system:
$ vagrant ssh $ which nginx /usr/sbin/nginx $ netstat -at | grep http tcp 0 0 *:http *:* LISTEN
The virtual machine has been provisioned, and nginx is set up and
started. The Web server can be tested to be working, but it's more
difficult if you have to
ssh in to the box to test
this. Next, let's
look at how to configure networking.
The first option to access ports on your virtual machine is port forwarding. For this example, nginx serves http traffic on port 80. To forward the guest machine port 80 to port 8080 on the host, add the following line to the Vagrantfile:
config.vm.network "forwarded_port", guest: 80, host: 8080
As before, destroy the VM and do another
vagrant up. Once the
virtual machine has been brought up and provisioned, the Web server
can be accessed on the host port 8080. On your favorite browser, visit
http://localhost:8080/ to be greeted with the nginx home page. This
is one of the easier ways to be able to connect to the virtual machine.
For example, let's modify the bootstrap.sh to link the "html" directory in the Vagrant directory to the nginx root directory. This would be an example of doing simple static HTML Web site development. This could be distributed to anybody to modify the HTML on the host and immediately see the results on the guest.
The revised bootstrap looks like this:
#!/usr/bin/env bash # provisioning is run as root by default # make sure system sources are up to date. apt-get update # install a web server echo "==== Installing NGINX ====" apt-get install -y nginx echo "==== Start the NGINX Server ====" service nginx start echo "==== Symlink Test Directory ====" ln -s /vagrant/html/ /usr/share/nginx/www/html
You can access the html directory through the nginx Web server using the forwarded port once the VM has been booted and provisioned by Vagrant. For example, using curl:
$ curl "http://localhost:8080/html/tester.html"
This example assumes an html directory is in your Vagrant directory that has a tester.html file in it.
What if you want to provide a way to access the virtual machine as if it were another machine on the network? Vagrant provides a very easy way to use VirtualBox networking to set up the virtual machine with a static IP on the same LAN. Remove the port forwarding line from the Vagrantfile and replace it with the following:
config.vm.network "private_network", ip: "192.168.56.20"
Once you have re-ran
vagrant up, your virtual machine will be accessible
from your host using the IP address specified above. In my own projects,
I use this private networking to assign my static IP a domain by modifying
the /etc/hosts file. This allows testing of complicated http redirect
flows that rely on certain domains.
It also allows multiple Vagrant virtual machines to contact one another, as it is a shared network between the host and all other virtual machines that are on the network. For distributed projects, being able to control the networking access of multiple standalone components all of which have their own Vagrantfile (or shared) is very powerful.
Again, in my work environment, it's not uncommon to spin up multiple virtual machines, one for a database, one for an app server and one for a squid proxy. Running functional tests against these tests a production-like setup. Vagrant allows you to do this in a simple, easy-to-repeat way, and the private network means there is no hassle in setting up intercommunication between the various components.
The last part of Vagrant that I want to cover is having multiple machines in the one Vagrantfile. I already have given an example of why you might want to have multiple Vagrantfiles for different components, so that they can be tested/developed on their own or as a collective. Having multiple machines in the one Vagrantfile is powerful when a single project can have multiple parts that don't belong on the one machine. Often in a Web development project, you will run the app server and database on the same machine for testing but will have multiple app servers and databases when that system gets into the production environment. This is the cause of a lot of production bugs due to untested component configuration.
Vagrant allows you to manage this all through a single Vagrantfile. If the idea of multiple machines is one that interests you, I also recommend looking closely at the new Docker container option for Vagrant. Docker is built on top of Linux containers and allows you to spin up machines much faster than VirtualBox. Multiple machine support in Vagrant is all the more powerful if the provider level is much faster to spin up machines.
For multiple machine support, the Vagrantfile allows you to configure multiple machines, each having their own configuration. The Vagrantfile below shows an example of what a MySQL master and slave Vagrantfile might look like:
Vagrant.configure("2") do |config| config.vm.box = "hashicorp/precise32" config.vm.define "master" do |master| master.vm.provision :shell, :path => "master_bootstrap.sh" master.vm.network "private_network", ip: "192.168.56.20" end config.vm.define "slave" do |slave| slave.vm.provision :shell, :path => "slave_bootstrap.sh" slave.vm.network "private_network", ip: "192.168.56.21" end end
Each machine is defined with the first config block as separate blocks. They support all of the same options as the normal one-machine Vagrant config blocks. For example, for the master here, you define the shell provisioning script to be run as well as the static IP address to give this virtual machine. This allows you to test distributed systems in the same easy repeatable way as you could with a single machine.
When using a multiple machine configuration like the above, there are a few changes
to the way you have to run Vagrant commands. Running
bring up both boxes automatically. The master will be provisioned first
and then the slave. You can choose to bring up only one of the machines
by supplying the machine name:
$ vagrant up master
When the boxes have booted and been provisioned, you also have to specify
the machine name when using
Let's reflect on
what you have
achieved here: multiple virtual machines booting, being provisioned
automatically and consistent IP addresses using one command—
up. This is repeatable across the three major operating systems and a
number of different providers including the most popular virtualization
technologies and cloud offerings.
This removes so many of the pain points from working on systems in
local development. There are a lot of advantages to making the switch to
using Vagrant for both local development and your continuous integration
systems. All developers' test machines are running the same code and are
provisioned in the same fashion. Test failures are not tied to a specific
developer's setup and should be reproducable on anyone's machine by running
vagrant up. This article covered only some of the amazing capabilities
of Vagrant, so I encourage you also to read over the brilliant
documentation at http://docs.vagrantup.com.
Richard Delaney is a software engineer with Demonware Ireland. Richard works on back-end Web services using Python and the Django Web framework. He has been an avid Linux user and evangelist for the past five years.
Pick up any e-commerce web or mobile app today, and you’ll be holding a mashup of interconnected applications and services from a variety of different providers. For instance, when you connect to Amazon’s e-commerce app, cookies, tags and pixels that are monitored by solutions like Exact Target, BazaarVoice, Bing, Shopzilla, Liveramp and Google Tag Manager track every action you take. You’re presented with special offers and coupons based on your viewing and buying patterns. If you find something you want for your birthday, a third party manages your wish list, which you can share through multiple social- media outlets or email to a friend. When you select something to buy, you find yourself presented with similar items as kind suggestions. And when you finally check out, you’re offered the ability to pay with promo codes, gifts cards, PayPal or a variety of credit cards.Get the Guide
|Omesh Tickoo and Ravi Iyer's Making Sense of Sensors (Apress)||Apr 21, 2017|
|Low Power Wireless: 6LoWPAN, IEEE802.15.4 and the Raspberry Pi||Apr 20, 2017|
|CodeLathe's Tonido Personal Cloud||Apr 19, 2017|
|Wrapping Up the Mars Lander||Apr 18, 2017|
|MultiTaction's MT Canvus-Connect||Apr 17, 2017|
|Android Candy: Facebook Everything?!?!||Apr 14, 2017|
- Teradici's Cloud Access Platform: "Plug & Play" Cloud for the Enterprise
- Low Power Wireless: 6LoWPAN, IEEE802.15.4 and the Raspberry Pi
- The Weather Outside Is Frightful (Or Is It?)
- Simple Server Hardening
- Understanding Firewalld in Multi-Zone Configurations
- Gordon H. Williams' Making Things Smart (Maker Media, Inc.)
- Non-Linux FOSS: Control Web-Based Music!
- Server Technology's HDOT Alt-Phase Switched POPS PDU
- IGEL Universal Desktop Converter