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 |
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
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
- Define multiple VMs using
config.vm.define - Assign unique network IPs to each VM
- Run
vagrant upto start all VMs simultaneously - Use
vagrant statusto 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.