Skip to main content

Building an HA Virtual Infrastructure

HAThis tutorial will use VirtualBox and Vagrant to create redundant components for an HA Infrastructure.  This includes using HAProxy as a load balancer, Apache webservers, and a MySQL master-master database cluster. The load-balancer will be configured with round robin, a scheduling algorithm that distributes work evenly.  The webservers will be identical Rocky Linux 8 servers running the Apache webserver. The database will be two MySQL servers in a master-master configuration.  Also known as “mirror” because both servers update the data in real-time to ensure that both servers have the latest data. All of this can be done on Mac, Windows and Linux.

Install VirtualBox first and reboot after installation.  Then install Vagrant and reboot.  Once rebooted, open a shell of your choice.  I am using Powershell.  Type 'vagrant' on the command line to verify it is installed correctly.  Make sure VirtualBox is up and running.  Create a directory C:\vagrant.  In Powershell change into the vagrant directory and type

vagrant init
 vagrant plugin install vagrant-vbguest 

Install the extension pack in VirtualBox.  Support for VirtualBox RDP, disk encryption, NVMe and PXE boot for Intel network cards.  For Linux servers this may require recompiling the kernel.  While this is done with automation it sometimes creates an error.  For this tutorial we will disable these automatic updates.

In this infrastructure example we will use Ubuntu for the HAProxy load balancer, Rocky Linux 8 for the Apache web servers, and Ubuntu for the MySQL instances.  Port forwarding will be configured for each server.  We will use the following IP addresses and ports:

ServerIPVBoxLocal sshLocal web
Load Balancer10.0.2.200yunsheng/haproxybase2002220080
Web Server 110.0.2.201geerlingguy/rockylinux82012220180
Web Server 210.0.2.202geerlingguy/rockylinux82022220280
Database110.0.2.203dperezc01/mysqltrusty642032220380
Database 210.0.2.204dperezc01/mysqltrusty642042220480

We will edit the file called Vagrantfile in C:\vagrant.  

Vagrant.configure("2") do |config|
  if Vagrant.has_plugin?("vagrant-vbguest")
    config.vbguest.auto_update = false
  end
  config.vm.define "lb1" do |lb1|
    lb1.vm.box = "yunsheng/haproxybase"
    lb1.vm.hostname = 'lb1'
    lb1.vm.box_version = "1.0.0"
    lb1.vm.network :private_network, ip: "10.0.2.200"
    lb1.vm.network :forwarded_port, guest: 22, host: 20022, id: "ssh"
    lb1.vm.network :forwarded_port, guest: 80, host: 20080, id: "http"
    lb1.vm.provider :virtualbox do |v|
      v.customize ["modifyvm", :id, "--memory", 512]
      v.customize ["modifyvm", :id, "--name", "lb1"]
      v.customize ["modifyvm", :id, "--uartmode1", "disconnected" ]
    end
  end

  config.vm.define "web1" do |web1|
    web1.vm.box = "geerlingguy/rockylinux8"
    web1.vm.hostname = 'web1'
    web1.vm.box_url = "geerlingguy/rockylinux8"

    web1.vm.network :private_network, ip: "10.0.2.201"
    web1.vm.network :forwarded_port, guest: 22, host: 20122, id: "ssh"
    web1.vm.network :forwarded_port, guest: 80, host: 20180, id: "http"
    web1.vm.provider :virtualbox do |v|
      v.customize ["modifyvm", :id, "--natdnshostresolver1", "on"]
      v.customize ["modifyvm", :id, "--memory", 512]
      v.customize ["modifyvm", :id, "--name", "web1"]
    end
  end

  config.vm.define "web2" do |web2|
    web2.vm.box = "geerlingguy/rockylinux8"
    web2.vm.hostname = 'web2'
    web2.vm.box_url = "geerlingguy/rockylinux8"
    web2.vm.network :private_network, ip: "10.0.2.202"
    web2.vm.network :forwarded_port, guest: 22, host: 20222, id: "ssh"
    web2.vm.network :forwarded_port, guest: 80, host: 20280, id: "http"
    web2.vm.provider :virtualbox do |v|
      v.customize ["modifyvm", :id, "--natdnshostresolver1", "on"]
      v.customize ["modifyvm", :id, "--memory", 512]
      v.customize ["modifyvm", :id, "--name", "web2"]
    end
  end

  config.vm.define "db1" do |db1|
    db1.vm.box = "dperezc01/mysqltrusty64"
    db1.vm.hostname = 'db1'
    db1.vm.box_url = "dperezc01/mysqltrusty64"
    db1.vm.network :private_network, ip: "10.0.2.203"
    db1.vm.network :forwarded_port, guest: 22, host: 20322, id: "ssh"
    db1.vm.network :forwarded_port, guest: 80, host: 20380, id: "http"
    db1.vm.provider :virtualbox do |v|
      v.customize ["modifyvm", :id, "--memory", 512]
      v.customize ["modifyvm", :id, "--name", "db1"]
    db1.vm.network "forwarded_port", guest: 3306, host: 3307, host_ip: "127.0.0.1"
    end
  end

  config.vm.define "db2" do |db2|
    db2.vm.box = "dperezc01/mysqltrusty64"
    db2.vm.hostname = 'db2'
    db2.vm.box_url = "dperezc01/mysqltrusty64"
    db2.vm.network :private_network, ip: "10.0.2.204"
    db2.vm.network :forwarded_port, guest: 22, host: 20422, id: "ssh"
    db2.vm.network :forwarded_port, guest: 80, host: 20480, id: "http"
    # MySQL server
    db2.vm.network "forwarded_port", guest: 3306, host: 3308, host_ip: "127.0.0.1"
    db2.vm.provider :virtualbox do |v|
      v.customize ["modifyvm", :id, "--memory", 512]
      v.customize ["modifyvm", :id, "--name", "db2"]
    end
  end

end

Once saved, run the following command

vagrant up

VirtualBox serversSwitch to VirtualBox.  You should see the new virtual machines coming up and running.  Open and log in to the new virtual machines with user name 'vagrant' and password 'vagrant'.  In Powershell type

PS C:\vagrant> vagrant ssh web1
Last login: Mon Jan  1 01:18:53 2024
[vagrant@web1 ~]$ 

This is just the beginning of using this combination of technologies. The combination of Vagrant and VirtualBox should save you lots of time.  Spinning up this infrastructure with Vagrant takes only a few minutes because of the automation and other human task elimination.  This can equate to hours of productivity gains per day if you do a lot of prototyping.  This gets even more impressive when you layer in components like Ansible and Kubernetes.  You can find Vagrant Boxes on the Vagrant Cloud.

ServerIPWeb page
Load Balancer10.0.2.20020080
Web Server 110.0.2.20120180
Web Server 210.0.2.20220280
Database110.0.2.20320380
Database 210.0.2.20420480

 

 

To delete the servers run the following in Powershell.  Vagrant normally asks for Y/N verification for each server.  We will use -f to disable this.

PS C:\vagrant> vagrant destroy -f

 

Helpful links

https://developer.hashicorp.com/vagrant/docs

https://www.virtualbox.org/wiki/Documentation

https://www.activecountermeasures.com/port-forwarding-with-virtualbox/