Skip to main content

Working with Multi-Machine Environments

1. Defining Multiple VMs

Property Description Example
config.vm.define Defines a named VM within the Vagrantfile config.vm.define "web"
config.vm.box Specifies the base box for a VM config.vm.box = "ubuntu/focal64"
config.vm.network Configures network settings for a VM config.vm.network "private_network", ip: "192.168.56.10"
config.vm.provision Runs provisioners on a specific VM config.vm.provision "shell", path: "setup.sh"

Example: Defining Multiple VMs in Vagrantfile

# Vagrantfile
Vagrant.configure("2") do |config|
  config.vm.define "web" do |web|
    web.vm.box = "ubuntu/focal64"
    web.vm.network "private_network", ip: "192.168.56.10"
    web.vm.provision "shell", path: "web_setup.sh"
  end

  config.vm.define "db" do |db|
    db.vm.box = "centos/7"
    db.vm.network "private_network", ip: "192.168.56.11"
    db.vm.provision "shell", path: "db_setup.sh"
  end
end
Note: Each VM defined with config.vm.define can have its own unique configuration including box, network, and provisioners.

2. Setting Primary Machine

Option Values Notes
primary true Designates the primary machine in a multi-machine environment

Example: Defining Primary Machine

Vagrant.configure("2") do |config|
  config.vm.define "web" do |web|
    web.vm.box = "ubuntu/focal64"
    web.vm.network "private_network", ip: "192.168.10.10"
  end

  config.vm.define "db" do |db|
    db.vm.box = "ubuntu/focal64"
    db.vm.network "private_network", ip: "192.168.10.11"
    db.vm.provision "shell", inline: "echo 'DB machine'"
  end

  config.vm.define "primary", primary: true do |primary|
    primary.vm.box = "ubuntu/focal64"
    primary.vm.network "private_network", ip: "192.168.10.12"
    primary.vm.provision "shell", inline: "echo 'Primary machine'"
  end
end
Note: The primary option is used to designate one machine as the primary in a multi-machine environment. This machine is typically used for operations like vagrant up when no specific machine is specified.

3. Configuring Machine-Specific Settings

Setting Description Example
config.vm.provision Provisioning script or playbook to run on the machine config.vm.provision "shell", path: "script.sh"
config.vm.network Network configuration for the machine (private/public) config.vm.network "private_network", ip: "192.168.56.10"
config.vm.synced_folder Synced folder configuration between host and guest config.vm.synced_folder ".", "/vagrant"
config.vm.box Base box to use for the machine config.vm.box = "ubuntu/focal64"
config.vm.hostname Hostname for the machine config.vm.hostname = "webserver"

Example: Machine-specific network configuration

config.vm.define "web" do |web|
  web.vm.network "private_network", ip: "192.168.56.10"
  web.vm.hostname = "webserver"
end

config.vm.define "db" do |db|
  db.vm.network "private_network", ip: "192.168.56.11"
  db.vm.hostname = "dbserver"
end
Note: Machine-specific settings override global configurations in the Vagrantfile.

4. Using Auto-Start

Auto-start functionality in Vagrant allows you to automatically start and provision multiple machines defined in your Vagrantfile with a single command. This is particularly useful for multi-machine environments where you want to ensure all machines are running and configured consistently.

Option Values Description
config.vm.autostart true | false Determines whether the machine should be started automatically when running vagrant up without specifying a machine name. Defaults to false.

Example: Enabling Auto-Start for a Machine

config.vm.define "web" do |web|
  web.vm.box = "ubuntu/focal64"
  web.vm.network "private_network", ip: "192.168.56.10"
  web.vm.autostart = true
end
Note: When config.vm.autostart is set to true, the machine will be started automatically during vagrant up even if it is not explicitly targeted. This can be useful for setting up a default environment with specific machines always running.

5. Managing Individual Machines

Command Description Options
vagrant up <machine-name> Starts a specific machine --no-provision to skip provisioning
vagrant halt <machine-name> Shuts down a specific machine --force to force shutdown
vagrant suspend <machine-name> Puts a machine in suspended state None
vagrant resume <machine-name> Resumes a suspended machine None
vagrant reload <machine-name> Reloads a specific machine --provision to re-run provisioners
vagrant destroy <machine-name> Destroys a specific machine --force to skip confirmation

Example: Starting a Specific Machine

vagrant up web-server

Example: Halting a Specific Machine

vagrant halt database
Note: Machine names are defined in the Vagrantfile under the config.vm.define directive.

6. Communicating Between Machines

