DEV Community

Cover image for How to Create and Automate Virtual Machines using Vagrant
Kehinde Alade
Kehinde Alade

Posted on • Updated on

How to Create and Automate Virtual Machines using Vagrant

Vagrant is an automation tool that helps in easily creating virtual machines and automating them while saving time and increasing productivity.

Based on https://www.vagrantup.com/intro, Vagrant is a tool for building and managing virtual machine environments in a single workflow. With an easy-to-use workflow and focus on automation, Vagrant lowers development environment setup time, increases production parity, and makes the "works on my machine" excuse a relic of the past.

Have you ever used VirtualBox or VMWare before? Vagrant helps us automate and quickly build the things you'd have used VirtualBox for; sounds easy, I know, right?

We'd be learning about Vagrant by using it with Ansible; what is Ansible?

Ansible is an IT automation tool. It can configure systems, deploy software, and orchestrate more advanced IT tasks such as continuous deployments or zero downtime rolling updates.

Ever thought of writing a script to automate something for you using Python or Golang? Ansible helps you do that without writing actual codes; YAML is the language ansible understands.

Even though I've tried to make this article as beginner-level as it could be, there are still some requirements;

  • YAML (basics)
  • Docker (basics)
  • Linux
  • Basics of VirtualBox

So what's the point of this article? What do we want to use Ansible and Vagrant for?

We would use Vagrant to create three remote Virtual Machines using Virtual Box and automate tasks using Ansible on the VMs.

The three VMs are;

  1. The Controller VM: This controls other targets VMs and automates tasks using Ansible, so, Ansible will be installed on the Controller VM.
  2. Target 1 and Target 2 VMs: These are the target VMs; we'd use the Controller VM to automate tasks in these target VMS.

Now, let's dive right in and install Vagrant.

Install Vagrant on your PC

Visit https://www.vagrantup.com/downloads and download; you can use the executable file for Windows OR use brew for Mac; it's available for Mac, Linux and Windows.

After downloading and installing it, to confirm, run;



vagrant --version


Enter fullscreen mode Exit fullscreen mode

Also, install VirtualBox, https://www.virtualbox.org/wiki/Downloads.

Using Vagrant to create the VMs (Controller VMs and Targets)

As a Dockerfile is to Docker, a Vagrantfile is for Vagrant; inside a Vagrantfile is where we configure the VM we want to use, so open your text editor and create a Vagrantfile

Vagrantfile



NUM_NODES = 2
NUM_CONTROLLER_NODE = 1
IP_NTW = "192.168.56."
CONTROLLER_IP_START = 2
NODE_IP_START = 3


Enter fullscreen mode Exit fullscreen mode

We created a few variables quick explanation about them.

  • NUM_NODES: This is the number of nodes(target VMs) we want to create.
  • NUM_CONTROLLER_NODE: Number of Controller nodes.
  • IP_NTW: This is the network range we want the VMs to belong to, so our network will have the format of 192.168.56.{any_number}
  • CONTROLLER_IP_START: We specified the start number where the controller would be assigned to in the network, so our controller will start from 192.168.56.2, and the NODE_IP_START will be starting from 3, that's 192.168.56.3.

These will all make sense in some moments. Let's continue for now. We'd be using an Ubuntu image, it's called Image in Docker, but it's called a Box in Vagrant; you can search for boxes at https://app.vagrantup.com/boxes/search.

Vagrantfile



NUM_NODES = 2
NUM_CONTROLLER_NODE = 1
IP_NTW = "192.168.56."
CONTROLLER_IP_START = 2
NODE_IP_START = 3

Vagrant.configure("2") do |config|
    config.vm.box = "ubuntu/trusty64"

end


Enter fullscreen mode Exit fullscreen mode

The 2 in vagrant.configure("2") specifies the configuration version, don't change it, we also used the ubuntu/trusty64 box, the config is a local variable inside the vagrant.configure("2") directive, we use it to configure the box, like config.vm.box = "ubuntu/trusty64", this specifies the box we used.

Configuration for the Target VMs

Vagrantfile



NUM_NODES = 2
NUM_CONTROLLER_NODE = 1
IP_NTW = "192.168.56."
CONTROLLER_IP_START = 2
NODE_IP_START = 3

Vagrant.configure("2") do |config|
    config.vm.box = "ubuntu/trusty64"

    (1..NUM_NODES).each do |i|
        config.vm.define "target0#{i}" do |node|
            node.vm.provider "virtualbox" do |vb|
                vb.name = "target0#{i}"
                vb.memory = 2048
                vb.cpus = 2
            end

            node.vm.hostname = "target0#{i}"
            node.vm.network "private_network", ip: IP_NTW + "#{NODE_IP_START + i}"
            node.vm.network "forwarded_port", guest: 22, host: "#{2720 + i}"
        end
end


Enter fullscreen mode Exit fullscreen mode

We created the target VMs, and we already created a Variable called NUM_NODES, so we created a foreach loop to loop from 1..NUM_NODES, and for each loop instance, we define the config for each target. Our counter variable is i.

Then we defined the name of the box config.vm.define "target0#{i}" do |node|, in it, we set a provider of Virtualbox, Vagrant will use Virtualbox to set up the box, also expect our configs to be for Virtualbox, we then gave the box a name, set the memory to use, also the number of CPUs.

