Multipass availability zones with a load-balanced web service

In this tutorial, we will use Multipass availability zones to build a simple, highly available web service. We will deploy three Nginx web servers, one in each availability zone, and a fourth instance acting as a load balancer to distribute traffic between them.

In the real world, availability zones are clusters of data centers in a particular region. Multipass provides a local simulation of availability zones for development purposes.

To complete this tutorial, you need Multipass 1.17 or later installed on your host.

Check the available zones

Multipass ships with a fixed set of availability zones. List them, along with their status, before you start:

multipass zones

Sample output:

Name    State       Subnet
zone1   Available   192.168.252.0/24
zone2   Available   192.168.253.0/24
zone3   Available   192.168.254.0/24

Note

Multipass assigns each zone its own subnet, simulating the network separation between real-world availability zones.

We will spread our web servers across zone1, zone2 and zone3.

Launch the web servers

First, let’s launch one web server in each availability zone. We will customize their landing pages so we can easily see which zone is responding.

Launch and configure the first server (zone1)

multipass launch --name web-a --zone zone1
multipass exec web-a -- sudo apt-get update
multipass exec web-a -- sudo apt-get install -y nginx
multipass exec web-a -- bash -c 'echo "<h1>Welcome to web-a in zone1</h1>" | sudo tee /var/www/html/index.html'
multipass exec web-a -- bash -c "echo '<h1>Welcome to web-a in zone1</h1>' | sudo tee /var/www/html/index.html"

Launch and configure the second server (zone2)

multipass launch --name web-b --zone zone2
multipass exec web-b -- sudo apt-get update
multipass exec web-b -- sudo apt-get install -y nginx
multipass exec web-b -- bash -c 'echo "<h1>Welcome to web-b in zone2</h1>" | sudo tee /var/www/html/index.html'
multipass exec web-b -- bash -c "echo '<h1>Welcome to web-b in zone2</h1>' | sudo tee /var/www/html/index.html"

Launch and configure the third server (zone3)

multipass launch --name web-c --zone zone3
multipass exec web-c -- sudo apt-get update
multipass exec web-c -- sudo apt-get install -y nginx
multipass exec web-c -- bash -c 'echo "<h1>Welcome to web-c in zone3</h1>" | sudo tee /var/www/html/index.html'
multipass exec web-c -- bash -c "echo '<h1>Welcome to web-c in zone3</h1>' | sudo tee /var/www/html/index.html"

Launch the load balancer

Now we will launch a fourth instance to act as a load balancer. We will place it explicitly in zone3 so we know exactly where it lives, and use HAProxy, a popular open-source load balancer, to distribute traffic across all three zones.

multipass launch --name load-balancer --zone zone3
multipass exec load-balancer -- sudo apt-get update
multipass exec load-balancer -- sudo apt-get install -y haproxy

Configure HAProxy

The load balancer needs the IP address of each web server so it can send incoming requests to them. Get these addresses:

WEB_A_IP=$(multipass info web-a --format csv | awk -F, 'NR>1 {print $5}')
WEB_B_IP=$(multipass info web-b --format csv | awk -F, 'NR>1 {print $5}')
WEB_C_IP=$(multipass info web-c --format csv | awk -F, 'NR>1 {print $5}')
$WEB_A_IP = (multipass info web-a --format csv | ConvertFrom-Csv).Ipv4
$WEB_B_IP = (multipass info web-b --format csv | ConvertFrom-Csv).Ipv4
$WEB_C_IP = (multipass info web-c --format csv | ConvertFrom-Csv).Ipv4

Create a configuration file locally and transfer it to the load balancer:

cat << EOF > haproxy.cfg

frontend http_front
    bind *:80
    default_backend http_back

backend http_back
    balance roundrobin
    server web-a $WEB_A_IP:80 check
    server web-b $WEB_B_IP:80 check
    server web-c $WEB_C_IP:80 check
EOF

multipass transfer haproxy.cfg load-balancer:
multipass exec load-balancer -- sudo mv /home/ubuntu/haproxy.cfg /etc/haproxy/haproxy.cfg
multipass exec load-balancer -- sudo systemctl restart haproxy
@"
frontend http_front
    bind *:80
    default_backend http_back

backend http_back
    balance roundrobin
    server web-a ${WEB_A_IP}:80 check
    server web-b ${WEB_B_IP}:80 check
    server web-c ${WEB_C_IP}:80 check
"@ | Set-Content -Encoding ascii haproxy.cfg

multipass transfer haproxy.cfg load-balancer:
multipass exec load-balancer -- sudo mv /home/ubuntu/haproxy.cfg /etc/haproxy/haproxy.cfg
multipass exec load-balancer -- sudo systemctl restart haproxy

Test the high availability

Find the IP address of your load balancer:

LB_IP=$(multipass info load-balancer --format csv | awk -F, 'NR>1 {print $5}')
$LB_IP = (multipass info load-balancer --format csv | ConvertFrom-Csv).Ipv4

From now on, send requests only to the load balancer. It decides which healthy backend server responds. Query it once:

curl http://$LB_IP
curl.exe "http://$LB_IP"

Expected output:

<h1>Welcome to web-a in zone1</h1>

Run the command again:

curl http://$LB_IP
curl.exe "http://$LB_IP"

This time, the response comes from the next web server in another availability zone:

<h1>Welcome to web-b in zone2</h1>

Simulate a zone failure

To simulate an outage of an entire availability zone, disable zone1. Multipass forcefully switches off every instance in that zone and keeps them off until the zone is re-enabled, mirroring a real cloud provider losing a zone:

multipass disable-zones zone1

After a few moments, query the same load balancer address three times. HAProxy detects that web-a is unavailable and sends the requests to the surviving web servers:

curl http://$LB_IP
curl http://$LB_IP
curl http://$LB_IP
curl.exe "http://$LB_IP"
curl.exe "http://$LB_IP"
curl.exe "http://$LB_IP"

Expected output (the order may vary):

<h1>Welcome to web-b in zone2</h1>
<h1>Welcome to web-c in zone3</h1>
<h1>Welcome to web-b in zone2</h1>

Notice that none of the responses comes from web-a in zone1.

Take down a second zone

Now disable zone2 as well, leaving only zone3 healthy:

multipass disable-zones zone2

Query the load balancer again. With two zones down, every request can only come from web-c in zone3:

curl http://$LB_IP
curl http://$LB_IP
curl.exe "http://$LB_IP"
curl.exe "http://$LB_IP"

Expected output:

<h1>Welcome to web-c in zone3</h1>
<h1>Welcome to web-c in zone3</h1>

Conclusion

You have built a highly available web service that spans all three availability zones. Even when an entire zone goes offline, your users can still access the application through the healthy zones, demonstrating the power of infrastructure redundancy with Multipass.

Tear down the environment

Restore the zones

Bring both zones back online. Instances that were running when the zones were disabled are started again automatically:

multipass enable-zones zone1 zone2

After a few moments, web-a and web-b rejoin the rotation and the load balancer serves all three zones once more.

Let’s now delete the instances, free their resources on our host machine, and remove the local HAProxy configuration file:

multipass delete --purge web-a web-b web-c load-balancer
rm haproxy.cfg
multipass delete --purge web-a web-b web-c load-balancer
Remove-Item haproxy.cfg