Method Description Usage Notes
private_network Creates a private network between machines config.vm.network "private_network", ip: "192.168.10.10" Allows direct communication between VMs
public_network Assigns a public network interface to the VM config.vm.network "public_network" Accessible from the host machine
forwarded_port Maps a port from the host to guest machine config.vm.network "forwarded_port", guest: 80, host: 8080 Useful for web development

Example: Setting up private network communication

Vagrant.configure("2") do |config|
  config.vm.define "web" do |web|
    web.vm.box = "ubuntu/focal64"
    web.vm.network "private_network", ip: "192.168.10.10"
  end

  config.vm.define "db" do |db|
    db.vm.box = "ubuntu/focal64"
    db.vm.network "private_network", ip: "192.168.10.11"
  end
end
Note: Private networks are isolated to the Vagrant environment and do not require host machine configuration.
Warning: Ensure that IP addresses used in private networks do not conflict with existing network ranges.

7. Setting Machine Dependencies

Dependency Type Description Configuration Notes
config.vm.provision Provisioning script or playbook to run on the machine "shell" or "ansible" Can be run multiple times in sequence
config.vm.provision "shell" Runs a shell script on the guest machine path: "script.sh" or inline: "echo 'Hello'" Supports inline or external scripts
config.vm.provision "ansible" Runs an Ansible playbook on the guest machine playbook: "playbook.yml" Requires Ansible to be installed on the host
config.vm.provision "ansible_local" Runs an Ansible playbook using local Ansible on the guest playbook: "playbook.yml" Does not require Ansible on the host

Example: Shell Provisioning

config.vm.provision "shell", inline: <<-SHELL
  echo "Installing Node.js"
  curl -sL https://deb.nodesource.com/setup_20.x | sudo -E bash -
  sudo apt-get install -y nodejs
SHELL

Example: Ansible Provisioning

config.vm.provision "ansible", playbook: "playbook.yml"
Note: Provisioning runs after the machine is created but before it is configured. Dependencies between machines can be managed using config.vm.network and custom scripts.
Warning: Provisioning scripts should be idempotent to avoid issues during repeated runs.

8. Using Parallel Execution

Example: Parallel VMs with Vagrant

Vagrant.configure("2") do |config|
  config.vm.define "web" do |web|
    web.vm.box = "ubuntu/focal64"
    web.vm.network "private_network", ip: "192.168.56.10"
  end

  config.vm.define "db" do |db|
    db.vm.box = "ubuntu/focal64"
    db.vm.network "private_network", ip: "192.168.56.11"
  end

  config.vm.provision "shell", inline: "echo 'Starting parallel VMs'"
end
Option Description Default
config.vm.provision Provisioning script to run on each VM None
config.vm.network Network configuration for VMs None
Note: Parallel execution is enabled by default in Vagrant when multiple VMs are defined.

Workflow: Running Parallel VMs

  1. Define multiple VMs using config.vm.define
  2. Assign unique network IPs to each VM
  3. Run vagrant up to start all VMs simultaneously
  4. Use vagrant status to check VM states

Comparison: Vagrant vs Docker for Parallel Environments

  • Vagrant: Full VMs, more isolation, slower startup
  • Docker: Lightweight containers, faster, less isolation

9. Configuring Provider Per Machine

Machine Provider Configuration
web virtualbox Default provider settings
db vmware_fusion VMware-specific settings
worker libvirt Libvirt-specific settings

Example: Multi-provider configuration

Vagrant.configure("2") do |config|
  config.vm.define "web" do |web|
    web.vm.provider "virtualbox"
    web.vm.box = "ubuntu/focal64"
  end

  config.vm.define "db" do |db|
    db.vm.provider "vmware_fusion"
    db.vm.box = "centos/7"
  end

  config.vm.define "worker" do |worker|
    worker.vm.provider "libvirt"
    worker.vm.box = "debian/bullseye64"
  end
end
Note: Each machine can have its own provider configuration, allowing for different virtualization technologies per machine.

10. Setting Provisioning Order

When working with multi-machine environments in Vagrant, controlling the order of provisioning is crucial for dependencies and setup sequences.

Property Description Values
provisioners List of provisioners to run on each machine ['shell', 'ansible']
order Defines the order in which provisioners run 1, 2, 3...

Example: Defining Provisioning Order

Vagrant.configure("2") do |config|
  config.vm.define "web" do |web|
    web.vm.provision "shell", inline: "echo 'Web server setup'"
    web.vm.provision "ansible", playbook: "web.yml"
  end

  config.vm.define "db" do |db|
    db.vm.provision "shell", inline: "echo 'Database setup'"
    db.vm.provision "ansible", playbook: "db.yml"
  end
end
Note: Provisioners within a single machine are executed in the order they are defined. For inter-machine dependencies, use shell scripts or Ansible roles to manage setup sequence.

Was this article helpful?