node.vm.hostname = "target0#{i}" set the hostname, so the first target will be target01 and the second target02.

Next, we defined the networks.

A quick network refresher.

  • By default, all boxes in Vagrant use Adapter 1, which is the NAT; using NAT, our VMs can get their internet connections from the host(YOUR PC), but your VMs can't communicate with each other.
  • In Vagrant, a private network is the same as a Host-Only network; a Host-Only network allows VMs on the same network to communicate with each other but can't communicate outside the network.

So combining NAT and a Host-Only network means our VMs can communicate with each other (since they're on the same network); also, they can get Internet Connectivity from the host using the NAT.

Back to Vagrant, This line creates a private network(Host Only) node.vm.network "private_network", ip: IP_NTW + "#{NODE_IP_START + i}", also set the IP, it uses the IP_NTW and adds the NODE_IP_START variable and the current loop, poor little i, we could have used the DHCP server to automatically assign IP address to our VMs, but we won't be covering that.

node.vm.network "forwarded_port", guest: 22, host: "#{2720 + i}" this part defines a port forwarding, which is used to handle SSH connection; SSH connection uses the port 22 on all systems, so whenever the host receives a request on port 2720, it's routed to the VM on port 22(SSH), that's basically what port forwarding does, it forwards ports on the host to the VM in this case, using this you can SSH from your PC into the VMs.

Configuration for the Controller VM(s)

Vagrantfile



NUM_NODES = 2
NUM_CONTROLLER_NODE = 1
IP_NTW = "192.168.56."
CONTROLLER_IP_START = 2
NODE_IP_START = 3

Vagrant.configure("2") do |config|
    config.vm.box = "ubuntu/trusty64"

    (1..NUM_NODES).each do |i|
        config.vm.define "target0#{i}" do |node|
            node.vm.provider "virtualbox" do |vb|
                vb.name = "target0#{i}"
                vb.memory = 2048
                vb.cpus = 2
            end

            node.vm.hostname = "target0#{i}"
            node.vm.network "private_network", ip: IP_NTW + "#{NODE_IP_START + i}"
            node.vm.network "forwarded_port", guest: 22, host: "#{2720 + i}"
        end
    end

    i = 0

    (1..NUM_CONTROLLER_NODE).each do [i] 
        config.vm.define "nodecontroller" do |node|
            node.vm.provider "virtualbox" do |vb|
                vb.name = "nodecontroller"
                vb.memory = 2048
                vb.cpus = 2
            end

            node.vm.hostname = "nodecontroller"
            node.vm.network "private_network", ip: IP_NTW + "#{CONTROLLER_IP_START + i}"
            node.vm.network "forwarded_port", guest: 22, host: "#{2710 + i}"
        end
    end
end


Enter fullscreen mode Exit fullscreen mode

Starting from the comment Configuration for Controller VM(s) down is where we did the config of the controller VM; there is nothing to explain here; both configs are similar. Your Vagrantfile should be the same as this.

Vagrant Ubuntu

Now let's run the Vagrantfile and set up the virtual machines, change the directory into where the Vagrantfile is then run.



vagrant up


Enter fullscreen mode Exit fullscreen mode

This would take a few minutes, so be patient; when it finishes, you can run vagrant status to see the Virtual machines that were created.

Vagrant status

You can also open your Virtualbox, and you would see the virtual machines there too.

Virtualbox

Working with the Virtual Machines

Let's SSH into the nodecontroller.



vagrant ssh nodecontroller


Enter fullscreen mode Exit fullscreen mode

If it requests a password, use vagrant as the password for all the VMS.

Get the IP address of nodecontroller.



ifconfig


Enter fullscreen mode Exit fullscreen mode

You should see (192.168.56.2)

ifconfig

Now exit nodecontroller.



exit


Enter fullscreen mode Exit fullscreen mode

Let's get the IP addresses of target01 and target02



vagrant ssh target01


Enter fullscreen mode Exit fullscreen mode

Run ifconfig and exit, then repeat the same process for target02.

My IP addresses are;

  • target01: 192.168.56.4
  • target02: 192.168.56.5
  • nodecontroller: 192.168.56.2

Yours could be different; you can notice they all end in 56. this means they're on the same network and can communicate.

SSH to target02 from target01

First, SSH into target01.



ssh 192.168.56.5


Enter fullscreen mode Exit fullscreen mode

Try SSH all vice and versa, from target01-target02, target02-target01, nodecontroller-target01, nodecontroller-target02.

Remember I said earlier that since we used a Host-Only network, we can communicate with other VMs on the same networks; let's try to SSH into target01 from nodecontroller.

You can also test internet connectivity on all VMs; let's try pinging google.com.



ping google.com


Enter fullscreen mode Exit fullscreen mode

ping google

Now everything is set!

However, installing Ansible and Automating Tasks would come in the Part 2 series of this article. This one is long enough, felt like I've been typing forever, lol.

I know I said a lot in this article, I just wanted everyone to be able to follow along, including beginners, so I tried breaking everything down; hopefully, I didn't bore you.

If you got this far, Add a Reaction and Follow me so you will get notified when I post part 2 of this article.

Thanks for reading. 😀

Top comments (0)