While studying for my RHCSA certificate two years ago, I needed a solution to easily build and destroy VMs that would mimic the testing environment. After some googling, I stumbled on a RHCSA Reddit thread where a user mentioned Vagrant π‘.
Vagrant is an open-source tool that helps to automate the creation and management of Virtual Machines. Vagrant simplifies the management of virtual environments, and ensures uniform development setups across your team, , while being easy to use and highly customizable. In this article, Iβll guide you through setting up your first Vagrant VM.
β οΈ If you have a Mac with Apple silicon, this guide isn’t for you π.
Prerequisites π
Before you follow along, lets take care of some housekeeping.
First you’ll need to download Vagrant.
Finally you’ll need to download a provider. In Vagrant, a βproviderβ refers to the software that Vagrant uses to create and manage virtual environments. Providers are responsible for managing the underlying resources that Vagrant interacts with, such as virtual machines, containers, or cloud instances. Vagrant supports a variety of providers:
- VirtualBox
- VMware
- Hyper-V
- Docker
Understanding The Vagrantfile π
A Vagrantfile
is a configuration file used by Vagrant to define the settings and setup of a virtual environment. It serves as a blueprint for Vagrant to create and manage the virtual machines consistently across different environments. It is written in Ruby and provides a way to describe the type of machine required for a project, how it should be configured, and the software that needs to be installed. It’s akin to an ansible playbook, or a recipe in a cookbook. To see one of these in action, run the following command. vagrant init
. If successful, you should see the following output:
A `Vagrantfile` has been placed in this directory. You are now
ready to `vagrant up` your first virtual environment! Please read
the comments in the Vagrantfile as well as documentation on
`vagrantup.com` for more information on using Vagrant.
On your machine, you will see a lot of commented out lines, but we’ll ignore those for now and focus on the following:
Vagrant.configure("2") do |config|
config.vm.box = "base"
end
Vagrantfiles are broken into different blocks. This is a config block, which initializes a Vagrant environment using the βbaseβ box as the virtual machine image. This is the most basic configuration one can.
To start this VM, you’d run the vagrant up
. Lets try to bring our VM up.
β ~ vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Box 'base' could not be found. Attempting to find and install...
default: Box Provider: virtualbox
default: Box Version: >= 0
==> default: Box file was not detected as metadata. Adding it directly...
==> default: Adding box 'base' (v0) for provider: virtualbox
default: Downloading: base
An error occurred while downloading the remote file. The error
message, if any, is reproduced below. Please fix this error and try
again.
Couldn't open file /Users/vagrant_user/base
Unfortunately, it failed because base is not a valid box. In the next section, I’ll discuss vagrant boxes.
Understanding Boxes π
A Vagrant box is a prepackaged, base virtual machine image used to create and provision new Vagrant environments. It contains the operating system and may include additional software or configurations. Boxes serve as the starting point for Vagrant environments, providing a consistent foundation upon which developers can build and customize their virtual machines. If you need Ubuntu, there’s a box for that! If you prefer CentOS, there’s a box for that as well. There a ton on Vagrant Cloud to choose from.
Here’s our above example of a with an updated vm.box
.
Vagrant.configure("2") do |config|
config.vm.box = "generic/rhel8"
end
Now when we run vagrant up
, we should see output similar to the following:
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Box 'generic/centos8' could not be found. Attempting to find and install...
default: Box Provider: virtualbox
default: Box Version: >= 0
==> default: Loading metadata for box 'generic/centos8'
default: URL: https://vagrantcloud.com/api/v2/vagrant/generic/centos8
==> default: Adding box 'generic/centos8' (v4.3.12) for provider: virtualbox (amd64)
default: Downloading: https://vagrantcloud.com/generic/boxes/centos8/versions/4.3.12/providers/virtualbox/amd64/vagrant.box
default: Calculating and comparing box checksum...
==> default: Successfully added box 'generic/centos8' (v4.3.12) for 'virtualbox (amd64)'!
==> default: Importing base box 'generic/centos8'...
==> default: Matching MAC address for NAT networking...
==> default: Checking if box 'generic/centos8' version '4.3.12' is up to date...
==> default: Setting the name of the VM: xavier_default_1718241012190_34544
==> default: Clearing any previously set network interfaces...
==> default: Preparing network interfaces based on configuration...
default: Adapter 1: nat
==> default: Forwarding ports...
default: 22 (guest) => 2222 (host) (adapter 1)
==> default: Running 'pre-boot' VM customizations...
==> default: Booting VM...
==> default: Waiting for machine to boot. This may take a few minutes...
default: SSH address: 127.0.0.1:2222
default: SSH username: vagrant
default: SSH auth method: private key
default: Vagrant insecure key detected. Vagrant will automatically replace
default: this with a newly generated keypair for better security.
default:
default: Inserting generated public key within guest...
default: Removing insecure key from the guest if it's present...
default: Key inserted! Disconnecting and reconnecting using new SSH key...
==> default: Machine booted and ready!
We can no ssh into our box with the vagrant ssh
command!
xavier@MacBook-Pro ~ % vagrant ssh
[vagrant@centos8 ~]$
Handy Vagrant Commands π
Besides vagrant init
, vagrant up
, and vagrant ssh
, there a few other handy vagrant commands you’ll be using:
vagrant status
- Show current box status.vagrant suspend
- Pause the current box.vagrant resume
- Resume the current box.vagrant halt
- Shutdown the current box.vagrant destroy
- Destroy the current box. By running this command, you will lose any data stored on the box.vagrant snapshot
- Take a snapshot of the current box.vagrant reload
- The equivalent of running a halt followed by an up. This command is required after making changes to your Vagrantfile.
Enhancing Your Vagrantfile Configuration π
Our example Vagrantfile demonstrates the simplest possible configuration, but Vagrant offers a wealth of features to further customize your development environment. Here are a few additions you can make to enhance your Vagrant setup:
Adding a Custom Box π
You can specify a custom box instead of the default “base”:
Vagrant.configure("2") do |config|
config.vm.box = "generic/rhel8"
end
Setting Up Networking π
Configure port forwarding or a private network:
Vagrant.configure("2") do |config|
config.vm.box = "generic/rhel8"
# Forward a port from the guest to the host
config.vm.network "forwarded_port", guest: 80, host: 8080
# Create a private network, which allows host-only access to the machine
config.vm.network "private_network", type: "dhcp"
end
Syncing Folders π
Sync folders between your host machine and the guest VM to easily share files:
Vagrant.configure("2") do |config|
config.vm.box = "generic/rhel8"
# Sync a folder from the host to the guest
config.vm.synced_folder "./data", "/vagrant_data"
end
Provisioning π
Automate the setup of your development environment using shell scripts, Ansible, Chef, or Puppet:
Vagrant.configure("2") do |config|
config.vm.box = "generic/rhel8"
# Use a shell script to provision the VM
config.vm.provision "shell", inline: <<-SHELL
sudo apt-get update
sudo apt-get install -y apache2
SHELL
end
Customizing VM Resources π
Adjust the virtual machine’s resources such as memory and CPU:
Vagrant.configure("2") do |config|
config.vm.box = "generic/rhel8"
config.vm.provider "virtualbox" do |vb|
# Customize the amount of memory on the VM
vb.memory = "1024"
vb.cpus = 2
end
end
Multi-Machine Setup π
Define multiple virtual machines within the same Vagrantfile for complex environments:
Vagrant.configure("2") do |config|
config.vm.define "web" do |web|
web.vm.box = "generic/rhel8"
web.vm.network "private_network", ip: "192.168.33.10"
end
config.vm.define "db" do |db|
db.vm.box = "generic/rhel8"
db.vm.network "private_network", ip: "192.168.33.11"
end
end
By incorporating these features, you can create a more robust and tailored development environment to meet your specific needs.
This was just a brief introduction to Vagrant. Head over to their website for more detailed documentation, tutorials, and a comprehensive list of features.
Thanks for reading! If you found this post helpful, please share it with someone who might benefit from it.