Vagrant para Entornos de Desarrollo
Vagrant automates development environment setup by providing lightweight, reproducible virtual machines configured through code. Vagrant enables developers to work in environments identical to production, eliminating dependency and configuration inconsistencies. This guide covers installation, Vagrantfile configuration, box management, provisioning strategies, networking, multi-machine setups, and synced folders.
Tabla de Contenidos
- Vagrant Overview
- Installation and Setup
- Vagrantfile Configuration
- Box Management
- Provisioning Strategies
- Networking Configuration
- Synced Folders
- Multi-Machine Environments
- Advanced Features
- Conclusion
Descripción General de Vagrant
Vagrant simplifies development environment creation by automating VM provisioning and configuration. Instead of manually installing software on development systems, Vagrant defines infrastructure as code, enabling teams to share identical environments.
Key benefits:
- Reproducibility: Same environment for all developers
- Consistency: Development matches production
- Isolation: No system package pollution
- Collaboration: Share Vagrant configurations via version control
- Multiple Providers: VirtualBox, Docker, Hyper-V support
- Simple Workflow: One command to start working
Vagrant architecture:
┌────────────────────────┐
│ Development Machine │
├────────────────────────┤
│ Vagrant CLI │
│ (vagrant up/ssh/etc) │
└──────────┬─────────────┘
│
▼
┌────────────────────────┐
│ Hypervisor/Provider │
│ (VirtualBox/Docker) │
└──────────┬─────────────┘
│
▼
┌────────────────────────┐
│ Virtual Machine │
│ (Development OS) │
│ Provisioned with code |
└────────────────────────┘
Instalación y Configuración
Install Vagrant and required dependencies.
Install Vagrant:
# macOS
brew install vagrant
# Ubuntu/Debian
wget https://releases.hashicorp.com/vagrant/2.4.0/vagrant_2.4.0_linux_amd64.zip
unzip vagrant_2.4.0_linux_amd64.zip
sudo mv vagrant /usr/local/bin/
# Windows
choco install vagrant
# Verify installation
vagrant version
Install VirtualBox provider:
# macOS
brew install virtualbox
# Ubuntu/Debian
sudo apt-get install virtualbox
# Windows
choco install virtualbox
# Verify
vboxmanage --version
Install additional providers (optional):
# Docker provider
vagrant plugin install vagrant-docker-compose
# Hyper-V provider (Windows)
vagrant plugin install vagrant-hyperv
# List installed plugins
vagrant plugin list
Configuración de Vagrantfile
The Vagrantfile defines VM configuration, provisioning, and networking.
Basic Vagrantfile:
# Vagrantfile
Vagrant.configure("2") do |config|
# Base box
config.vm.box = "ubuntu/focal64"
config.vm.box_version = "20.04.5"
# Hostname
config.vm.hostname = "devenv"
# Network
config.vm.network "private_network", ip: "192.168.33.10"
# Provider configuration
config.vm.provider "virtualbox" do |vb|
vb.gui = false
vb.cpus = 2
vb.memory = 2048
end
# Provisioning
config.vm.provision "shell", inline: <<-SHELL
apt-get update
apt-get install -y nginx
SHELL
end
Comprehensive Vagrantfile:
# Vagrantfile
Vagrant.configure("2") do |config|
config.vm.box = "ubuntu/focal64"
config.vm.box_version = "20.04.5"
config.vm.box_check_update = false
# Hostname and domain
config.vm.hostname = "webapp.local"
# Networks
# Private network for host-only access
config.vm.network "private_network", ip: "192.168.33.10"
# Port forwarding
config.vm.network "forwarded_port", guest: 80, host: 8080
config.vm.network "forwarded_port", guest: 443, host: 8443
config.vm.network "forwarded_port", guest: 3000, host: 3000
# Public network (bridged)
# config.vm.network "public_network"
# Synced folder
config.vm.synced_folder ".", "/vagrant", type: "virtualbox"
config.vm.synced_folder "app", "/opt/app", owner: "www-data", group: "www-data"
# VirtualBox configuration
config.vm.provider "virtualbox" do |vb|
vb.name = "webapp-dev"
vb.gui = false
vb.cpus = 2
vb.memory = 2048
vb.customize ["modifyvm", :id, "--natdnshostresolver1", "on"]
end
# Shell provisioning
config.vm.provision "shell", path: "scripts/bootstrap.sh"
# Shell inline provisioning
config.vm.provision "shell", inline: <<-SHELL
echo "Provisioning development environment"
systemctl start nginx
systemctl enable nginx
SHELL
# File provisioning
config.vm.provision "file", source: "config/nginx.conf",
destination: "/tmp/nginx.conf"
# Ansible provisioning
config.vm.provision "ansible" do |ansible|
ansible.playbook = "provisioning/playbook.yml"
ansible.become = true
end
# Docker provisioning
config.vm.provision :docker do |d|
d.images = ["ubuntu:20.04"]
end
# Disable default share
# config.vm.synced_folder ".", "/vagrant", disabled: true
end
Configuration with variables:
# Vagrantfile
require 'yaml'
# Load configuration from file
config_file = File.expand_path('vagrant.yml', __dir__)
config_data = YAML.load_file(config_file) if File.exist?(config_file)
config_data ||= {}
Vagrant.configure("2") do |config|
config.vm.box = config_data['box'] || "ubuntu/focal64"
config.vm.hostname = config_data['hostname'] || "vagrant"
config.vm.provider "virtualbox" do |vb|
vb.cpus = config_data['cpus'] || 2
vb.memory = config_data['memory'] || 2048
end
config.vm.network "private_network",
ip: config_data['ip'] || "192.168.33.10"
(config_data['ports'] || {}).each do |guest, host|
config.vm.network "forwarded_port",
guest: guest, host: host
end
end
vagrant.yml:
# vagrant.yml
box: ubuntu/focal64
hostname: webapp
cpus: 4
memory: 4096
ip: 192.168.33.10
ports:
80: 8080
443: 8443
3000: 3000
5432: 5432
Gestión de Boxes
Vagrant boxes are base images for virtual machines.
Find and use boxes:
# Search for boxes
vagrant box search ubuntu
# Add a box
vagrant box add ubuntu/focal64
# Specific version
vagrant box add ubuntu/focal64 --box-version 20.04.5
# Add from URL
vagrant box add mybox https://example.com/boxes/mybox.box
# List boxes
vagrant box list
# Remove box
vagrant box remove ubuntu/focal64
# Update boxes
vagrant box update
Create custom box:
# Package VM as box
vagrant package --output mybox.box
# Import box
vagrant box add mybox file://mybox.box
# Add to Vagrant Cloud
# Login
vagrant login
# Push to cloud
vagrant cloud publish myorg/mybox 1.0 virtualbox mybox.box
Estrategias de Aprovisionamiento
Provision VMs with required software and configuration.
Shell provisioning:
# Inline script
config.vm.provision "shell", inline: <<-SHELL
apt-get update
apt-get install -y nginx
systemctl start nginx
SHELL
# External script
config.vm.provision "shell", path: "bootstrap.sh"
# With arguments
config.vm.provision "shell",
path: "bootstrap.sh",
args: ["nginx", "php-fpm"]
# As different user
config.vm.provision "shell",
inline: "echo 'Hello from non-root'",
privileged: false
bootstrap.sh:
#!/bin/bash
set -e
echo "Installing packages..."
apt-get update
apt-get install -y \
nginx \
curl \
wget \
vim \
git
echo "Configuring services..."
systemctl start nginx
systemctl enable nginx
echo "Bootstrap complete"
File provisioning:
# Copy file
config.vm.provision "file",
source: "config/nginx.conf",
destination: "/tmp/nginx.conf"
# Copy directory
config.vm.provision "file",
source: "app/",
destination: "/opt/app"
# Run as root after copying
config.vm.provision "shell",
inline: "mv /tmp/nginx.conf /etc/nginx/nginx.conf && systemctl reload nginx",
privileged: true
Ansible provisioning:
config.vm.provision "ansible" do |ansible|
ansible.playbook = "provisioning/playbook.yml"
ansible.inventory_path = "provisioning/inventory"
ansible.become = true
ansible.extra_vars = {
ansible_python_interpreter: "/usr/bin/python3"
}
end
provisioning/playbook.yml:
---
- hosts: all
become: yes
vars:
packages:
- nginx
- curl
- git
tasks:
- name: Update package cache
apt:
update_cache: yes
- name: Install packages
apt:
name: "{{ packages }}"
state: present
- name: Start nginx
systemd:
name: nginx
state: started
enabled: yes
Docker provisioning:
config.vm.provision :docker do |d|
# Install Docker
d.version = "latest"
# Pull images
d.images = [
"ubuntu:20.04",
"postgres:13",
"redis:latest"
]
# Build image
d.build_image "/vagrant/Dockerfile",
args: "-t myapp:latest"
# Run container
d.run "postgres:13",
args: "-d --name db -e POSTGRES_PASSWORD=secret"
# Install docker-compose
d.install_docker_compose = true
end
Configuración de Red
Configure networking for VM access and communication.
Network types:
# Private network (host-only)
config.vm.network "private_network", ip: "192.168.33.10"
# Dynamic IP
config.vm.network "private_network", type: "dhcp"
# Port forwarding
config.vm.network "forwarded_port", guest: 80, host: 8080
# Public network (bridged)
config.vm.network "public_network",
bridge: "en0: Wi-Fi (AirPort)"
# Multiple networks
config.vm.network "private_network", ip: "192.168.33.10"
config.vm.network "private_network", ip: "192.168.34.10"
Advanced networking:
# Configure hostname and DNS
config.vm.hostname = "webapp.local"
config.vm.network "private_network",
ip: "192.168.33.10",
hostname: true
# Port forwarding with autocorrect
config.vm.network "forwarded_port",
guest: 80,
host: 8080,
auto_correct: true
# Multiple port forwards
[
{ guest: 80, host: 8080 },
{ guest: 443, host: 8443 },
{ guest: 3000, host: 3000 }
].each do |port|
config.vm.network "forwarded_port",
guest: port[:guest],
host: port[:host]
end
# Configure /etc/hosts on host
config.hostsupdater.aliases = ["webapp.local", "api.local"]
Carpetas Sincronizadas
Share folders between host and guest for development.
Basic synced folders:
# Default sync (current directory to /vagrant)
config.vm.synced_folder ".", "/vagrant", type: "virtualbox"
# Sync app directory
config.vm.synced_folder "app", "/opt/app"
# Sync with ownership
config.vm.synced_folder "app", "/opt/app",
owner: "www-data",
group: "www-data"
# Sync with mount options
config.vm.synced_folder ".", "/vagrant",
mount_options: ["dmode=755", "fmode=644"]
# Disable default share
config.vm.synced_folder ".", "/vagrant", disabled: true
NFS synced folders (faster for large directories):
# NFS requires nfs-utils on host
config.vm.synced_folder ".", "/vagrant", type: "nfs"
# With specific options
config.vm.synced_folder "app", "/opt/app",
type: "nfs",
nfs_version: 4,
nfs_udp: false
rsync synced folders (one-way sync):
# Auto-sync on vagrant up
config.vm.synced_folder "app", "/opt/app",
type: "rsync",
rsync__auto: true,
rsync__exclude: [".git", "node_modules", ".env"]
# Manual sync
# vagrant rsync
# vagrant rsync-auto
Entornos Multi-Máquina
Define complex environments with multiple VMs.
Multi-machine Vagrantfile:
# Vagrantfile
Vagrant.configure("2") do |config|
config.vm.box = "ubuntu/focal64"
# Web server
config.vm.define "web" do |web|
web.vm.hostname = "web.local"
web.vm.network "private_network", ip: "192.168.33.10"
web.vm.network "forwarded_port", guest: 80, host: 8080
web.vm.provider "virtualbox" do |vb|
vb.cpus = 2
vb.memory = 2048
vb.name = "webapp-web"
end
web.vm.provision "shell", path: "scripts/install-nginx.sh"
end
# Database server
config.vm.define "db" do |db|
db.vm.hostname = "db.local"
db.vm.network "private_network", ip: "192.168.33.11"
db.vm.provider "virtualbox" do |vb|
vb.cpus = 2
vb.memory = 4096
vb.name = "webapp-db"
end
db.vm.provision "shell", path: "scripts/install-postgres.sh"
end
# Cache server
config.vm.define "cache" do |cache|
cache.vm.hostname = "cache.local"
cache.vm.network "private_network", ip: "192.168.33.12"
cache.vm.provider "virtualbox" do |vb|
vb.cpus = 1
vb.memory = 1024
vb.name = "webapp-cache"
end
cache.vm.provision "shell", path: "scripts/install-redis.sh"
end
end
Control multi-machine environments:
# Start all machines
vagrant up
# Start specific machine
vagrant up web
# SSH into specific machine
vagrant ssh db
# Provision specific machine
vagrant provision cache
# Status of all machines
vagrant status
# Destroy specific machine
vagrant destroy db
Características Avanzadas
Triggers and callbacks:
# Run script before/after actions
config.trigger.before :up do |trigger|
trigger.info = "Preparing environment..."
trigger.run = {inline: "echo 'Starting up'"}
end
config.trigger.after :up do |trigger|
trigger.info = "Environment ready"
trigger.run = {path: "scripts/post-up.sh"}
end
# Before provision
config.trigger.before :provision do |trigger|
trigger.info = "Running pre-provision checks"
end
Plugins:
# Useful plugins
vagrant plugin install vagrant-vbguest # VirtualBox guest additions
vagrant plugin install vagrant-cachier # Shared cache directory
vagrant plugin install vagrant-env # .env file support
vagrant plugin install vagrant-docker-login # Docker registry auth
# List plugins
vagrant plugin list
# Update plugins
vagrant plugin update
# Remove plugin
vagrant plugin uninstall vagrant-vbguest
Debugging:
# Verbose output
vagrant up --debug
# View logs
cat ~/.vagrant.d/logs/vagrant.log
# SSH with verbose
vagrant ssh -- -vvv
# Test connectivity
vagrant ssh -c "ping 8.8.8.8"
Conclusión
Vagrant eliminates development environment inconsistencies by providing reproducible, infrastructure-as-code virtual machines. By configuring VMs through Vagrantfiles, provisioning with shells or configuration management, and sharing configurations through version control, teams ensure all developers work in identical environments. Combined with Docker containers and orchestration tools, Vagrant provides a foundation for consistent development and testing workflows.


