How to Use Vagrant for Virtual Machine Management
In this blog, we will manage the VMs using Vagrant
Disadvantages of Managing Virtual Machines Manually
Time-Consuming Setup
Manually creating virtual machines (VMs) involves several steps, including downloading an operating system, configuring the VM settings, and installing necessary software. This repetitive process is not only time-consuming but also error-prone.Inconsistent Environments
When multiple team members create VMs independently, variations in configurations often lead to inconsistencies, making it difficult to replicate environments across teams.Error-Prone Configuration
Misconfigurations, such as incorrect network settings or conflicting dependencies, are common and require manual troubleshooting, which can lead to downtime or extended setup periods.
About Vagrant
Vagrant helps us to automate the provisioning, configuration, and management of virtualized environments.
Key Features:
- Works with multiple providers like VirtualBox, VMware, Hyper-V, and cloud platforms.
- Uses a configuration file (Vagrantfile
) to define and manage VM settings.
- Supports provisioning with tools like Ansible, Chef, Puppet, and shell scripts.
Advantages of Vagrant
Rapid Environment Setup
Vagrant allows for quick provisioning of development environments using predefined base images (boxes). This eliminates the repetitive manual setup process.Consistent Environments
By using a single Vagrantfile shared across teams, Vagrant ensures every developer works in an identical environment, reducing the “works on my machine” problem.Supports Provisioning Tools
Integration with configuration management tools like Ansible and Puppet allows for automated and repeatable setups, reducing manual effort.
How it Works
Vagrant reads them
Vagrantfile
to understand the required environment specifications.
vagrant init
, to generate the vagrant file.It automates the download of base images (called boxes).
The tool configures and provisions the environment, ensuring consistency and applicability.
Example: Create a Vagrantfile using a custom vagrant box for VirtualBox.
Pre-requisite steps…
Note: I have used Ubuntu 22.04 server image
Create the VM using the ISO file.
Create one VM manually, and install the server using an ISO file,
For better practice, use LVM to create a disk so that we can increase the partition whenever required.Create user.
Create a user that we use in the vagrant file configuration.
adduser minex
Add user to sudo file
Update the sudoers file, and add the entry of the above user.
echo "minex ALL=(ALL) NOPASSWD: ALL" | sudo tee /etc/sudoers.d/minex
Install all the required packages
Installing the following packages in the server.
apt install -y net-tools vim git
Set the timezone
ln -sf /usr/share/zoneinfo/Asia/Kolkata /etc/localtime
Convert .vdi to .box format
Packaging the existing VM’s .vdi into .box format
vagrant package --base Testing --output default-server.box
Added the .box file in the vagrant’s box listvagrant box add default-server/jammy64 default-server.box
Verify
vagrant box list
Creating the vagrant file
Using YAML-based configuration file for Vagrantfile.
We are going to use the YAML configuration file, where we define all the variables for the vagrant file.# syntax require 'yaml' config_data = YAML.load_file('config.yaml')
Using, the above syntax to load the config file.
# config.yaml file for Vagrantfile box_name: "default-server/jammy64" name: test hostname: test-server username: "minex" password: "098765" memory: "1024" cpu: 1 networks: bridge: true hostonly: false bridge: type: dhcp ip: "192.168.0.116" gateway: "192.168.0.1" hostonly: use_existing: false type: dhcp ip: "192.168.59.103" network: "VirtualBox Host-Only Ethernet Adapter #2"
Explanation:
- We use key-value pairs and dictionary variables.
- Based on the selection of the network, whether bridge or host-only, update the respective dictionary with appropriate values.
- In the Host-only network, we also have the option to choose the existing network or create a new one.Using the above-created custom vagrant box.
# syntax config.vm.box = "default-server/jammy64"
Create the condition-based networking setup.
# Configure a bridge network if config_data['networks']['bridge'] # Debugging output puts "Bridge setting: #{config_data['networks']['bridge']}" public_network_options = if config_data['bridge']['type'] == "dhcp" # Debugging output puts "DHCP setting: #{config_data['bridge']['type']}" { type: config_data['bridge']['type'] } elsif config_data['bridge']['type'] == "static" { type: config_data['bridge']['type'], ip: config_data['bridge']['ip'], gateway: config_data['bridge']['gateway'], netmask: "255.255.255.0", # Default netmask nameservers: ["8.8.8.8", "8.8.4.4"] # Default nameserver } end # Debugging output puts "Public Network options: #{public_network_options.inspect}" config.vm.network "public_network", **public_network_options end # Configure a host-only network if config_data['networks']['hostonly'] # Debugging output puts "Host-only setting: #{config_data['networks']['hostonly']}" private_network_options = if config_data['hostonly']['use_existing'] { type: 'static', # Default to static type ip: config_data['hostonly']['ip'], virtualbox__intnet: config_data['hostonly']['network'] } else # Debugging output puts "Use existing hostonly: #{config_data['hostonly']['use_existing']}" { type: 'static', # Default to static type ip: config_data['hostonly']['ip'] } end # Add DHCP or static type logic if config_data['hostonly']['type'] == "dhcp" private_network_options.delete(:ip) # Remove static IP if type is DHCP private_network_options[:type] = "dhcp" end
Explanation:
- Here, we have used the IF condition to check, and only execute if the respective network is selected.
- We also used aputs
command to print the output for debugging purposes.Override the SSH settings.
By default, Vagrant uses their own SSH private key to access and configure the VMs, but we are using our password-based login through Vagrant.# syntax # Override the SSH settings config.ssh.username = username # Replace with your username config.ssh.password = password # Replace with your password config.ssh.insert_key = false
Other config in the Vagrantfile
There are also other configs in the Vagrantfile, such as memory, CPU, graphic controller, USB controller, etc.Enable provisioning (optional)
We used the shell provisioning in the Vagrantfile, to install the required packages.
Refer to the Github repo for the full code.
Create VM using Vagrant file.
git clone https://github.com/minex970/vagrant
cd vagrant/default-server
# create config file using sample file.
cp sample-config.yaml config.yaml
# update the config as per the requirement
# creating vm
vagrant up
# access the server
vagrant ssh
Destroy the VMvagrant destory
Stop VMvagrant halt
SSH configvagrant ssh-config
, to get the SSH config of the current vagrant project.
For troubleshooting:
Use the following option while running up
and ssh
command, which was very helpful for debugging purposes.vagrant up --debug
ORvagrant up --debug-timestamp
Subscribe to our newsletter, for such blogs.
Refer to the following link: https://minex.hashnode.dev/benefits-of-choosing-iac-to-address-it-infrastructure-issues
Thank you for reading…