Vagrant is neat if you need a whip up a machine to quickly test a script or check compatibility on an operating system that is different than what you normally run. And the value of that isn’t to be minimized. But some of the real power of Vagrant happens when you start to stand up full environments (think 3-tier applications or large scale web server farms) in a repeatable, effortless way. In Hashicorp Land, this is specifically referred to as a “multi-machine” environment. Any Vagrantfile that defines and controls multiple guest machines qualifies for this descriptor.
Defining Multi-Machine Environments
Building a Vagrantfile that will configure a multi-machine environment is as simple as defining multiple VMs with the parameter config.vm.define.
In the below example nabbed from Hashicorp documentation, one case see that an Apache front end and MySQL back end are both defined.
Vagrant.configure("2") do |config| config.vm.provision "shell", inline: "echo Hello" config.vm.define "web" do |web| web.vm.box = "apache" end config.vm.define "db" do |db| db.vm.box = "mysql" end end
Once the VMs are defined, configuration takes place by using the inner variable with the same name. In the example, web.
anything and db.
anything will apply configurations specifically to that machine. Global configurations can still be defined and will apply to all VMs. When configuring a multi-machine environment, it’s important to consider the load order of a Vagrantfile. I covered this in Part 3 of this series, but just to quickly recap, the load order is:
- Vagrantfile packaged with the box that is to be used for a given machine.
- Vagrantfile in your Vagrant home directory (defaults to
~/.vagrant.d
). This lets you specify some defaults for your system user. - Vagrantfile from the project directory. This is the Vagrantfile that you’ll be modifying most of the time.
- Multi-machine overrides if any.
- Provider-specific overrides, if any.
As the Vagrantfile grows and a large number of machines are defined, it can become a bit of a mess. Scott Lowe wrote about an idea he found over on this blog that breaks all the configuration data out into a separate YAML file. You could also use JSON or XML if you’re more comfortable with that, as in this example.
Accessing Multi-Machine Environments
When using a multi-machine environment, some vagrant commands need to become more specific. If you issue vagrant ssh
in a multi-machine environment, which machine should be connected to? The commands in a multi-machine environment that only make sense for one machine need to have the machine specified in the command. So in the case of SSH, the command would be vagrant ssh web
. In the case of a command like reload, you could issue vagrant reload
and reload the whole environment, or you could specify one VM, as in vagrant reload db
. Since sometimes one needs to be specific but there’s also a large number of VM’s, the Vagrantfile will also parse regex when it identifies a regular expression for the name, such as /web[A-Za-z0-9]/
.