Gateway API Hands-on Labs
Overview
The sample labs in this section demonstrate how to use the Gateway API to configure a Gateway and expose a service to external traffic. The labs are based on the Gateway API and GKE Gateway features.
Contents
- Lab1. External Gateway using Certificate Manager with wildcard domain
- Lab2. Configuring a static IP for a Gateway
- Lab3. Multi-cluster gateway
- Lab4. Capacity-based load balancing
Prerequisites
1. Enable APIs, such as GKE, GKE Hub, and GKE Multi-cluster Ingress (MCI), etc. in your projects
# Environment variables
export PROJECT_ID=play-api-service
export PROJECT_NUMBER=374299782509
# Enable APIs
gcloud services enable \
container.googleapis.com \
gkehub.googleapis.com \
multiclusterservicediscovery.googleapis.com \
multiclusteringress.googleapis.com \
trafficdirector.googleapis.com \
--project=${PROJECT_ID}
2. Provision a GKE cluster with Gateway API, or enable existed GKE clutser
# Create a GKE cluster with Gateway API
gcloud container clusters create pt-cluster-4 \
--gateway-api=standard \
--release-channel=Rapid \
--region=asia-southeast1
# Enable Gateway API for an existing GKE cluster
gcloud container clusters update pt-cluster-4 \
--gateway-api=standard \
--region=asia-southeast1
# Verify the cluster
kubectl get gatewayclass
3. Checkout the sample code
git clone https://github.com/cc4i/awesome-gke.git
cd awesome-gke/gatewayclass
Lab 1. External Gateway using Certificate Manager with wildcard domain
1.1 Create a certificate map
# Enable Certificate Manager API
gcloud services enable certificatemanager.googleapis.com
# Create a DNS Authorization to validate your certificate. Example here is my personal domain cc4i.xyz and reigstered in GoDaddy, you can use your own domain.
gcloud certificate-manager dns-authorizations create dns-auth-cc4i-xyz \
--domain="cc4i.xyz"
# !!!Returning DNS resource record needs to be added as CNAME into your DNS configuration !!!
# Create a certificate
gcloud beta certificate-manager certificates create store-cc4i-xyz-cert \
--domains="cc4i.xyz,*.cc4i.xyz" \
--dns-authorizations=dns-auth-cc4i-xyz
# Create a certificate map
gcloud beta certificate-manager maps create store-cc4i-xyz-map
# Create a certificate map entry for wildcard domain
gcloud beta certificate-manager maps entries create store-cc4i-xyz-map-entry1 \
--map=store-cc4i-xyz-map \
--hostname="*.cc4i.xyz" \
--certificates=store-cc4i-xyz-cert
# Create a certificate map entry for root domain
gcloud beta certificate-manager maps entries create store-cc4i-xyz-map-entry2 \
--map=store-cc4i-xyz-map \
--hostname="cc4i.xyz" \
--certificates=store-cc4i-xyz-cert
References: - DNS Authorization - Secure a gateway
1.2 Create a Gateway
# Create a Gateway
kubectl apply -f single-https/gateway.yaml
# Verify the Gateway
kubectl describe gateways.gateway.networking.k8s.io external-http
1.3 Deployment demo application
# Deploy the demo application
kubectl apply -f single-https/store.yaml
kubectl get pods
kubectl get service
# Check Gateway IP
kubectl get gateways.gateway.networking.k8s.io external-http -o=jsonpath="{.status.addresses[0].value}"
# Apply the http route
kubectl apply -f single-https/store-route-external.yaml
References: - Demo applications - HTTPRoute
1.4 Use shared Gateways
# Used as a shared Gateway
kubectl apply -f single-https/site.yaml
# Apply the http route
kubectl apply -f single-https/site-route-external.yaml
Lab 2. Configuring a static IP for a Gateway
2.1 Create a static IP address
# https://cloud.google.com/kubernetes-engine/docs/how-to/deploying-gateways#gateway_ip_addressing
gcloud compute addresses create test-public-ip-cc4i-xyz \
--global \
--project=${PROJECT_ID}
2.2 Create a Gateway with static IP
# Apply the Gateway with static IP
kubectl apply -f single-https/named-ip-gateway.yaml
Lab 3. Multi-cluster gateway
3.1 Craete multiple GKE clusters in different regions
# Create multiple GKE clusters in different regions
gcloud container clusters create gke-west-1 \
--gateway-api=standard \
--zone=us-west1-a \
--workload-pool=${PROJECT_ID}.svc.id.goog \
--cluster-version=1.25.6-gke.1000 \
--project=${PROJECT_ID}
gcloud container clusters create gke-west-2 \
--gateway-api=standard \
--zone=us-west1-a \
--workload-pool=${PROJECT_ID}.svc.id.goog \
--cluster-version=1.25.6-gke.1000 \
--project=${PROJECT_ID}
gcloud container clusters create gke-east-1 \
--gateway-api=standard \
--zone=us-east1-b \
--workload-pool=${PROJECT_ID}.svc.id.goog \
--cluster-version=1.25.6-gke.1000 \
--project=${PROJECT_ID}
# Rename the context
kubectl config rename-context gke_${PROJECT_ID}_us-west1-a_gke-west-1 gke-west-1
kubectl config rename-context gke_${PROJECT_ID}_us-west1-a_gke-west-2 gke-west-2
kubectl config rename-context gke_${PROJECT_ID}_us-east1-b_gke-east-1 gke-east-1
3.2 Register to the fleet
# Register to the fleet
gcloud container fleet memberships register gke-west-1 \
--gke-cluster us-west1-a/gke-west-1 \
--enable-workload-identity \
--project=${PROJECT_ID}
gcloud container fleet memberships register gke-west-2 \
--gke-cluster us-west1-a/gke-west-2 \
--enable-workload-identity \
--project=${PROJECT_ID}
gcloud container fleet memberships register gke-east-1 \
--gke-cluster us-east1-b/gke-east-1 \
--enable-workload-identity \
--project=${PROJECT_ID}
# Try following command to add permission to service account if you got error ralated to permission!!!
gcloud projects add-iam-policy-binding ${PROJECT_ID} --member \
serviceAccount:service-${PROJECT_NUMBER}@gcp-sa-gkehub.iam.gserviceaccount.com \
--role "roles/gkehub.connect"
# Validate the membership
gcloud container fleet memberships list --project=${PROJECT_ID}
3.3 Enable multi-cluster services
# Enable multi-cluster services API
gcloud container fleet multi-cluster-services enable \
--project ${PROJECT_ID}
# Grant IAM permission required for multi-cluster services
gcloud projects add-iam-policy-binding ${PROJECT_ID} \
--member "serviceAccount:${PROJECT_ID}.svc.id.goog[gke-mcs/gke-mcs-importer]" \
--role "roles/compute.networkViewer" \
--project=${PROJECT_ID}
# Choose member cluster, which would host the resource for multi-cluster Gateway
gcloud container fleet ingress enable \
--config-membership=gke-west-1 \
--project=${PROJECT_ID}
# Validate the ingress
gcloud container fleet ingress describe --project=${PROJECT_ID}
# Grant IAM permission required for multi-cluster services
gcloud projects add-iam-policy-binding ${PROJECT_ID} \
--member "serviceAccount:service-${PROJECT_NUMBER}@gcp-sa-multiclusteringress.iam.gserviceaccount.com" \
--role "roles/container.admin" \
--project=${PROJECT_ID}
# Validate the GatewayClass
kubectl get gatewayclasses --context=gke-west-1
3.4 Deploy demo application into all clusters
# Deploy demo application into all clusters
kubectl apply --context gke-west-1 -f multi/multi-store.yaml
kubectl apply --context gke-west-2 -f multi/multi-store.yaml
kubectl apply --context gke-east-1 -f multi/multi-store.yaml
kubectl apply -f store-west-service.yaml --context gke-west-1
kubectl apply -f store-east-service.yaml --context gke-east-1 --namespace store
# Validate the deployment
kubectl get serviceexports --context gke-east-1 -n store
kubectl get serviceimports --context gke-east-1 -n store
3.5 Deploy external http Gateway
# Deploy external http Gateway
kubectl apply -f multi/external-http-gateway.yaml --context gke-west-1 --namespace store
# Apply the http route
kubectl apply -f multi/public-route-external.yaml --context gke-west-1 --namespace store
# Validate the Gateway
kubectl describe gateways.gateway.networking.k8s.io external-http --context gke-west-1 --namespace store
3.6 Validate deployment
# Get the IP of the Gateway
kubectl get gateway -n store
kubectl get gateways.gateway.networking.k8s.io external-http \
-o=jsonpath="{.status.addresses[0].value}" --context gke-west-1 --namespace store
# Take a while to sync all routes into GLB
curl -H "host: store.example.com" http://34.98.80.105
curl -H "host: store.example.com" http://34.98.80.105/west
curl -H "host: store.example.com" http://34.98.80.105/east
Reference: - Enable Multi-cluster Gateway - Fleet
Lab 4. Capacity-based load balancing
4.1 Prepare clusters if not done in previous steps
kubectl get gatewayclasses --context=gke-west-1
4.2 Deploy the demo application
# Deploy the application into all clusters
kubectl apply -f capacity-based-glb/store-traffic-deploy.yaml --context gke-west-1
kubectl apply -f capacity-based-glb/store-traffic-deploy.yaml --context gke-east-1
kubectl apply -f capacity-based-glb/store-service.yaml --context gke-west-1
kubectl apply -f capacity-based-glb store-service.yaml --context gke-east-1
4.3 Deploy external http Gateway
# Deploy external http Gateway
kubectl apply -f store-route.yaml --context gke-west-1
# Validate the Gateway
kubectl describe gateways.gateway.networking.k8s.io store -n traffic-test --context gke-west-1
4.4 Testing the Gateway
# Get the IP of the Gateway
curl http://34.160.103.232
# Take a while to sync all routes into GLB
kubectl get gateways.gateway.networking.k8s.io store -n traffic-test \
--context=gke-west-1 \
-o=jsonpath="{.metadata.annotations.networking\.gke\.io/url-maps}"
# Add a load generator to the cluster
kubectl run --context=gke-west-1 -i --tty --rm loadgen \
--image=cyrilbkr/httperf \
--restart=Never \
-- /bin/sh -c 'httperf \
--server=34.160.103.232 \
--hog --uri="/zone" --port 80 --wsess=100000,1,1 --rate 10'
# Fetch metrics from Monitoring & observe the traffic distribution
fetch https_lb_rule
| metric 'loadbalancing.googleapis.com/https/backend_request_count'
| filter (resource.url_map_name =='gkemcg1-traffic-test-store-armvfyupay1t')
| align rate(1m)
| every 1m
| group_by [resource.backend_scope],
[value_backend_request_count_aggregate:
aggregate(value.backend_request_count)]
# Add more traffic to cluster & observe the traffic distribution
kubectl run --context=gke-west-1 -i --tty --rm loadgen \
--image=cyrilbkr/httperf \
--restart=Never \
-- /bin/sh -c 'httperf \
--server=34.160.103.232 \
--hog --uri="/zone" --port 80 --wsess=100000,1,1 --rate 30'
Reference: - Capacity-based load balancing