Configure Gateway, HTTPRoute, and TLS resources to route external traffic to ACK services through an Application Load Balancer (ALB) instance.
Resource model
The Gateway API defines three resource types, each owned by a different role:
| Resource | Owner | Purpose |
|---|---|---|
| GatewayClass | Infrastructure provider (Alibaba Cloud) | Defines a gateway class backed by a controller — here, the ALB Ingress Controller |
| Gateway | Cluster operator | Provisions an ALB instance and configures listeners (ports, protocols, hostnames) |
| HTTPRoute | Application developer | Defines routing rules that map incoming requests to backend Services |
Platform teams control infrastructure while application teams manage routing rules independently.
The ALB Ingress Controller has supported the Gateway API since version 2.17.0.
Prerequisites
Ensure the following:
-
An ACK managed cluster running Kubernetes 1.24 or later
-
The ALB Ingress Controller version 2.17.0 or later installed in the cluster
-
The Gateway API version 1.1.0 or later installed in the cluster
-
Two vSwitches that support ALB in the VPC where your cluster is deployed
Verify the environment
The ALB Ingress Controller automatically creates a GatewayClass resource named alb. Verify it exists before proceeding.
kubectl
Check the GatewayClass:
kubectl get gatewayclass
Example output:
NAME CONTROLLER ACCEPTED AGE
alb gateways.alibabacloud.com/alb/v1 True 1m
ACCEPTED: True confirms the GatewayClass is ready.
Deploy a sample application
Create an httpbin.yaml file:
The Service usesClusterIPby default. If your cluster uses the Flannel network plug-in, changespec.typetoNodePort.
apiVersion: apps/v1
kind: Deployment
metadata:
name: go-httpbin
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: go-httpbin
template:
metadata:
labels:
app: go-httpbin
version: v1
spec:
containers:
- image: registry.cn-hangzhou.aliyuncs.com/mse/go-httpbin
args:
- "--port=8090"
- "--version=v1"
imagePullPolicy: Always
name: go-httpbin
ports:
- containerPort: 8090
---
apiVersion: v1
kind: Service
metadata:
name: go-httpbin
namespace: default
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 8090
protocol: TCP
selector:
app: go-httpbin
Apply the manifest:
kubectl apply -f httpbin.yaml
Deploy the Gateway and routing rule
Creating a Gateway provisions an ALB instance and incurs fees. ALB instances created by a Gateway are not automatically deleted when you delete the cluster. Delete the Gateway resource before deleting the cluster to avoid unexpected charges.
Step 1: Create the Gateway and HTTPRoute
Create a gateway.yaml file:
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: alb
namespace: default
spec:
gatewayClassName: alb
listeners:
- name: http
protocol: HTTP
port: 80
hostname: "*.ingress.top"
allowedRoutes:
namespaces:
from: Same
---
apiVersion: gateway.networking.k8s.io/v1beta1
kind: HTTPRoute
metadata:
name: demo-route
spec:
parentRefs: # Attach this route to the Gateway above
- group: gateway.networking.k8s.io
kind: Gateway
name: alb
hostnames:
- demo.ingress.top
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs: # Forward matched traffic to go-httpbin on port 80
- kind: Service
name: go-httpbin
port: 80
The Gateway provisions an ALB instance with an HTTP listener on port 80 for *.ingress.top. The HTTPRoute forwards traffic for demo.ingress.top to the go-httpbin Service.
Apply the manifest:
kubectl apply -f gateway.yaml
Step 2: Wait for the Gateway to be ready
kubectl wait --for=condition=programmed gateway/alb --timeout=120s
Verify the Gateway address:
kubectl get gateway alb
Example output:
NAME CLASS ADDRESS PROGRAMMED AGE
alb alb alb-0mwhq4ck6xxxxxxxxx.cn-hangzhou.alb.aliyuncsslb.com True 2m12s
Step 3: Check the HTTPRoute status
kubectl describe httproute demo-route | grep Status -A 20
Example output:
Status:
Parents:
Conditions:
Last Transition Time: 2025-05-23T08:21:25Z
Message: Route is accepted.
Observed Generation: 1
Reason: Accepted
Status: True
Type: Accepted
Last Transition Time: 2025-05-23T08:21:25Z
Message: Route is resolved.
Observed Generation: 1
Reason: ResolvedRefs
Status: True
Type: ResolvedRefs
Controller Name: gateways.alibabacloud.com/alb/v1
Parent Ref:
Group: gateway.networking.k8s.io
Kind: Gateway
Name: alb
Accepted: True and ResolvedRefs: True confirm the route is active.
Step 4: Test access
Get the Gateway address and send a test request:
export ALB_DOMAIN=$(kubectl get gateway alb -n default -o jsonpath='{.status.addresses[?(@.type=="Hostname")].value}')
curl -H "Host: demo.ingress.top" http://${ALB_DOMAIN}/version
Example output:
version: v1
hostname: go-httpbin-547xxxxxf6-xxxxx
Use cases
Modify request headers with a filter
HTTPRoute filters let you rewrite requests or responses in transit. This example adds a custom request header.
Create an httproute-filter.yaml file:
apiVersion: gateway.networking.k8s.io/v1beta1
kind: HTTPRoute
metadata:
name: demo-filter
spec:
parentRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: alb
hostnames:
- filter.ingress.top
rules:
- matches:
- path:
type: PathPrefix
value: /
filters:
- type: RequestHeaderModifier
requestHeaderModifier:
add:
- name: my-header
value: foo
backendRefs:
- kind: Service
name: go-httpbin
port: 80
The RequestHeaderModifier filter modifies requests before they reach the backend:
-
Adds
my-header: footo matching requests. -
Uses the
addaction, which appends rather than replaces existing headers with the same name.
Apply the routing rule:
kubectl apply -f httproute-filter.yaml
Test with the /header endpoint, which echoes request headers:
curl -H "Host: filter.ingress.top" http://${ALB_DOMAIN}/header
Example output:
headers: {
"Accept": [
"*/*"
],
"Connection": [
"close"
],
"Host": [
"filter.ingress.top"
],
"My-Header": [
"foo"
],
"Path": [
"/header"
],
"Protocol": [
"HTTP/1.1"
],
"Remoteip": [
"118.xx.xx.91"
],
"URL": [
"/header"
],
"User-Agent": [
"curl/8.9.1"
]
}
query param:
, hostname: go-httpbin-547xxxxxf6-xxxxx
My-Header: foo in the output confirms the filter works.
Split traffic by weight
Assign weights to multiple backend Services to distribute traffic proportionally, such as for canary deployments.
Create an nginx.yaml file with two NGINX deployments:
old-nginx returns old; new-nginx returns new. Both deploy in the default namespace.
Create an httproute-weight.yaml file:
apiVersion: gateway.networking.k8s.io/v1beta1
kind: HTTPRoute
metadata:
name: demo-weight
spec:
parentRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: alb
hostnames:
- weight.ingress.top
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
# Weights are relative, not percentages — they do not need to add up to 100.
- kind: Service
name: old-nginx
port: 80
weight: 100
- kind: Service
name: new-nginx
port: 80
weight: 100
Both backends have equal weights (100:100), so traffic splits 1:1.
Apply the manifests:
kubectl apply -f nginx.yaml
kubectl apply -f httproute-weight.yaml
Send 10 requests to observe the distribution:
for i in {1..10}; do curl -H "Host: weight.ingress.top" http://${ALB_DOMAIN}/; done
Example output:
old
new
new
old
new
old
old
new
new
old
Traffic splits roughly 1:1 between the two backends.
Configure a TLS certificate
Add HTTPS termination to the Gateway by referencing a Kubernetes Secret with your TLS certificate.
Step 1: Create a self-signed certificate
openssl req -subj '/CN=ingress.top' -new -newkey rsa:2048 -sha256 \
-days 365 -nodes -x509 -keyout server.key -out server.crt \
-addext "subjectAltName = DNS:ingress.top" \
-addext "keyUsage = digitalSignature" \
-addext "extendedKeyUsage = serverAuth" 2> /dev/null; \
openssl x509 -in server.crt -subject -noout
Step 2: Create a TLS Secret
kubectl create secret tls ingress.top --key server.key --cert server.crt
Step 3: Update the Gateway to add an HTTPS listener
Create a gateway-tls.yaml file:
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: alb
namespace: default
spec:
gatewayClassName: alb
listeners:
- name: http
protocol: HTTP
port: 80
hostname: "*.ingress.top"
allowedRoutes:
namespaces:
from: Same
- name: https
protocol: HTTPS
port: 443
hostname: "*.ingress.top"
allowedRoutes:
namespaces:
from: Same
tls:
mode: Terminate # ALB terminates TLS and forwards plain HTTP to backends
certificateRefs:
- kind: Secret
name: ingress.top # The Secret created in the previous step
In Terminate mode, ALB decrypts HTTPS traffic and forwards plain HTTP to backends. The certificateRefs field references the Secret holding the certificate and private key.
Apply the update:
kubectl apply -f gateway-tls.yaml
Step 4: Verify the certificate
Wait for the Gateway PROGRAMMED status to return to True:
kubectl wait --for=condition=programmed gateway/alb --timeout=120s
Verify the certificate:
openssl s_client -servername ingress.top -connect ${ALB_DOMAIN}:443
Example output:
CONNECTED(00000003)
depth=0 CN = ingress.top
verify error:num=18:self-signed certificate
verify return:1
depth=0 CN = ingress.top
verify return:1
---
Certificate chain
0 s:CN = ingress.top
i:CN = ingress.top
a:PKEY: rsaEncryption, 2048 (bit); sigalg: RSA-SHA256
v:NotBefore: Jun 24 10:49:39 2025 GMT; NotAfter: Jun 24 10:49:39 2026 GMT
---
Server certificate
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
subject=CN = ingress.top
issuer=CN = ingress.top
---
...
New, TLSv1.2, Cipher is ECDHE-RSA-AES128-GCM-SHA256
Server public key is 2048 bit
...
Verify return code: 18 (self-signed certificate)
CN = ingress.top and the TLSv1.2 cipher confirm TLS termination works. The self-signed certificate error is expected — use a CA-signed certificate in production.
Test HTTPS access with the -k flag to skip self-signed certificate verification:
curl -H "Host: demo.ingress.top" -k https://${ALB_DOMAIN}/version
Example output:
version: v1
hostname: go-httpbin-547xxxxxf6-xxxxx
Next steps
-
Gateway API — Full specification, including advanced routing such as header-based matching and traffic mirroring.
-
ALB Ingress Controller — ALB-specific annotations and configuration for production workloads.