I've recently worked on a project with GCP service extensions. The service extensions has 2 modes.
Service Extensions Plugins
The first mode is service extensions plugins that are WASM based plugins that are run within the load balancer context. This is useful for stateless validation and updates to the request and response.
The plugins can be implemented using C++ and Rust, which is ok as long as you have a small picece of code. This mode is very similar to the AWS lambda.
The advantage is we do not need to manage compute resources, it is done as part of the load balancer itself, which is great.
The disadvantage is that we can have only a short small stateless piece of code. Forget about complex logic here.
Service Extensions Callouts
The advatage is that we get a much flexible implementation choices, and we can manage state and complex logic.
The disadvantage is that we need to manage the compute resources. This is not just managing a single deployment, but managing a deploying in each region the load balancer is working.
For example if we have a global load balancer, and the callouts backend is a kubernetes based solution, we need to have a deployment in each of the load balancer regions, and since GCP supports 40 regions, we need 40(!) kubernetes clusters.
Service Extenstion Callouts Example
Following the GCP documents, we can create a simple working example of the service extension callouts for an internal regional load balancer. By the way, it is obvious why the example is for a regional load balancer, and not for a global load balancer that would require 40 deployments.
The creation is based on gcloud CLI. We start by creating a load balancer over a VMs instance group backend.
#VPC
gcloud compute networks create lb-network --subnet-mode=custom
gcloud compute networks subnets create backend-subnet \
--network=lb-network \
--range=10.1.2.0/24 \
--region=us-west1
gcloud compute networks subnets create europe-subnet \
--network=lb-network \
--range=10.3.4.0/24 \
--region=europe-west1
gcloud compute networks subnets create proxy-only-subnet \
--purpose=REGIONAL_MANAGED_PROXY \
--role=ACTIVE \
--region=us-west1 \
--network=lb-network \
--range=10.129.0.0/23
# Firewall Rules
gcloud compute firewall-rules create fw-allow-ssh \
--network=lb-network \
--action=allow \
--direction=ingress \
--target-tags=allow-ssh \
--rules=tcp:22
gcloud compute firewall-rules create fw-allow-health-check \
--network=lb-network \
--action=allow \
--direction=ingress \
--source-ranges=130.211.0.0/22,35.191.0.0/16 \
--target-tags=load-balanced-backend \
--rules=tcp
gcloud compute firewall-rules create fw-allow-proxies \
--network=lb-network \
--action=allow \
--direction=ingress \
--source-ranges=10.129.0.0/23 \
--target-tags=load-balanced-backend \
--rules=tcp:80,tcp:443,tcp:8080
# IP for the load balancer
gcloud compute addresses create l7-ilb-ip-address \
--region=us-west1 \
--subnet=backend-subnet
gcloud compute addresses describe l7-ilb-ip-address \
--region=us-west1
# managed vm instance group
gcloud compute instance-templates create l7-ilb-backend-template \
--region=us-west1 \
--network=lb-network \
--subnet=backend-subnet \
--tags=allow-ssh,load-balanced-backend \
--image-family=debian-12 \
--image-project=debian-cloud \
--metadata=startup-script='#! /bin/bash
apt-get update
apt-get install apache2 -y
a2ensite default-ssl
a2enmod ssl
vm_hostname="$(curl -H "Metadata-Flavor:Google" \
http://metadata.google.internal/computeMetadata/v1/instance/name)"
echo "Page served from: $vm_hostname" | \
tee /var/www/html/index.html
systemctl restart apache2'
gcloud compute instance-groups managed create l7-ilb-backend-example \
--zone=us-west1-a \
--size=2 \
--template=l7-ilb-backend-template
# load balancer
gcloud compute health-checks create http l7-ilb-basic-check \
--region=us-west1 \
--use-serving-port
gcloud compute backend-services create l7-ilb-backend-service \
--load-balancing-scheme=INTERNAL_MANAGED \
--protocol=HTTP \
--health-checks=l7-ilb-basic-check \
--health-checks-region=us-west1 \
--region=us-west1
gcloud compute backend-services add-backend l7-ilb-backend-service \
--balancing-mode=UTILIZATION \
--instance-group=l7-ilb-backend-example \
--instance-group-zone=us-west1-a \
--region=us-west1
gcloud compute url-maps create l7-ilb-map \
--default-service=l7-ilb-backend-service \
--region=us-west1
gcloud compute target-http-proxies create l7-ilb-proxy \
--url-map=l7-ilb-map \
--url-map-region=us-west1 \
--region=us-west1
gcloud compute forwarding-rules create l7-ilb-forwarding-rule \
--load-balancing-scheme=INTERNAL_MANAGED \
--network=lb-network \
--subnet=backend-subnet \
--address=l7-ilb-ip-address \
--ports=80 \
--region=us-west1 \
--target-http-proxy=l7-ilb-proxy \
--target-http-proxy-region=us-west1
Next we create a test VM that is used the send requests to the internal load balancer.
gcloud compute instances create l7-ilb-client-us-west1-a \
--image-family=debian-12 \
--image-project=debian-cloud \
--network=lb-network \
--subnet=backend-subnet \
--zone=us-west1-a \
--tags=allow-ssh
gcloud compute addresses describe l7-ilb-ip-address \
--region=us-west1
gcloud compute ssh l7-ilb-client-us-west1-a \
--zone=us-west1-a
# RUN FROM THE TEST VM
#curl -D - -H "host: example.com" http://IP OF LOAD BALANCER
Last we create a callout backend with a rule to handle hostname example.com.
# create callout backend
gcloud compute instances create-with-container callouts-vm \
--container-image=us-docker.pkg.dev/service-extensions/ext-proc/service-callout-basic-example-python:latest \
--network=lb-network \
--subnet=backend-subnet \
--zone=us-west1-a \
--tags=allow-ssh,load-balanced-backend
gcloud compute instance-groups unmanaged create callouts-ig \
--zone=us-west1-a
gcloud compute instance-groups unmanaged set-named-ports callouts-ig \
--named-ports=http:80,grpc:443 \
--zone=us-west1-a
gcloud compute instance-groups unmanaged add-instances callouts-ig \
--zone=us-west1-a \
--instances=callouts-vm
# update the load balancer
gcloud compute health-checks create http callouts-hc \
--region=us-west1 \
--port=80
gcloud compute backend-services create l7-ilb-callout-service \
--load-balancing-scheme=INTERNAL_MANAGED \
--protocol=HTTP2 \
--port-name=grpc \
--health-checks=callouts-hc \
--health-checks-region=us-west1 \
--region=us-west1
gcloud compute backend-services add-backend l7-ilb-callout-service \
--balancing-mode=UTILIZATION \
--instance-group=callouts-ig \
--instance-group-zone=us-west1-a \
--region=us-west1
```
# Traffic extension
```bash
cat >traffic.yaml <<EOF
name: traffic-ext
forwardingRules:
- https://www.googleapis.com/compute/v1/projects/radware-cto/regions/us-west1/forwardingRules/l7-ilb-forwarding-rule
loadBalancingScheme: INTERNAL_MANAGED
metadata: {"fr": "{forwarding_rule_id}", "key2": {"key3":"value"}}
extensionChains:
- name: "chain1"
matchCondition:
celExpression: 'request.host == "example.com"'
extensions:
- name: 'ext11'
authority: ext11.com
service: https://www.googleapis.com/compute/v1/projects/radware-cto/regions/us-west1/backendServices/l7-ilb-callout-service
failOpen: false
timeout: 0.1s
supportedEvents:
- RESPONSE_HEADERS
EOF
gcloud service-extensions lb-traffic-extensions import traffic-ext \
--source=traffic.yaml \
--location=us-west1
The callout backend is based on the example in https://github.com/GoogleCloudPlatform/service-extensions. I would recommend starting with this Go or python based example as a first step.
No comments:
Post a Comment