» Multi-Machine

Vagrant is able to define and control multiple guest machines perVagrantfile. This is known as a "multi-machine" environment.

These machines are generally able to work together or are somehow associatedwith each other. Here are some use-cases people are using multi-machineenvironments for today:

  • Accurately modeling a multi-server production topology, such as separatinga web and database server.
  • Modeling a distributed system and how they interact with each other.
  • Testing an interface, such as an API to a service component.
  • Disaster-case testing: machines dying, network partitions, slow networks,inconsistent world views, etc.Historically, running complex environments such as these was done byflattening them onto a single machine. The problem with that is that it isan inaccurate model of the production setup, which can behave far differently.

Using the multi-machine feature of Vagrant, these environments can be modeledin the context of a single Vagrant environment without losing any of thebenefits of Vagrant.

» Defining Multiple Machines

Multiple machines are defined within the same project Vagrantfileusing the config.vm.define method call. This configuration directiveis a little funny, because it creates a Vagrant configuration within aconfiguration. An example shows this best:

  1. Vagrant.configure("2") do |config|
  2. config.vm.provision "shell", inline: "echo Hello"
  3. config.vm.define "web" do |web|
  4. web.vm.box = "apache"
  5. end
  6. config.vm.define "db" do |db|
  7. db.vm.box = "mysql"
  8. end
  9. end

As you can see, config.vm.define takes a block with another variable. Thisvariable, such as web above, is the exact same as the config variable,except any configuration of the inner variable applies only to the machinebeing defined. Therefore, any configuration on web will only affect theweb machine.

And importantly, you can continue to use the config object as well. Theconfiguration object is loaded and merged before the machine-specific configuration,just like other Vagrantfiles within theVagrantfile load order.

If you are familiar with programming, this is similar to how languages havedifferent variable scopes.

When using these scopes, order of execution for things such asprovisioners becomes important. Vagrant enforces ordering outside-in, inthe order listed in the Vagrantfile. For example, with the Vagrantfilebelow:

  1. Vagrant.configure("2") do |config|
  2. config.vm.provision :shell, inline: "echo A"
  3. config.vm.define :testing do |test|
  4. test.vm.provision :shell, inline: "echo B"
  5. end
  6. config.vm.provision :shell, inline: "echo C"
  7. end

The provisioners in this case will output "A", then "C", then "B". Noticethat "B" is last. That is because the ordering is outside-in, inthe order of the file.

If you want to apply a slightly different configuration to multiple machines,see this tip.

» Controlling Multiple Machines

The moment more than one machine is defined within a Vagrantfile, theusage of the various vagrant commands changes slightly. The change shouldbe mostly intuitive.

Commands that only make sense to target a single machine, such asvagrant ssh, now require the name of the machine to control. Usingthe example above, you would say vagrant ssh web or vagrant ssh db.

Other commands, such as vagrant up, operate on every machine bydefault. So if you ran vagrant up, Vagrant would bring up both theweb and DB machine. You could also optionally be specific and sayvagrant up web or vagrant up db.

Additionally, you can specify a regular expression for matching onlycertain machines. This is useful in some cases where you specify many similarmachines, for example if you are testing a distributed service you may havea leader machine as well as a follower0, follower1, follower2, etc. If youwant to bring up all the followers but not the leader, you can just dovagrant up /follower[0-9]/. If Vagrant sees a machine name within forwardslashes, it assumes you are using a regular expression.

» Communication Between Machines

In order to facilitate communication within machines in a multi-machine setup,the various networking options should be used.In particular, the private network canbe used to make a private network between multiple machines and the host.

» Specifying a Primary Machine

You can also specify a primary machine. The primary machine will be thedefault machine used when a specific machine in a multi-machine environmentis not specified.

To specify a default machine, just mark it primary when defining it. Onlyone primary machine may be specified.

  1. config.vm.define "web", primary: true do |web|
  2. # ...
  3. end

» Autostart Machines

By default in a multi-machine environment, vagrant up will startall of the defined machines. The autostart setting allows you to tellVagrant to not start specific machines. Example:

  1. config.vm.define "web"
  2. config.vm.define "db"
  3. config.vm.define "db_follower", autostart: false

When running vagrant up with the settings above, Vagrant will automaticallystart the "web" and "db" machines, but will not start the "db_follower" machine.You can manually force the "db_follower" machine to start by runningvagrant up db_follower.