A common use case is to inspect bidirectional traffic between two VPC networks by leveraging a group of network virtual appliances, that is, multi-NIC VMs.
VPC networks named vpc-a and vpc-b, each with one subnet.
Each backend VM has two network interfaces, one attached to each VPC network (nic0 attached to VPC vpc-a, nic1 attached to VPC vpc-b).
The subnets, subnet-a and subnet-b, use the 10.13.1.0/24 and 10.15.1.0/24 primary IP address ranges, respectively, and they both reside in the us-central1 region.
Creating the Common Managed Instance Group (MIG)
Create a startup script that will install the iptables software on any backend VM. This script named config.sh will be passed to the gcloud compute instance-templates create command using the –metadata flag in the next step:
#!/bin/bash
# Enable IP forwarding:
echo 1 > /proc/sys/net/ipv4/ip_forward
echo "net.ipv4.ip_forward=1" > /etc/sysctl.d/20-iptables.conf
# Read VM network configuration:
md_vm="http://metadata.google.internal/computeMetadata/v1/instance/"
md_net="$md_vm/network-interfaces"
nic0_gw="$(curl $md_net/0/gateway -H "Metadata-Flavor:Google" )"
nic0_mask="$(curl $md_net/0/subnetmask -H "Metadata-Flavor:Google")"
nic0_addr="$(curl $md_net/0/ip -H "Metadata-Flavor:Google")"
nic0_id="$(ip addr show | grep $nic0_addr | awk '{print $NF}')"
nic1_gw="$(curl $md_net/1/gateway -H "Metadata-Flavor:Google")"
nic1_mask="$(curl $md_net/1/subnetmask -H "Metadata-Flavor:Google")"
nic1_addr="$(curl $md_net/1/ip -H "Metadata-Flavor:Google")"
nic1_id="$(ip addr show | grep $nic1_addr | awk '{print $NF}')"
# Source based policy routing for nic1
echo "100 rt-nic1" >> /etc/iproute2/rt_tables
sudo ip rule add pri 32000 from $nic1_gw/$nic1_mask table rt-nic1
sleep 1
sudo ip route add 35.191.0.0/16 via $nic1_gw dev $nic1_id table rt-nic1
sudo ip route add 130.211.0.0/22 via $nic1_gw dev $nic1_id table rt-nic1
# Use a web server to pass the health check for this example.
# You should use a more complete test in production.
sudo apt-get update
sudo apt-get install apache2 -y
sudo a2ensite default-ssl
sudo a2enmod ssl
echo "Example web page to pass health check" | sudo tee /var/www/html/index.html
sudo systemctl restart apache2
Create a common instance template named third-party-template-multinic, which will be used to create new VMs in both the vpc-a and vpc-b VPC networks, when an autoscaling event is triggered:
gcloud compute instance-templates create third-party-template-multinic \
--region=us-central1 \
--network-interface subnet=subnet-a,address="" \
--network-interface subnet=subnet-b \
--tags=allow-ssh,allow-health-check,my-network-tag \
--image-family=debian-10 \
--image-project=debian-cloud \
--can-ip-forward \
--metadata=startup-script="$(< config.sh)"
Create a common managed instance group named third-party-instance-group that will also be used by the two backend services, one in the vpc-a and the other one in the vpc-b VPC networks:
gcloud compute instance-groups managed create third-party-instance-group \
--region=us-central1 \
--template=third-party-template-multinic \
--size=3
.
Create a new HTTP health check named hc-http-80 to test TCP connectivity to the VMs on port 80:
gcloud compute health-checks create http hc-http-80 \
--region=us-central1 \
--port=80
Use the previously created health check to create two internal backend services in the us-central1 region: one named backend-service-a in the vpc-a VPC, and the other one named backend-service-b in the vpc-b VPC:
gcloud compute backend-services create backend-service-a \
--load-balancing-scheme=internal \
--health-checks-region=us-central1 \
--health-checks=hc-http-80 \
--region=us-central1 \
--network=vpc-a \
--session-affinity=CLIENT_IP
gcloud compute backend-services create backend-service-b \
--load-balancing-scheme=internal \
--health-checks-region=us-central1 \
--health-checks=hc-http-80 \
--region=us-central1 \
--network=vpc-b \
--session-affinity=CLIENT_IP
Add to each of the two backend services the managed instance groups you created in step 3 (third-party-instance-group), which contains the third-party virtual appliances as backends:
gcloud compute backend-services add-backend backend-service-a \
--instance-group=third-party-instance-group \
--instance-group-region=us-central1 \
--region=us-central1
gcloud compute backend-services add-backend backend-service-b \
--instance-group=third-party-instance-group \
--instance-group-region=us-central1 \
--region=us-central1
Create two regional, internal forwarding rules: one associated with the subnet-a and the other one associated with the subnet-b. Connect each forwarding rule to its respective backend service, that is, backend-service-a and backend-service-b:
gcloud compute forwarding-rules create ilb-a \
--load-balancing-scheme=internal \
--ports=80 \
--network=vpc-a \
--subnet=subnet-a \
--region=us-central1 \
--backend-service=backend-service-a \
--address=10.13.1.77
gcloud compute forwarding-rules create ilb-b \
--load-balancing-scheme=internal \
--ports=80 \
--network=vpc-b \
--subnet=subnet-b \
--region=us-central1 \
--backend-service=backend-service-b \
--address=10.15.1.77
Creating the Custom Static Routes That Define the Load Balancers As the Next Hops:
gcloud compute routes create ilb-nhop-dest-10-15-1 \
--network=vpc-a \
--destination-range=10.15.1.0/24 \
--next-hop-ilb=ilb-a \
--next-hop-ilb-region=us-central1
gcloud compute routes create ilb-nhop-dest-10-13-1 \
--network=vpc-b \
--destination-range=10.13.1.0/24 \
--next-hop-ilb=ilb-b \
--next-hop-ilb-region=us-central1
Creating the First VM
gcloud compute instances create vm-a \
--zone=us-central1-a \
--image-family=debian-10 \
--image-project=debian-cloud \
--tags=allow-ssh \
--subnet=subnet-a \
--private-network-ip 10.13.1.70 \
--metadata=startup-script='#! /bin/bash
sudo apt-get update
sudo apt-get install apache2 -y
sudo a2ensite default-ssl
sudo a2enmod ssl
vm_hostname="$(curl -H "Metadata-Flavor:Google" \
http://metadata.google.internal/computeMetadata/v1/instance/name)"
echo "Page served from: $vm_hostname" | \
sudo tee /var/www/html/index.html
sudo systemctl restart apache2'
Creating the Second VM
gcloud compute instances create vm-b \
--zone=us-central1-b \
--image-family=debian-10 \
--image-project=debian-cloud \
--tags=allow-ssh \
--subnet=subnet-b \
--private-network-ip 10.15.1.70 \
--metadata=startup-script='#! /bin/bash
sudo apt-get update
sudo apt-get install apache2 -y
sudo a2ensite default-ssl
sudo a2enmod ssl
vm_hostname="$(curl -H "Metadata-Flavor:Google" \
http://metadata.google.internal/computeMetadata/v1/instance/name)"
echo "Page served from: $vm_hostname" | \
sudo tee /var/www/html/index.html
sudo systemctl restart apache2'
Verifying Load Balancer Health Status:
gcloud compute backend-services get-health backend-service-a \
--region us-central1
gcloud compute backend-services get-health backend-service-b \
--region us-central1
Testing Connectivity from the Testing VM:
gcloud compute ssh vm-a --zone=us-central1-a
curl http://10.15.1.70
exit
Testing Connectivity from the Production VM:
gcloud compute ssh vm-b --zone=us-central1-b
curl http://10.13.1.70
exit