In this article, I will show how to build a real working multi-cloud solution. As an example, I chose two most known and common cloud providers: Amazon AWS and Microsoft Azure. So what I'm going to do is to create a Load Balancer at AWS and put two nodes behind: the first one is EC2 instance at AWS and the second one is Virtual Machine at Azure. To test and show how it works, I'll put the simplest web-page on both nodes with a small difference.
Background
The cloud solution I'm going to build is actually based on two big architectural chunks: connecting virtual private networks from two cloud providers and building the load balancer with nodes itself.
I want to say 'thank you' to Gavin Lewis whose article inspired me. In fact, the first chunk (connecting AWS and Azure VPNs) is repeating his steps but providing more explanation and depicting omitted steps. Some things were not obvious for me when I did it myself so I decided to show a step-by-step guide of how to do that instead of just referring to that article.
Using the Code
As was mentioned above before constructing multi-cloud load balancer solution, we need to connect AWS and Azure networks. It's needed so that load balancer can interact with nodes as they are in the same network.
Connecting Networks
Azure
- First of all, we create Virtual Network. Specify its Name and Address space, let it be
172.18.0.0/16
. Choose existing Resource group or create a new one. And let's set West US Location for this Azure part of architecture.
Also, we need to create the Subnet. Set its Name and Address range where we reduce address range increasing subnet mask to 17 - 172.18.0.0/17
. Leave the rest of the parameters as they are.
- For connecting this VNet to AWS network, we will need a gateway, that's why we create Gateway Subnet for this VNet with Address range (CIDR block)
172.18.128.0/24
as suggested by default.
- The next step is creating Public IP Address to be assigned to Virtual Network Gateway in future. We only need to specify its Name and leave the rest by default.
- Now we are ready to create Virtual Network Gateway which is a junction point for AWS network. We set Name, change SKU parameter to Basic to save money sacrificing throughput, choose created earlier VNet and its Gateway Subnet. The last parameter to set is Public IP Address created on the previous step.
Creating VNet Gateway takes the most time (up to 60 minutes), so keep calm and switch to AWS console to continue there while it's under progress.
AWS
- Now we need to prepare a similar architecture for another provider. So we start from creating VPC. We should specify some free CIDR block for your region, so let it be
172.16.0.0/16
.
- Then we need to create Subnets for this VPC. For creating AWS Load Balancer, we need at least 2 subnets based on different Availability Zones.
So choose just created VPC, then choose one of possible Availability Zone and specify CIDR block for Subnet 1. Repeat these actions for the second subnet but with another CIDR block.
- Subnet 1:
172.16.0.0/18
- Subnet 2:
172.16.64.0/18
- To create VPN tunnel, we need to have Virtual Private Gateway on AWS side. Set some name and leave Amazon default ASN option as it is.
- For some reason, they don't have an option to attach Virtual Private Gateway to particular VPC while creating. So we should do it manually. Choose our multi-cloud VPC, status of the gateway should be changed to 'attached'.
Azure
- For the next step at AWS environment, we need to know Public IP address of created Azure Virtual Network Gateway from step 4. For this, choose your Public IP address from the list and note down IP address itself. In my example, it is
40.112.249.133
. It will appear only when VNG is fully created.
AWS
- Now we are ready to create Customer Gateway at AWS side and link it to Azure network using Public IP address from the previous step. We use static routing not to make stuff more complicated.
- This is one of the key steps of connecting two networks. So we're going to create Site-to-Site VPN Connection to join our networks. Ultimately, we will get two tunnels inside this VPN Connection which are joined to Local Network Gateways inside Azure network.
To create VPN Connection, fill in Name tag, choose Virtual Private Gateway from step 7. and existing Customer Gateway from the step 10. We don't have BGP and actually don't need it, so choose Static Routing Option and enter Static IP Prefix 172.18.0.0/17
- it is IP address range of Azure VNet Subnet 1 from step 1.
Leave the rest of the parameters by default.
- Once VPN Connection is created, we can download its configuration. We need Outside IP Address of Virtual Private Gateway and Pre-Shared SHA Key for each IPSec Tunnel.
If we choose Generic value for Vendor and Platform, Vendor Agnositc value for Software in Download Configuration dialog, we should get plain text file in downloads.
So find #1: Internet Key Exchange Configuration section for IPSec Tunnel #1 in the file you just downloaded, there is a line with Pre-Shared Key value and line with Virtual Private Gateway Outside IP Address:
IPSec Tunnel #1
- Pre-Shared Key : RyLbEbDeQEfRgyfNMCazi74Ifa8NCCR2
- Virtual Private Gateway : 13.59.179.250
The same for IPSec Tunnel #2.
IPSec Tunnel #2
- Pre-Shared Key : rNaec.9VsurcpGgdfP7CwfQU4OvRRrzs
- Virtual Private Gateway : 18.224.76.18
Azure
- Now we go back to Azure VNG where we need to create 2 Connections with their Local Network Gateways for each connection. There, we will specify the settings we got in the previous step. This is the final step of joining 2 networks.
Choose your Virtual Network Gateway, go to Connections in Settings section and click Add button.
Enter some Name for your connection, choose Connection type as Site-to-Site (IPsec), the same as we had for AWS VPN Connection. Enter Shared key from the first IPSec Tunnel we got in step 12. After that, click 'Choose a local network gateway' and 'Create new' button there.
Now we jump into Local Network Gateway creating dialog where we need to enter gateway's Name and IP address from the first IPSec Tunnel we got in step 12, it was Outside IP Address in configuration file. Also, specify Address space, it's CIDR block of AWS VPC - 172.16.0.0/16
.
Then, create the second Connection and Local Network Gateway for it. Repeat these actions but take data for Shared key and LNG IP address from the second AWS IPSec Tunnel.
You can also find these settings in Local Network Gateways, Configuration section.
- After some time, we can check our Connections of Virtual Network Gateway, the Status should be 'Connected'.
AWS
- Then check Status of two tunnels on AWS side. Pick your VPN Connection and click on Tunnel Details tab. The Status for both should be UP.
It means we successfully connected networks of 2 providers. But before we can really build multi-cloud solutions here, we should tune Route Table of VPC on AWS side to show where to route traffic.
- To tune Route Table, we need to have Internet Gateway. Let's create it with some name.
- After creating Internet Gateway, we need to attach it to our multi-cloud VPC. It needs just a few clicks.
- Now we can edit Route Table entries for our multi-cloud VPC. Find Route Table which belongs to multi-cloud VPC, click Actions and Edit routes.
We should add 2 routes. Traffic addressed to 172.18.0.0/16
(Azure VNet) we route to Virtual Private Gateway from step 7 and the rest traffic (except our local network which is already targeted locally) goes to Internet Gateway from step 16.
That's it, let's test if nodes in these networks can really interact with each other using private IP addresses.
Testing
- To test interaction, we will create 2 nodes - EC2 instance at AWS and Virtual machine at Azure inside connected networks and try to ping each other.
I will not describe how to create EC2 instance and Virtual machine, it's too trivial and you can easily find how to do that. Don't forget when creating that, you will need to ssh to these machines, so allow this in rules and save keys and passwords not to lose access.
To be able to ping EC2 instance, we have to allow it intentionally tuning Security Group which is assigned to created EC2 instance. Choose Security Group, go to Inbound tab, click Edit and add rule with next parameters:
Type - Custom ICMP
, Protocol - Echo Request
and Source 0.0.0.0/0
.
- Connect to both machines via ssh and try to ping each other by their private IP addresses. It should work. It also approves then networks are successfully connected to each other and we really can start building multi-cloud solutions here.
Load Balancer
- So the idea is to create Load Balancer at AWS and put to associated Target group 2 instances: one from VPC where LB is located itself and one from connected network. This way, we build LB target group which is placed not at different AZs or Regions, but different providers. So we get multi-cloud solution with nodes across the world.
Before creating LB, we need to prepare our nodes to act as web-servers. For that, we need to install any web-server there. This is also quite a trivial issue, there are many examples of how to do that. I can say that httpd
service will be more than enough for our purpose.
After installing web-server service on our nodes, put index.html file to /var/www/html folder. Put the next HTML code to AWS EC2 instance index.html:
<html><h1>Hello Multi-Cloud (AWS)</h1></html>
And the same but with (Azure) for Azure Virtual Machine:
<html><h1>Hello Multi-Cloud (Azure)</h1></html>
- Let's start to create LB itself. We will need an Application Load Balancer type. After choosing the type, we should fill in LB Name, choose internet-facing scheme to be able to test it via its DNS name.
- At the bottom of Configure Load Balancer tab, we can find Availability Zones section. On this step, LB doesn't know that it will be multi-cloud balancer, so we have to choose at least 2 AZs with subnets there. That's why we created 2 subnets in step 6.
- We can leave everything on Configure Security Settings by default and skip to Configure Security Groups. Here, we create a new security group with suggested TCP rule.
- The next Configure Routing tab is more interesting. We create a new target group for our nodes, specify some Name tag for it. Then we should choose
IP
as Target type. Leave Protocol and Port by default.
For the Health check, enter /index.html to the Path. So it should find our index.html files we created on each node.
- On Register Targets tab, we register two targets.
The first one is local EC2 instance. We choose our multi-cloud VPC and specify instance's Private IP address. Then click 'Add to list' button. For my case, it's 172.16.20.207
.
The second one is Azure VM. To register it, we choose 'Other private IP address' as Network value and type Private IP address of Azure VM in 172.18.0.0
subnet. For my case, it's 172.18.0.4
.
- After review, we create LB. When it's done, we can see newly created LB in the list. It takes some time to check that our targets are healthy. You can see this at Targets tab in Status column.
- Load Balancer is created and its targets are in healthy state. Let's check it live. Click on Description tab and find its DNS name. Copy it to clipboard and open URL in browser.
- You will see something like that. Try to refresh the page a couple of times. (Azure) should change to (AWS) and vice versa. It means LB route traffic to different nodes which are placed on different cloud providers.
Multi-cloud solution works!
Points of Interest
I just showed how to build multi-cloud solutions and not be locked-in with some particular provider. It can help to minimize risks of any single provider related to its price, availability and so on.
Of course, you can find much better business cases for multi-cloud approach, but I didn't pursue the goal to make a business solution. It's more about the technical solution and a fundamental example of how to join and mix different cloud providers. This solution is based on my experience at Intetics.
I'll be glad to see in the comments any other examples (real or just your ideas) of any business cases where it really make sense to build your architecture across multiple clouds.
History
- 12th November, 2019: V1
- 6th March, 2020: minor changes, title updated