Proxy Requests to Weighted Backends
Configure weighted routing to distribute traffic across multiple upstream services using APISIX or API7 Ingress Controller.
Applies to:API7 Ingress Controller (drives API7 Gateway)APISIX Ingress Controller (drives Apache APISIX)
Goal
Distribute HTTP requests between two upstream services according to assigned weights using a Gateway API HTTPRoute or an APISIX CRD route.
Before you begin
- Complete Set Up Ingress Controller and Gateway.
- You have
kubectlconfigured against the cluster used in the setup guide. - Choose a free local port for the gateway port-forward. The examples use
9080.
Set the variables this guide uses:
export UPSTREAM1_NAME="echo-1"
export UPSTREAM2_NAME="echo-2"
export UPSTREAM_PORT="80"
export UPSTREAM1_WEIGHT="1"
export UPSTREAM2_WEIGHT="4"
export REQUEST_COUNT="50"
export GATEWAY_SERVICE_NAME="apisix-gateway" # your gateway's Service name in namespace aic
export GATEWAY_HTTP_PORT="80"
export FORWARD_PORT="9080"Steps
Step 1: Deploy the example upstream services
Create a manifest for two http-echo services in the aic namespace:
apiVersion: apps/v1
kind: Deployment
metadata:
name: echo-1
namespace: aic
spec:
replicas: 1
selector:
matchLabels:
app: echo-1
template:
metadata:
labels:
app: echo-1
spec:
containers:
- name: http-echo
image: hashicorp/http-echo:0.2.3
args:
- "-text=Hello from pod $(POD_NAME) in upstream 1"
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
ports:
- containerPort: 5678
---
apiVersion: v1
kind: Service
metadata:
name: echo-1
namespace: aic
spec:
selector:
app: echo-1
ports:
- protocol: TCP
port: 80
targetPort: 5678
type: ClusterIP
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: echo-2
namespace: aic
spec:
replicas: 1
selector:
matchLabels:
app: echo-2
template:
metadata:
labels:
app: echo-2
spec:
containers:
- name: http-echo
image: hashicorp/http-echo:0.2.3
args:
- "-text=Hello from pod $(POD_NAME) in upstream 2"
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
ports:
- containerPort: 5678
---
apiVersion: v1
kind: Service
metadata:
name: echo-2
namespace: aic
spec:
selector:
app: echo-2
ports:
- protocol: TCP
port: 80
targetPort: 5678
type: ClusterIPApply the manifest and wait for the Pods to become ready:
kubectl apply -f lb-two-http-echo.yaml
kubectl wait --for=condition=ready pod -l app=echo-1 -n aic --timeout=120s
kubectl wait --for=condition=ready pod -l app=echo-2 -n aic --timeout=120sStep 2: Create the weighted route
Create a manifest for a route that load balances requests between the two services with the configured weights:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
namespace: aic
name: lb-route
spec:
parentRefs:
- name: apisix
rules:
- matches:
- path:
type: Exact
value: /
backendRefs:
- name: echo-1
port: 80
weight: 1
- name: echo-2
port: 80
weight: 4apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
namespace: aic
name: lb-route
spec:
ingressClassName: apisix
http:
- name: lb-route
match:
paths:
- /
backends:
- serviceName: echo-1
servicePort: 80
weight: 1
- serviceName: echo-2
servicePort: 80
weight: 4Apply the manifest:
kubectl apply -f lb-route.yamlValidate
Forward the gateway HTTP port to your local machine:
kubectl port-forward -n aic "svc/${GATEWAY_SERVICE_NAME}" "${FORWARD_PORT}:${GATEWAY_HTTP_PORT}" &Send REQUEST_COUNT consecutive requests and count how many are handled by each upstream:
resp=$(seq ${REQUEST_COUNT} | xargs -I{} curl "http://127.0.0.1:${FORWARD_PORT}/" -sL) && \
count_echo1=$(echo "$resp" | grep "upstream 1" | wc -l) && \
count_echo2=$(echo "$resp" | grep "upstream 2" | wc -l) && \
echo "echo-1: $count_echo1, echo-2: $count_echo2"Expected: a response similar to:
echo-1: 9, echo-2: 41The distribution of requests across services should be close to the configured 1:${UPSTREAM2_WEIGHT} ratio. The slight deviation is due to the gateway operating with multiple workers.
Roll back / Clean up
Delete the manifests created in this guide:
kubectl delete -f lb-route.yaml
kubectl delete -f lb-two-http-echo.yamlStop the local port-forward process if it is still running:
kill %1 2>/dev/null || trueTroubleshoot
| Symptom | Cause | Fix |
|---|---|---|
| Both counts are zero. | The route is not accepted, the upstream Pods are not ready, or the port-forward targets the wrong Service. | Verify the HTTPRoute/ApisixRoute status, check that echo-1 and echo-2 are ready, and confirm GATEWAY_SERVICE_NAME and FORWARD_PORT. |
| The ratio is very different from the configured weights. | The gateway has not finished loading the new route, or the test ran too few requests. | Wait a few seconds and increase REQUEST_COUNT to at least 50. |
curl returns 503 Service Unavailable. | Both upstreams are unhealthy or the Services have no endpoints. | Check the Pods with kubectl get pods -l app=echo-1 and kubectl get pods -l app=echo-2 -n aic. |